1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_COMPILER
9#define SKSL_COMPILER
10
11#include <map>
12#include <set>
13#include <unordered_set>
14#include <vector>
15#include "src/sksl/SkSLASTFile.h"
16#include "src/sksl/SkSLCFGGenerator.h"
17#include "src/sksl/SkSLContext.h"
18#include "src/sksl/SkSLErrorReporter.h"
19#include "src/sksl/SkSLLexer.h"
20#include "src/sksl/ir/SkSLProgram.h"
21#include "src/sksl/ir/SkSLSymbolTable.h"
22
23#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
24#include "src/gpu/GrShaderVar.h"
25#endif
26
27#define SK_FRAGCOLOR_BUILTIN 10001
28#define SK_IN_BUILTIN 10002
29#define SK_INCOLOR_BUILTIN 10003
30#define SK_OUTCOLOR_BUILTIN 10004
31#define SK_TRANSFORMEDCOORDS2D_BUILTIN 10005
32#define SK_TEXTURESAMPLERS_BUILTIN 10006
33#define SK_OUT_BUILTIN 10007
34#define SK_LASTFRAGCOLOR_BUILTIN 10008
35#define SK_MAIN_COORDS_BUILTIN 10009
36#define SK_WIDTH_BUILTIN 10011
37#define SK_HEIGHT_BUILTIN 10012
38#define SK_FRAGCOORD_BUILTIN 15
39#define SK_CLOCKWISE_BUILTIN 17
40#define SK_SAMPLEMASK_BUILTIN 20
41#define SK_VERTEXID_BUILTIN 42
42#define SK_INSTANCEID_BUILTIN 43
43#define SK_CLIPDISTANCE_BUILTIN 3
44#define SK_INVOCATIONID_BUILTIN 8
45#define SK_POSITION_BUILTIN 0
46
47namespace SkSL {
48
49class ByteCode;
50class ExternalValue;
51class IRGenerator;
52struct PipelineStageArgs;
53
54/**
55 * Main compiler entry point. This is a traditional compiler design which first parses the .sksl
56 * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
57 * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
58 * compiled output.
59 *
60 * See the README for information about SkSL.
61 */
62class SK_API Compiler : public ErrorReporter {
63public:
64 static constexpr const char* RTADJUST_NAME = "sk_RTAdjust";
65 static constexpr const char* PERVERTEX_NAME = "sk_PerVertex";
66
67 enum Flags {
68 kNone_Flags = 0,
69 // permits static if/switch statements to be used with non-constant tests. This is used when
70 // producing H and CPP code; the static tests don't have to have constant values *yet*, but
71 // the generated code will contain a static test which then does have to be a constant.
72 kPermitInvalidStaticTests_Flag = 1,
73 };
74
75 struct FormatArg {
76 enum class Kind {
77 kInput,
78 kOutput,
79 kCoords,
80 kUniform,
81 kChildProcessor,
82 kFunctionName
83 };
84
85 FormatArg(Kind kind)
86 : fKind(kind) {}
87
88 FormatArg(Kind kind, int index)
89 : fKind(kind)
90 , fIndex(index) {}
91
92 Kind fKind;
93 int fIndex;
94 String fCoords;
95 };
96
97#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
98 /**
99 * Represents the arguments to GrGLSLShaderBuilder::emitFunction.
100 */
101 struct GLSLFunction {
102 GrSLType fReturnType;
103 SkString fName;
104 std::vector<GrShaderVar> fParameters;
105 SkString fBody;
106 std::vector<Compiler::FormatArg> fFormatArgs;
107 };
108#endif
109
110 Compiler(Flags flags = kNone_Flags);
111
112 ~Compiler() override;
113
114 Compiler(const Compiler&) = delete;
115 Compiler& operator=(const Compiler&) = delete;
116
117 /**
118 * Registers an ExternalValue as a top-level symbol which is visible in the global namespace.
119 */
120 void registerExternalValue(ExternalValue* value);
121
122 std::unique_ptr<Program> convertProgram(Program::Kind kind, String text,
123 const Program::Settings& settings);
124
125 bool optimize(Program& program);
126
127 std::unique_ptr<Program> specialize(Program& program,
128 const std::unordered_map<SkSL::String, SkSL::Program::Settings::Value>& inputs);
129
130 bool toSPIRV(Program& program, OutputStream& out);
131
132 bool toSPIRV(Program& program, String* out);
133
134 bool toGLSL(Program& program, OutputStream& out);
135
136 bool toGLSL(Program& program, String* out);
137
138 bool toHLSL(Program& program, String* out);
139
140 bool toMetal(Program& program, OutputStream& out);
141
142 bool toMetal(Program& program, String* out);
143
144 bool toCPP(Program& program, String name, OutputStream& out);
145
146 bool toH(Program& program, String name, OutputStream& out);
147
148 std::unique_ptr<ByteCode> toByteCode(Program& program);
149
150#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
151 bool toPipelineStage(const Program& program, PipelineStageArgs* outArgs);
152#endif
153
154 /**
155 * Takes ownership of the given symbol. It will be destroyed when the compiler is destroyed.
156 */
157 Symbol* takeOwnership(std::unique_ptr<Symbol> symbol);
158
159 void error(int offset, String msg) override;
160
161 String errorText();
162
163 void writeErrorCount();
164
165 int errorCount() override {
166 return fErrorCount;
167 }
168
169 Context& context() {
170 return *fContext;
171 }
172
173 static const char* OperatorName(Token::Kind token);
174
175 static bool IsAssignment(Token::Kind token);
176
177private:
178 void processIncludeFile(Program::Kind kind, const char* src, size_t length,
179 std::shared_ptr<SymbolTable> base,
180 std::vector<std::unique_ptr<ProgramElement>>* outElements,
181 std::shared_ptr<SymbolTable>* outSymbolTable);
182
183 void addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
184 DefinitionMap* definitions);
185
186 void addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions);
187
188 void scanCFG(CFG* cfg, BlockId block, std::set<BlockId>* workList);
189
190 void computeDataFlow(CFG* cfg);
191
192 /**
193 * Simplifies the expression pointed to by iter (in both the IR and CFG structures), if
194 * possible.
195 */
196 void simplifyExpression(DefinitionMap& definitions,
197 BasicBlock& b,
198 std::vector<BasicBlock::Node>::iterator* iter,
199 std::unordered_set<const Variable*>* undefinedVariables,
200 bool* outUpdated,
201 bool* outNeedsRescan);
202
203 /**
204 * Simplifies the statement pointed to by iter (in both the IR and CFG structures), if
205 * possible.
206 */
207 void simplifyStatement(DefinitionMap& definitions,
208 BasicBlock& b,
209 std::vector<BasicBlock::Node>::iterator* iter,
210 std::unordered_set<const Variable*>* undefinedVariables,
211 bool* outUpdated,
212 bool* outNeedsRescan);
213
214 void scanCFG(FunctionDefinition& f);
215
216 Position position(int offset);
217
218 std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fGPUIntrinsics;
219 std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fInterpreterIntrinsics;
220 std::unique_ptr<ASTFile> fGpuIncludeSource;
221 std::shared_ptr<SymbolTable> fGpuSymbolTable;
222 std::vector<std::unique_ptr<ProgramElement>> fVertexInclude;
223 std::shared_ptr<SymbolTable> fVertexSymbolTable;
224 std::vector<std::unique_ptr<ProgramElement>> fFragmentInclude;
225 std::shared_ptr<SymbolTable> fFragmentSymbolTable;
226 std::vector<std::unique_ptr<ProgramElement>> fGeometryInclude;
227 std::shared_ptr<SymbolTable> fGeometrySymbolTable;
228 std::vector<std::unique_ptr<ProgramElement>> fPipelineInclude;
229 std::shared_ptr<SymbolTable> fPipelineSymbolTable;
230 std::vector<std::unique_ptr<ProgramElement>> fInterpreterInclude;
231 std::shared_ptr<SymbolTable> fInterpreterSymbolTable;
232
233 std::shared_ptr<SymbolTable> fTypes;
234 IRGenerator* fIRGenerator;
235 int fFlags;
236
237 const String* fSource;
238 std::shared_ptr<Context> fContext;
239 int fErrorCount;
240 String fErrorText;
241};
242
243#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
244struct PipelineStageArgs {
245 String fCode;
246 std::vector<Compiler::FormatArg> fFormatArgs;
247 std::vector<Compiler::GLSLFunction> fFunctions;
248};
249#endif
250
251} // namespace
252
253#endif
254