/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_COMPILER #define SKSL_COMPILER #include #include #include #include "src/sksl/SkSLByteCode.h" #include "src/sksl/SkSLCFGGenerator.h" #include "src/sksl/SkSLContext.h" #include "src/sksl/SkSLErrorReporter.h" #include "src/sksl/SkSLLexer.h" #include "src/sksl/ir/SkSLProgram.h" #include "src/sksl/ir/SkSLSymbolTable.h" #define SK_FRAGCOLOR_BUILTIN 10001 #define SK_IN_BUILTIN 10002 #define SK_INCOLOR_BUILTIN 10003 #define SK_OUTCOLOR_BUILTIN 10004 #define SK_TRANSFORMEDCOORDS2D_BUILTIN 10005 #define SK_TEXTURESAMPLERS_BUILTIN 10006 #define SK_OUT_BUILTIN 10007 #define SK_LASTFRAGCOLOR_BUILTIN 10008 #define SK_MAIN_X_BUILTIN 10009 #define SK_MAIN_Y_BUILTIN 10010 #define SK_WIDTH_BUILTIN 10011 #define SK_HEIGHT_BUILTIN 10012 #define SK_FRAGCOORD_BUILTIN 15 #define SK_CLOCKWISE_BUILTIN 17 #define SK_VERTEXID_BUILTIN 42 #define SK_INSTANCEID_BUILTIN 43 #define SK_CLIPDISTANCE_BUILTIN 3 #define SK_INVOCATIONID_BUILTIN 8 #define SK_POSITION_BUILTIN 0 namespace SkSL { class IRGenerator; /** * Main compiler entry point. This is a traditional compiler design which first parses the .sksl * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce * compiled output. * * See the README for information about SkSL. */ class SK_API Compiler : public ErrorReporter { public: static constexpr const char* RTADJUST_NAME = "sk_RTAdjust"; static constexpr const char* PERVERTEX_NAME = "sk_PerVertex"; enum Flags { kNone_Flags = 0, // permits static if/switch statements to be used with non-constant tests. This is used when // producing H and CPP code; the static tests don't have to have constant values *yet*, but // the generated code will contain a static test which then does have to be a constant. kPermitInvalidStaticTests_Flag = 1, }; struct FormatArg { enum class Kind { kInput, kOutput, kCoordX, kCoordY, kUniform, kChildProcessor }; FormatArg(Kind kind) : fKind(kind) {} FormatArg(Kind kind, int index) : fKind(kind) , fIndex(index) {} Kind fKind; int fIndex; }; Compiler(Flags flags = kNone_Flags); ~Compiler() override; Compiler(const Compiler&) = delete; Compiler& operator=(const Compiler&) = delete; /** * Registers an ExternalValue as a top-level symbol which is visible in the global namespace. */ void registerExternalValue(ExternalValue* value); std::unique_ptr convertProgram(Program::Kind kind, String text, const Program::Settings& settings); bool optimize(Program& program); std::unique_ptr specialize(Program& program, const std::unordered_map& inputs); bool toSPIRV(Program& program, OutputStream& out); bool toSPIRV(Program& program, String* out); bool toGLSL(Program& program, OutputStream& out); bool toGLSL(Program& program, String* out); bool toMetal(Program& program, OutputStream& out); bool toMetal(Program& program, String* out); bool toCPP(Program& program, String name, OutputStream& out); bool toH(Program& program, String name, OutputStream& out); std::unique_ptr toByteCode(Program& program); bool toPipelineStage(const Program& program, String* out, std::vector* outFormatArgs); /** * Takes ownership of the given symbol. It will be destroyed when the compiler is destroyed. */ Symbol* takeOwnership(std::unique_ptr symbol); void error(int offset, String msg) override; String errorText(); void writeErrorCount(); int errorCount() override { return fErrorCount; } Context& context() { return *fContext; } static const char* OperatorName(Token::Kind token); static bool IsAssignment(Token::Kind token); private: void processIncludeFile(Program::Kind kind, const char* src, size_t length, std::shared_ptr base, std::vector>* outElements, std::shared_ptr* outSymbolTable); void addDefinition(const Expression* lvalue, std::unique_ptr* expr, DefinitionMap* definitions); void addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions); void scanCFG(CFG* cfg, BlockId block, std::set* workList); void computeDataFlow(CFG* cfg); /** * Simplifies the expression pointed to by iter (in both the IR and CFG structures), if * possible. */ void simplifyExpression(DefinitionMap& definitions, BasicBlock& b, std::vector::iterator* iter, std::unordered_set* undefinedVariables, bool* outUpdated, bool* outNeedsRescan); /** * Simplifies the statement pointed to by iter (in both the IR and CFG structures), if * possible. */ void simplifyStatement(DefinitionMap& definitions, BasicBlock& b, std::vector::iterator* iter, std::unordered_set* undefinedVariables, bool* outUpdated, bool* outNeedsRescan); void scanCFG(FunctionDefinition& f); Position position(int offset); std::shared_ptr fGpuSymbolTable; std::vector> fVertexInclude; std::shared_ptr fVertexSymbolTable; std::vector> fFragmentInclude; std::shared_ptr fFragmentSymbolTable; std::vector> fGeometryInclude; std::shared_ptr fGeometrySymbolTable; std::vector> fPipelineInclude; std::shared_ptr fPipelineSymbolTable; std::vector> fInterpreterInclude; std::shared_ptr fInterpreterSymbolTable; std::shared_ptr fTypes; IRGenerator* fIRGenerator; int fFlags; const String* fSource; std::shared_ptr fContext; int fErrorCount; String fErrorText; }; } // namespace #endif