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 | #include "src/sksl/SkSLIRGenerator.h" |
9 | |
10 | #include "limits.h" |
11 | #include <memory> |
12 | #include <unordered_set> |
13 | |
14 | #include "src/sksl/SkSLCompiler.h" |
15 | #include "src/sksl/SkSLParser.h" |
16 | #include "src/sksl/SkSLUtil.h" |
17 | #include "src/sksl/ir/SkSLBinaryExpression.h" |
18 | #include "src/sksl/ir/SkSLBoolLiteral.h" |
19 | #include "src/sksl/ir/SkSLBreakStatement.h" |
20 | #include "src/sksl/ir/SkSLConstructor.h" |
21 | #include "src/sksl/ir/SkSLContinueStatement.h" |
22 | #include "src/sksl/ir/SkSLDiscardStatement.h" |
23 | #include "src/sksl/ir/SkSLDoStatement.h" |
24 | #include "src/sksl/ir/SkSLEnum.h" |
25 | #include "src/sksl/ir/SkSLExpressionStatement.h" |
26 | #include "src/sksl/ir/SkSLExternalFunctionCall.h" |
27 | #include "src/sksl/ir/SkSLExternalValueReference.h" |
28 | #include "src/sksl/ir/SkSLField.h" |
29 | #include "src/sksl/ir/SkSLFieldAccess.h" |
30 | #include "src/sksl/ir/SkSLFloatLiteral.h" |
31 | #include "src/sksl/ir/SkSLForStatement.h" |
32 | #include "src/sksl/ir/SkSLFunctionCall.h" |
33 | #include "src/sksl/ir/SkSLFunctionDeclaration.h" |
34 | #include "src/sksl/ir/SkSLFunctionDefinition.h" |
35 | #include "src/sksl/ir/SkSLFunctionReference.h" |
36 | #include "src/sksl/ir/SkSLIfStatement.h" |
37 | #include "src/sksl/ir/SkSLIndexExpression.h" |
38 | #include "src/sksl/ir/SkSLIntLiteral.h" |
39 | #include "src/sksl/ir/SkSLInterfaceBlock.h" |
40 | #include "src/sksl/ir/SkSLLayout.h" |
41 | #include "src/sksl/ir/SkSLNop.h" |
42 | #include "src/sksl/ir/SkSLNullLiteral.h" |
43 | #include "src/sksl/ir/SkSLPostfixExpression.h" |
44 | #include "src/sksl/ir/SkSLPrefixExpression.h" |
45 | #include "src/sksl/ir/SkSLReturnStatement.h" |
46 | #include "src/sksl/ir/SkSLSetting.h" |
47 | #include "src/sksl/ir/SkSLSwitchCase.h" |
48 | #include "src/sksl/ir/SkSLSwitchStatement.h" |
49 | #include "src/sksl/ir/SkSLSwizzle.h" |
50 | #include "src/sksl/ir/SkSLTernaryExpression.h" |
51 | #include "src/sksl/ir/SkSLUnresolvedFunction.h" |
52 | #include "src/sksl/ir/SkSLVarDeclarations.h" |
53 | #include "src/sksl/ir/SkSLVarDeclarationsStatement.h" |
54 | #include "src/sksl/ir/SkSLVariable.h" |
55 | #include "src/sksl/ir/SkSLVariableReference.h" |
56 | #include "src/sksl/ir/SkSLWhileStatement.h" |
57 | |
58 | namespace SkSL { |
59 | |
60 | class AutoSymbolTable { |
61 | public: |
62 | AutoSymbolTable(IRGenerator* ir) |
63 | : fIR(ir) |
64 | , fPrevious(fIR->fSymbolTable) { |
65 | fIR->pushSymbolTable(); |
66 | } |
67 | |
68 | ~AutoSymbolTable() { |
69 | fIR->popSymbolTable(); |
70 | SkASSERT(fPrevious == fIR->fSymbolTable); |
71 | } |
72 | |
73 | IRGenerator* fIR; |
74 | std::shared_ptr<SymbolTable> fPrevious; |
75 | }; |
76 | |
77 | class AutoLoopLevel { |
78 | public: |
79 | AutoLoopLevel(IRGenerator* ir) |
80 | : fIR(ir) { |
81 | fIR->fLoopLevel++; |
82 | } |
83 | |
84 | ~AutoLoopLevel() { |
85 | fIR->fLoopLevel--; |
86 | } |
87 | |
88 | IRGenerator* fIR; |
89 | }; |
90 | |
91 | class AutoSwitchLevel { |
92 | public: |
93 | AutoSwitchLevel(IRGenerator* ir) |
94 | : fIR(ir) { |
95 | fIR->fSwitchLevel++; |
96 | } |
97 | |
98 | ~AutoSwitchLevel() { |
99 | fIR->fSwitchLevel--; |
100 | } |
101 | |
102 | IRGenerator* fIR; |
103 | }; |
104 | |
105 | class AutoDisableInline { |
106 | public: |
107 | AutoDisableInline(IRGenerator* ir, bool canInline = false) |
108 | : fIR(ir) { |
109 | fOldCanInline = ir->fCanInline; |
110 | fIR->fCanInline &= canInline; |
111 | } |
112 | |
113 | ~AutoDisableInline() { |
114 | fIR->fCanInline = fOldCanInline; |
115 | } |
116 | |
117 | IRGenerator* fIR; |
118 | bool fOldCanInline; |
119 | }; |
120 | |
121 | IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> symbolTable, |
122 | ErrorReporter& errorReporter) |
123 | : fContext(*context) |
124 | , fCurrentFunction(nullptr) |
125 | , fRootSymbolTable(symbolTable) |
126 | , fSymbolTable(symbolTable) |
127 | , fLoopLevel(0) |
128 | , fSwitchLevel(0) |
129 | , fErrors(errorReporter) {} |
130 | |
131 | void IRGenerator::pushSymbolTable() { |
132 | fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable))); |
133 | } |
134 | |
135 | void IRGenerator::popSymbolTable() { |
136 | fSymbolTable = fSymbolTable->fParent; |
137 | } |
138 | |
139 | static void fill_caps(const SKSL_CAPS_CLASS& caps, |
140 | std::unordered_map<String, Program::Settings::Value>* capsMap) { |
141 | #define CAP(name) \ |
142 | capsMap->insert(std::make_pair(String(#name), Program::Settings::Value(caps.name()))) |
143 | CAP(fbFetchSupport); |
144 | CAP(fbFetchNeedsCustomOutput); |
145 | CAP(flatInterpolationSupport); |
146 | CAP(noperspectiveInterpolationSupport); |
147 | CAP(externalTextureSupport); |
148 | CAP(mustEnableAdvBlendEqs); |
149 | CAP(mustEnableSpecificAdvBlendEqs); |
150 | CAP(mustDeclareFragmentShaderOutput); |
151 | CAP(mustDoOpBetweenFloorAndAbs); |
152 | CAP(mustGuardDivisionEvenAfterExplicitZeroCheck); |
153 | CAP(inBlendModesFailRandomlyForAllZeroVec); |
154 | CAP(atan2ImplementedAsAtanYOverX); |
155 | CAP(canUseAnyFunctionInShader); |
156 | CAP(floatIs32Bits); |
157 | CAP(integerSupport); |
158 | #undef CAP |
159 | } |
160 | |
161 | void IRGenerator::start(const Program::Settings* settings, |
162 | std::vector<std::unique_ptr<ProgramElement>>* inherited, |
163 | bool isBuiltinCode) { |
164 | fSettings = settings; |
165 | fInherited = inherited; |
166 | fIsBuiltinCode = isBuiltinCode; |
167 | fCapsMap.clear(); |
168 | if (settings->fCaps) { |
169 | fill_caps(*settings->fCaps, &fCapsMap); |
170 | } else { |
171 | fCapsMap.insert(std::make_pair(String("integerSupport" ), |
172 | Program::Settings::Value(true))); |
173 | } |
174 | this->pushSymbolTable(); |
175 | fInvocations = -1; |
176 | fInputs.reset(); |
177 | fSkPerVertex = nullptr; |
178 | fRTAdjust = nullptr; |
179 | fRTAdjustInterfaceBlock = nullptr; |
180 | fInlineVarCounter = 0; |
181 | if (inherited) { |
182 | for (const auto& e : *inherited) { |
183 | if (e->fKind == ProgramElement::kInterfaceBlock_Kind) { |
184 | InterfaceBlock& intf = (InterfaceBlock&) *e; |
185 | if (intf.fVariable.fName == Compiler::PERVERTEX_NAME) { |
186 | SkASSERT(!fSkPerVertex); |
187 | fSkPerVertex = &intf.fVariable; |
188 | } |
189 | } |
190 | } |
191 | } |
192 | SkASSERT(fIntrinsics); |
193 | for (auto& pair : *fIntrinsics) { |
194 | pair.second.second = false; |
195 | } |
196 | } |
197 | |
198 | std::unique_ptr<Extension> IRGenerator::convertExtension(int offset, StringFragment name) { |
199 | return std::make_unique<Extension>(offset, name); |
200 | } |
201 | |
202 | void IRGenerator::finish() { |
203 | this->popSymbolTable(); |
204 | fSettings = nullptr; |
205 | } |
206 | |
207 | std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& statement) { |
208 | switch (statement.fKind) { |
209 | case ASTNode::Kind::kBlock: |
210 | return this->convertBlock(statement); |
211 | case ASTNode::Kind::kVarDeclarations: |
212 | return this->convertVarDeclarationStatement(statement); |
213 | case ASTNode::Kind::kIf: |
214 | return this->convertIf(statement); |
215 | case ASTNode::Kind::kFor: |
216 | return this->convertFor(statement); |
217 | case ASTNode::Kind::kWhile: |
218 | return this->convertWhile(statement); |
219 | case ASTNode::Kind::kDo: |
220 | return this->convertDo(statement); |
221 | case ASTNode::Kind::kSwitch: |
222 | return this->convertSwitch(statement); |
223 | case ASTNode::Kind::kReturn: |
224 | return this->convertReturn(statement); |
225 | case ASTNode::Kind::kBreak: |
226 | return this->convertBreak(statement); |
227 | case ASTNode::Kind::kContinue: |
228 | return this->convertContinue(statement); |
229 | case ASTNode::Kind::kDiscard: |
230 | return this->convertDiscard(statement); |
231 | default: |
232 | // it's an expression |
233 | std::unique_ptr<Statement> result = this->convertExpressionStatement(statement); |
234 | if (fRTAdjust && Program::kGeometry_Kind == fKind) { |
235 | SkASSERT(result->fKind == Statement::kExpression_Kind); |
236 | Expression& expr = *((ExpressionStatement&) *result).fExpression; |
237 | if (expr.fKind == Expression::kFunctionCall_Kind) { |
238 | FunctionCall& fc = (FunctionCall&) expr; |
239 | if (fc.fFunction.fBuiltin && fc.fFunction.fName == "EmitVertex" ) { |
240 | std::vector<std::unique_ptr<Statement>> statements; |
241 | statements.push_back(getNormalizeSkPositionCode()); |
242 | statements.push_back(std::move(result)); |
243 | return std::make_unique<Block>(statement.fOffset, std::move(statements), |
244 | fSymbolTable); |
245 | } |
246 | } |
247 | } |
248 | return result; |
249 | } |
250 | } |
251 | |
252 | std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) { |
253 | std::vector<std::unique_ptr<Statement>> = std::move(fExtraStatements); |
254 | std::unique_ptr<Statement> result = this->convertSingleStatement(statement); |
255 | if (!result) { |
256 | fExtraStatements = std::move(oldExtraStatements); |
257 | return nullptr; |
258 | } |
259 | if (fExtraStatements.size()) { |
260 | fExtraStatements.push_back(std::move(result)); |
261 | std::unique_ptr<Statement> block(new Block(-1, std::move(fExtraStatements), nullptr, |
262 | false)); |
263 | fExtraStatements = std::move(oldExtraStatements); |
264 | return block; |
265 | } |
266 | fExtraStatements = std::move(oldExtraStatements); |
267 | return result; |
268 | } |
269 | |
270 | std::unique_ptr<Block> IRGenerator::convertBlock(const ASTNode& block) { |
271 | SkASSERT(block.fKind == ASTNode::Kind::kBlock); |
272 | AutoSymbolTable table(this); |
273 | std::vector<std::unique_ptr<Statement>> statements; |
274 | for (const auto& child : block) { |
275 | std::unique_ptr<Statement> statement = this->convertStatement(child); |
276 | if (!statement) { |
277 | return nullptr; |
278 | } |
279 | statements.push_back(std::move(statement)); |
280 | } |
281 | return std::make_unique<Block>(block.fOffset, std::move(statements), fSymbolTable); |
282 | } |
283 | |
284 | std::unique_ptr<Statement> IRGenerator::convertVarDeclarationStatement(const ASTNode& s) { |
285 | SkASSERT(s.fKind == ASTNode::Kind::kVarDeclarations); |
286 | auto decl = this->convertVarDeclarations(s, Variable::kLocal_Storage); |
287 | if (!decl) { |
288 | return nullptr; |
289 | } |
290 | return std::unique_ptr<Statement>(new VarDeclarationsStatement(std::move(decl))); |
291 | } |
292 | |
293 | std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTNode& decls, |
294 | Variable::Storage storage) { |
295 | SkASSERT(decls.fKind == ASTNode::Kind::kVarDeclarations); |
296 | auto iter = decls.begin(); |
297 | const Modifiers& modifiers = iter++->getModifiers(); |
298 | const ASTNode& rawType = *(iter++); |
299 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
300 | const Type* baseType = this->convertType(rawType); |
301 | if (!baseType) { |
302 | return nullptr; |
303 | } |
304 | if (baseType->nonnullable() == *fContext.fFragmentProcessor_Type && |
305 | storage != Variable::kGlobal_Storage) { |
306 | fErrors.error(decls.fOffset, |
307 | "variables of type '" + baseType->displayName() + "' must be global" ); |
308 | } |
309 | if (fKind != Program::kFragmentProcessor_Kind) { |
310 | if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
311 | baseType->kind() == Type::Kind::kMatrix_Kind) { |
312 | fErrors.error(decls.fOffset, "'in' variables may not have matrix type" ); |
313 | } |
314 | if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
315 | (modifiers.fFlags & Modifiers::kUniform_Flag)) { |
316 | fErrors.error(decls.fOffset, |
317 | "'in uniform' variables only permitted within fragment processors" ); |
318 | } |
319 | if (modifiers.fLayout.fWhen.fLength) { |
320 | fErrors.error(decls.fOffset, "'when' is only permitted within fragment processors" ); |
321 | } |
322 | if (modifiers.fLayout.fFlags & Layout::kTracked_Flag) { |
323 | fErrors.error(decls.fOffset, "'tracked' is only permitted within fragment processors" ); |
324 | } |
325 | if (modifiers.fLayout.fCType != Layout::CType::kDefault) { |
326 | fErrors.error(decls.fOffset, "'ctype' is only permitted within fragment processors" ); |
327 | } |
328 | if (modifiers.fLayout.fKey) { |
329 | fErrors.error(decls.fOffset, "'key' is only permitted within fragment processors" ); |
330 | } |
331 | } |
332 | if (fKind == Program::kPipelineStage_Kind) { |
333 | if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
334 | baseType->nonnullable() != *fContext.fFragmentProcessor_Type) { |
335 | fErrors.error(decls.fOffset, "'in' variables not permitted in runtime effects" ); |
336 | } |
337 | } |
338 | if (modifiers.fLayout.fKey && (modifiers.fFlags & Modifiers::kUniform_Flag)) { |
339 | fErrors.error(decls.fOffset, "'key' is not permitted on 'uniform' variables" ); |
340 | } |
341 | if (modifiers.fLayout.fMarker.fLength) { |
342 | if (fKind != Program::kPipelineStage_Kind) { |
343 | fErrors.error(decls.fOffset, "'marker' is only permitted in runtime effects" ); |
344 | } |
345 | if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) { |
346 | fErrors.error(decls.fOffset, "'marker' is only permitted on 'uniform' variables" ); |
347 | } |
348 | if (*baseType != *fContext.fFloat4x4_Type) { |
349 | fErrors.error(decls.fOffset, "'marker' is only permitted on float4x4 variables" ); |
350 | } |
351 | } |
352 | if (modifiers.fLayout.fFlags & Layout::kSRGBUnpremul_Flag) { |
353 | if (fKind != Program::kPipelineStage_Kind) { |
354 | fErrors.error(decls.fOffset, "'srgb_unpremul' is only permitted in runtime effects" ); |
355 | } |
356 | if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) { |
357 | fErrors.error(decls.fOffset, |
358 | "'srgb_unpremul' is only permitted on 'uniform' variables" ); |
359 | } |
360 | auto validColorXformType = [](const Type& t) { |
361 | return t.kind() == Type::kVector_Kind && t.componentType().isFloat() && |
362 | (t.columns() == 3 || t.columns() == 4); |
363 | }; |
364 | if (!validColorXformType(*baseType) && !(baseType->kind() == Type::kArray_Kind && |
365 | validColorXformType(baseType->componentType()))) { |
366 | fErrors.error(decls.fOffset, |
367 | "'srgb_unpremul' is only permitted on half3, half4, float3, or float4 " |
368 | "variables" ); |
369 | } |
370 | } |
371 | if (modifiers.fFlags & Modifiers::kVarying_Flag) { |
372 | if (fKind != Program::kPipelineStage_Kind) { |
373 | fErrors.error(decls.fOffset, "'varying' is only permitted in runtime effects" ); |
374 | } |
375 | if (!baseType->isFloat() && |
376 | !(baseType->kind() == Type::kVector_Kind && baseType->componentType().isFloat())) { |
377 | fErrors.error(decls.fOffset, "'varying' must be float scalar or vector" ); |
378 | } |
379 | } |
380 | for (; iter != decls.end(); ++iter) { |
381 | const ASTNode& varDecl = *iter; |
382 | if (modifiers.fLayout.fLocation == 0 && modifiers.fLayout.fIndex == 0 && |
383 | (modifiers.fFlags & Modifiers::kOut_Flag) && fKind == Program::kFragment_Kind && |
384 | varDecl.getVarData().fName != "sk_FragColor" ) { |
385 | fErrors.error(varDecl.fOffset, |
386 | "out location=0, index=0 is reserved for sk_FragColor" ); |
387 | } |
388 | const ASTNode::VarData& varData = varDecl.getVarData(); |
389 | const Type* type = baseType; |
390 | std::vector<std::unique_ptr<Expression>> sizes; |
391 | auto iter = varDecl.begin(); |
392 | if (varData.fSizeCount > 0 && (modifiers.fFlags & Modifiers::kIn_Flag)) { |
393 | fErrors.error(varDecl.fOffset, "'in' variables may not have array type" ); |
394 | } |
395 | for (size_t i = 0; i < varData.fSizeCount; ++i, ++iter) { |
396 | const ASTNode& rawSize = *iter; |
397 | if (rawSize) { |
398 | auto size = this->coerce(this->convertExpression(rawSize), *fContext.fInt_Type); |
399 | if (!size) { |
400 | return nullptr; |
401 | } |
402 | String name(type->fName); |
403 | int64_t count; |
404 | if (size->fKind == Expression::kIntLiteral_Kind) { |
405 | count = ((IntLiteral&) *size).fValue; |
406 | if (count <= 0) { |
407 | fErrors.error(size->fOffset, "array size must be positive" ); |
408 | return nullptr; |
409 | } |
410 | name += "[" + to_string(count) + "]" ; |
411 | } else { |
412 | fErrors.error(size->fOffset, "array size must be specified" ); |
413 | return nullptr; |
414 | } |
415 | type = fSymbolTable->takeOwnershipOfSymbol( |
416 | std::make_unique<Type>(name, Type::kArray_Kind, *type, (int)count)); |
417 | sizes.push_back(std::move(size)); |
418 | } else { |
419 | type = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>( |
420 | type->name() + "[]" , Type::kArray_Kind, *type, /*columns=*/-1)); |
421 | sizes.push_back(nullptr); |
422 | } |
423 | } |
424 | auto var = std::make_unique<Variable>(varDecl.fOffset, modifiers, varData.fName, *type, |
425 | storage); |
426 | if (var->fName == Compiler::RTADJUST_NAME) { |
427 | SkASSERT(!fRTAdjust); |
428 | SkASSERT(var->fType == *fContext.fFloat4_Type); |
429 | fRTAdjust = var.get(); |
430 | } |
431 | std::unique_ptr<Expression> value; |
432 | if (iter != varDecl.end()) { |
433 | value = this->convertExpression(*iter); |
434 | if (!value) { |
435 | return nullptr; |
436 | } |
437 | value = this->coerce(std::move(value), *type); |
438 | if (!value) { |
439 | return nullptr; |
440 | } |
441 | var->fWriteCount = 1; |
442 | var->fInitialValue = value.get(); |
443 | } |
444 | if (storage == Variable::kGlobal_Storage && var->fName == "sk_FragColor" && |
445 | (*fSymbolTable)[var->fName]) { |
446 | // already defined, ignore |
447 | } else if (storage == Variable::kGlobal_Storage && (*fSymbolTable)[var->fName] && |
448 | (*fSymbolTable)[var->fName]->fKind == Symbol::kVariable_Kind && |
449 | ((Variable*) (*fSymbolTable)[var->fName])->fModifiers.fLayout.fBuiltin >= 0) { |
450 | // already defined, just update the modifiers |
451 | Variable* old = (Variable*) (*fSymbolTable)[var->fName]; |
452 | old->fModifiers = var->fModifiers; |
453 | } else { |
454 | variables.emplace_back(new VarDeclaration(var.get(), std::move(sizes), |
455 | std::move(value))); |
456 | StringFragment name = var->fName; |
457 | fSymbolTable->add(name, std::move(var)); |
458 | } |
459 | } |
460 | return std::make_unique<VarDeclarations>(decls.fOffset, baseType, std::move(variables)); |
461 | } |
462 | |
463 | std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(const ASTNode& m) { |
464 | SkASSERT(m.fKind == ASTNode::Kind::kModifiers); |
465 | Modifiers modifiers = m.getModifiers(); |
466 | if (modifiers.fLayout.fInvocations != -1) { |
467 | if (fKind != Program::kGeometry_Kind) { |
468 | fErrors.error(m.fOffset, "'invocations' is only legal in geometry shaders" ); |
469 | return nullptr; |
470 | } |
471 | fInvocations = modifiers.fLayout.fInvocations; |
472 | if (fSettings->fCaps && !fSettings->fCaps->gsInvocationsSupport()) { |
473 | modifiers.fLayout.fInvocations = -1; |
474 | Variable* invocationId = (Variable*) (*fSymbolTable)["sk_InvocationID" ]; |
475 | SkASSERT(invocationId); |
476 | invocationId->fModifiers.fFlags = 0; |
477 | invocationId->fModifiers.fLayout.fBuiltin = -1; |
478 | if (modifiers.fLayout.description() == "" ) { |
479 | return nullptr; |
480 | } |
481 | } |
482 | } |
483 | if (modifiers.fLayout.fMaxVertices != -1 && fInvocations > 0 && fSettings->fCaps && |
484 | !fSettings->fCaps->gsInvocationsSupport()) { |
485 | modifiers.fLayout.fMaxVertices *= fInvocations; |
486 | } |
487 | return std::make_unique<ModifiersDeclaration>(modifiers); |
488 | } |
489 | |
490 | std::unique_ptr<Statement> IRGenerator::convertIf(const ASTNode& n) { |
491 | SkASSERT(n.fKind == ASTNode::Kind::kIf); |
492 | auto iter = n.begin(); |
493 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
494 | *fContext.fBool_Type); |
495 | if (!test) { |
496 | return nullptr; |
497 | } |
498 | std::unique_ptr<Statement> ifTrue = this->convertStatement(*(iter++)); |
499 | if (!ifTrue) { |
500 | return nullptr; |
501 | } |
502 | std::unique_ptr<Statement> ifFalse; |
503 | if (iter != n.end()) { |
504 | ifFalse = this->convertStatement(*(iter++)); |
505 | if (!ifFalse) { |
506 | return nullptr; |
507 | } |
508 | } |
509 | if (test->fKind == Expression::kBoolLiteral_Kind) { |
510 | // static boolean value, fold down to a single branch |
511 | if (((BoolLiteral&) *test).fValue) { |
512 | return ifTrue; |
513 | } else if (ifFalse) { |
514 | return ifFalse; |
515 | } else { |
516 | // False & no else clause. Not an error, so don't return null! |
517 | std::vector<std::unique_ptr<Statement>> empty; |
518 | return std::unique_ptr<Statement>(new Block(n.fOffset, std::move(empty), |
519 | fSymbolTable)); |
520 | } |
521 | } |
522 | return std::unique_ptr<Statement>(new IfStatement(n.fOffset, n.getBool(), std::move(test), |
523 | std::move(ifTrue), std::move(ifFalse))); |
524 | } |
525 | |
526 | std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) { |
527 | SkASSERT(f.fKind == ASTNode::Kind::kFor); |
528 | AutoLoopLevel level(this); |
529 | AutoSymbolTable table(this); |
530 | std::unique_ptr<Statement> initializer; |
531 | auto iter = f.begin(); |
532 | if (*iter) { |
533 | initializer = this->convertStatement(*iter); |
534 | if (!initializer) { |
535 | return nullptr; |
536 | } |
537 | } |
538 | ++iter; |
539 | std::unique_ptr<Expression> test; |
540 | if (*iter) { |
541 | AutoDisableInline disableInline(this); |
542 | test = this->coerce(this->convertExpression(*iter), *fContext.fBool_Type); |
543 | if (!test) { |
544 | return nullptr; |
545 | } |
546 | |
547 | } |
548 | ++iter; |
549 | std::unique_ptr<Expression> next; |
550 | if (*iter) { |
551 | AutoDisableInline disableInline(this); |
552 | next = this->convertExpression(*iter); |
553 | if (!next) { |
554 | return nullptr; |
555 | } |
556 | this->checkValid(*next); |
557 | } |
558 | ++iter; |
559 | std::unique_ptr<Statement> statement = this->convertStatement(*iter); |
560 | if (!statement) { |
561 | return nullptr; |
562 | } |
563 | return std::make_unique<ForStatement>(f.fOffset, std::move(initializer), std::move(test), |
564 | std::move(next), std::move(statement), fSymbolTable); |
565 | } |
566 | |
567 | std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) { |
568 | SkASSERT(w.fKind == ASTNode::Kind::kWhile); |
569 | AutoLoopLevel level(this); |
570 | std::unique_ptr<Expression> test; |
571 | auto iter = w.begin(); |
572 | { |
573 | AutoDisableInline disableInline(this); |
574 | test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type); |
575 | } |
576 | if (!test) { |
577 | return nullptr; |
578 | } |
579 | std::unique_ptr<Statement> statement = this->convertStatement(*(iter++)); |
580 | if (!statement) { |
581 | return nullptr; |
582 | } |
583 | return std::make_unique<WhileStatement>(w.fOffset, std::move(test), std::move(statement)); |
584 | } |
585 | |
586 | std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) { |
587 | SkASSERT(d.fKind == ASTNode::Kind::kDo); |
588 | AutoLoopLevel level(this); |
589 | auto iter = d.begin(); |
590 | std::unique_ptr<Statement> statement = this->convertStatement(*(iter++)); |
591 | if (!statement) { |
592 | return nullptr; |
593 | } |
594 | std::unique_ptr<Expression> test; |
595 | { |
596 | AutoDisableInline disableInline(this); |
597 | test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type); |
598 | } |
599 | if (!test) { |
600 | return nullptr; |
601 | } |
602 | return std::make_unique<DoStatement>(d.fOffset, std::move(statement), std::move(test)); |
603 | } |
604 | |
605 | std::unique_ptr<Statement> IRGenerator::convertSwitch(const ASTNode& s) { |
606 | SkASSERT(s.fKind == ASTNode::Kind::kSwitch); |
607 | AutoSwitchLevel level(this); |
608 | auto iter = s.begin(); |
609 | std::unique_ptr<Expression> value = this->convertExpression(*(iter++)); |
610 | if (!value) { |
611 | return nullptr; |
612 | } |
613 | if (value->fType != *fContext.fUInt_Type && value->fType.kind() != Type::kEnum_Kind) { |
614 | value = this->coerce(std::move(value), *fContext.fInt_Type); |
615 | if (!value) { |
616 | return nullptr; |
617 | } |
618 | } |
619 | AutoSymbolTable table(this); |
620 | std::unordered_set<int> caseValues; |
621 | std::vector<std::unique_ptr<SwitchCase>> cases; |
622 | for (; iter != s.end(); ++iter) { |
623 | const ASTNode& c = *iter; |
624 | SkASSERT(c.fKind == ASTNode::Kind::kSwitchCase); |
625 | std::unique_ptr<Expression> caseValue; |
626 | auto childIter = c.begin(); |
627 | if (*childIter) { |
628 | caseValue = this->convertExpression(*childIter); |
629 | if (!caseValue) { |
630 | return nullptr; |
631 | } |
632 | caseValue = this->coerce(std::move(caseValue), value->fType); |
633 | if (!caseValue) { |
634 | return nullptr; |
635 | } |
636 | int64_t v = 0; |
637 | if (!this->getConstantInt(*caseValue, &v)) { |
638 | fErrors.error(caseValue->fOffset, "case value must be a constant integer" ); |
639 | return nullptr; |
640 | } |
641 | if (caseValues.find(v) != caseValues.end()) { |
642 | fErrors.error(caseValue->fOffset, "duplicate case value" ); |
643 | } |
644 | caseValues.insert(v); |
645 | } |
646 | ++childIter; |
647 | std::vector<std::unique_ptr<Statement>> statements; |
648 | for (; childIter != c.end(); ++childIter) { |
649 | std::unique_ptr<Statement> converted = this->convertStatement(*childIter); |
650 | if (!converted) { |
651 | return nullptr; |
652 | } |
653 | statements.push_back(std::move(converted)); |
654 | } |
655 | cases.emplace_back(new SwitchCase(c.fOffset, std::move(caseValue), |
656 | std::move(statements))); |
657 | } |
658 | return std::unique_ptr<Statement>(new SwitchStatement(s.fOffset, s.getBool(), |
659 | std::move(value), std::move(cases), |
660 | fSymbolTable)); |
661 | } |
662 | |
663 | std::unique_ptr<Statement> IRGenerator::convertExpressionStatement(const ASTNode& s) { |
664 | std::unique_ptr<Expression> e = this->convertExpression(s); |
665 | if (!e) { |
666 | return nullptr; |
667 | } |
668 | this->checkValid(*e); |
669 | return std::unique_ptr<Statement>(new ExpressionStatement(std::move(e))); |
670 | } |
671 | |
672 | std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTNode& r) { |
673 | SkASSERT(r.fKind == ASTNode::Kind::kReturn); |
674 | SkASSERT(fCurrentFunction); |
675 | // early returns from a vertex main function will bypass the sk_Position normalization, so |
676 | // SkASSERT that we aren't doing that. It is of course possible to fix this by adding a |
677 | // normalization before each return, but it will probably never actually be necessary. |
678 | SkASSERT(Program::kVertex_Kind != fKind || !fRTAdjust || "main" != fCurrentFunction->fName); |
679 | if (r.begin() != r.end()) { |
680 | std::unique_ptr<Expression> result = this->convertExpression(*r.begin()); |
681 | if (!result) { |
682 | return nullptr; |
683 | } |
684 | if (fCurrentFunction->fReturnType == *fContext.fVoid_Type) { |
685 | fErrors.error(result->fOffset, "may not return a value from a void function" ); |
686 | } else { |
687 | result = this->coerce(std::move(result), fCurrentFunction->fReturnType); |
688 | if (!result) { |
689 | return nullptr; |
690 | } |
691 | } |
692 | return std::unique_ptr<Statement>(new ReturnStatement(std::move(result))); |
693 | } else { |
694 | if (fCurrentFunction->fReturnType != *fContext.fVoid_Type) { |
695 | fErrors.error(r.fOffset, "expected function to return '" + |
696 | fCurrentFunction->fReturnType.displayName() + "'" ); |
697 | } |
698 | return std::unique_ptr<Statement>(new ReturnStatement(r.fOffset)); |
699 | } |
700 | } |
701 | |
702 | std::unique_ptr<Statement> IRGenerator::convertBreak(const ASTNode& b) { |
703 | SkASSERT(b.fKind == ASTNode::Kind::kBreak); |
704 | if (fLoopLevel > 0 || fSwitchLevel > 0) { |
705 | return std::unique_ptr<Statement>(new BreakStatement(b.fOffset)); |
706 | } else { |
707 | fErrors.error(b.fOffset, "break statement must be inside a loop or switch" ); |
708 | return nullptr; |
709 | } |
710 | } |
711 | |
712 | std::unique_ptr<Statement> IRGenerator::convertContinue(const ASTNode& c) { |
713 | SkASSERT(c.fKind == ASTNode::Kind::kContinue); |
714 | if (fLoopLevel > 0) { |
715 | return std::unique_ptr<Statement>(new ContinueStatement(c.fOffset)); |
716 | } else { |
717 | fErrors.error(c.fOffset, "continue statement must be inside a loop" ); |
718 | return nullptr; |
719 | } |
720 | } |
721 | |
722 | std::unique_ptr<Statement> IRGenerator::convertDiscard(const ASTNode& d) { |
723 | SkASSERT(d.fKind == ASTNode::Kind::kDiscard); |
724 | return std::unique_ptr<Statement>(new DiscardStatement(d.fOffset)); |
725 | } |
726 | |
727 | std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<Block> main) { |
728 | Layout invokeLayout; |
729 | Modifiers invokeModifiers(invokeLayout, Modifiers::kHasSideEffects_Flag); |
730 | FunctionDeclaration* invokeDecl = new FunctionDeclaration(-1, |
731 | invokeModifiers, |
732 | "_invoke" , |
733 | std::vector<const Variable*>(), |
734 | *fContext.fVoid_Type, |
735 | false); |
736 | fProgramElements->push_back(std::unique_ptr<ProgramElement>( |
737 | new FunctionDefinition(-1, *invokeDecl, std::move(main)))); |
738 | fSymbolTable->add(invokeDecl->fName, std::unique_ptr<FunctionDeclaration>(invokeDecl)); |
739 | |
740 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
741 | Variable* loopIdx = (Variable*) (*fSymbolTable)["sk_InvocationID" ]; |
742 | SkASSERT(loopIdx); |
743 | std::unique_ptr<Expression> test(new BinaryExpression(-1, |
744 | std::unique_ptr<Expression>(new VariableReference(-1, *loopIdx)), |
745 | Token::Kind::TK_LT, |
746 | std::make_unique<IntLiteral>(fContext, -1, fInvocations), |
747 | *fContext.fBool_Type)); |
748 | std::unique_ptr<Expression> next(new PostfixExpression( |
749 | std::unique_ptr<Expression>( |
750 | new VariableReference(-1, |
751 | *loopIdx, |
752 | VariableReference::kReadWrite_RefKind)), |
753 | Token::Kind::TK_PLUSPLUS)); |
754 | ASTNode endPrimitiveID(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, "EndPrimitive" ); |
755 | std::unique_ptr<Expression> endPrimitive = this->convertExpression(endPrimitiveID); |
756 | SkASSERT(endPrimitive); |
757 | |
758 | std::vector<std::unique_ptr<Statement>> loopBody; |
759 | std::vector<std::unique_ptr<Expression>> invokeArgs; |
760 | loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement( |
761 | this->call(-1, |
762 | *invokeDecl, |
763 | std::vector<std::unique_ptr<Expression>>())))); |
764 | loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement( |
765 | this->call(-1, |
766 | std::move(endPrimitive), |
767 | std::vector<std::unique_ptr<Expression>>())))); |
768 | std::unique_ptr<Expression> assignment(new BinaryExpression(-1, |
769 | std::unique_ptr<Expression>(new VariableReference(-1, *loopIdx, |
770 | VariableReference::kWrite_RefKind)), |
771 | Token::Kind::TK_EQ, |
772 | std::make_unique<IntLiteral>(fContext, -1, 0), |
773 | *fContext.fInt_Type)); |
774 | std::unique_ptr<Statement> initializer(new ExpressionStatement(std::move(assignment))); |
775 | std::unique_ptr<Statement> loop = std::unique_ptr<Statement>( |
776 | new ForStatement(-1, |
777 | std::move(initializer), |
778 | std::move(test), |
779 | std::move(next), |
780 | std::make_unique<Block>(-1, std::move(loopBody)), |
781 | fSymbolTable)); |
782 | std::vector<std::unique_ptr<Statement>> children; |
783 | children.push_back(std::move(loop)); |
784 | return std::make_unique<Block>(-1, std::move(children)); |
785 | } |
786 | |
787 | std::unique_ptr<Statement> IRGenerator::getNormalizeSkPositionCode() { |
788 | // sk_Position = float4(sk_Position.xy * rtAdjust.xz + sk_Position.ww * rtAdjust.yw, |
789 | // 0, |
790 | // sk_Position.w); |
791 | SkASSERT(fSkPerVertex && fRTAdjust); |
792 | #define REF(var) std::unique_ptr<Expression>(\ |
793 | new VariableReference(-1, *var, VariableReference::kRead_RefKind)) |
794 | #define WREF(var) std::unique_ptr<Expression>(\ |
795 | new VariableReference(-1, *var, VariableReference::kWrite_RefKind)) |
796 | #define FIELD(var, idx) std::unique_ptr<Expression>(\ |
797 | new FieldAccess(REF(var), idx, FieldAccess::kAnonymousInterfaceBlock_OwnerKind)) |
798 | #define POS std::unique_ptr<Expression>(new FieldAccess(WREF(fSkPerVertex), 0, \ |
799 | FieldAccess::kAnonymousInterfaceBlock_OwnerKind)) |
800 | #define ADJUST (fRTAdjustInterfaceBlock ? \ |
801 | FIELD(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex) : \ |
802 | REF(fRTAdjust)) |
803 | #define SWIZZLE(expr, ...) std::unique_ptr<Expression>(new Swizzle(fContext, expr, \ |
804 | { __VA_ARGS__ })) |
805 | #define OP(left, op, right) std::unique_ptr<Expression>( \ |
806 | new BinaryExpression(-1, left, op, right, \ |
807 | *fContext.fFloat2_Type)) |
808 | std::vector<std::unique_ptr<Expression>> children; |
809 | children.push_back(OP(OP(SWIZZLE(POS, 0, 1), Token::Kind::TK_STAR, SWIZZLE(ADJUST, 0, 2)), |
810 | Token::Kind::TK_PLUS, |
811 | OP(SWIZZLE(POS, 3, 3), Token::Kind::TK_STAR, SWIZZLE(ADJUST, 1, 3)))); |
812 | children.push_back(std::unique_ptr<Expression>(new FloatLiteral(fContext, -1, 0.0))); |
813 | children.push_back(SWIZZLE(POS, 3)); |
814 | std::unique_ptr<Expression> result = OP(POS, Token::Kind::TK_EQ, |
815 | std::unique_ptr<Expression>(new Constructor(-1, |
816 | *fContext.fFloat4_Type, |
817 | std::move(children)))); |
818 | return std::unique_ptr<Statement>(new ExpressionStatement(std::move(result))); |
819 | } |
820 | |
821 | template<typename T> |
822 | class AutoClear { |
823 | public: |
824 | AutoClear(T* container) |
825 | : fContainer(container) { |
826 | SkASSERT(container->empty()); |
827 | } |
828 | |
829 | ~AutoClear() { |
830 | fContainer->clear(); |
831 | } |
832 | |
833 | private: |
834 | T* fContainer; |
835 | }; |
836 | |
837 | template <typename T> AutoClear(T* c) -> AutoClear<T>; |
838 | |
839 | void IRGenerator::convertFunction(const ASTNode& f) { |
840 | AutoClear clear(&fReferencedIntrinsics); |
841 | auto iter = f.begin(); |
842 | const Type* returnType = this->convertType(*(iter++)); |
843 | if (!returnType) { |
844 | return; |
845 | } |
846 | auto type_is_allowed = [&](const Type* t) { |
847 | #if defined(SKSL_STANDALONE) |
848 | return true; |
849 | #else |
850 | GrSLType unusedSLType; |
851 | return fKind != Program::kPipelineStage_Kind || |
852 | type_to_grsltype(fContext, *t, &unusedSLType); |
853 | #endif |
854 | }; |
855 | if (returnType->nonnullable() == *fContext.fFragmentProcessor_Type || |
856 | !type_is_allowed(returnType)) { |
857 | fErrors.error(f.fOffset, |
858 | "functions may not return type '" + returnType->displayName() + "'" ); |
859 | return; |
860 | } |
861 | const ASTNode::FunctionData& fd = f.getFunctionData(); |
862 | std::vector<const Variable*> parameters; |
863 | for (size_t i = 0; i < fd.fParameterCount; ++i) { |
864 | const ASTNode& param = *(iter++); |
865 | SkASSERT(param.fKind == ASTNode::Kind::kParameter); |
866 | ASTNode::ParameterData pd = param.getParameterData(); |
867 | auto paramIter = param.begin(); |
868 | const Type* type = this->convertType(*(paramIter++)); |
869 | if (!type) { |
870 | return; |
871 | } |
872 | for (int j = (int) pd.fSizeCount; j >= 1; j--) { |
873 | int size = (param.begin() + j)->getInt(); |
874 | String name = type->name() + "[" + to_string(size) + "]" ; |
875 | type = fSymbolTable->takeOwnershipOfSymbol( |
876 | std::make_unique<Type>(std::move(name), Type::kArray_Kind, *type, size)); |
877 | } |
878 | // Only the (builtin) declarations of 'sample' are allowed to have FP parameters |
879 | if ((type->nonnullable() == *fContext.fFragmentProcessor_Type && !fIsBuiltinCode) || |
880 | !type_is_allowed(type)) { |
881 | fErrors.error(param.fOffset, |
882 | "parameters of type '" + type->displayName() + "' not allowed" ); |
883 | return; |
884 | } |
885 | StringFragment name = pd.fName; |
886 | const Variable* var = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>( |
887 | param.fOffset, pd.fModifiers, name, *type, Variable::kParameter_Storage)); |
888 | parameters.push_back(var); |
889 | } |
890 | |
891 | if (fd.fName == "main" ) { |
892 | switch (fKind) { |
893 | case Program::kPipelineStage_Kind: { |
894 | bool valid; |
895 | switch (parameters.size()) { |
896 | case 2: |
897 | valid = parameters[0]->fType == *fContext.fFloat2_Type && |
898 | parameters[0]->fModifiers.fFlags == 0 && |
899 | parameters[1]->fType == *fContext.fHalf4_Type && |
900 | parameters[1]->fModifiers.fFlags == (Modifiers::kIn_Flag | |
901 | Modifiers::kOut_Flag); |
902 | break; |
903 | case 1: |
904 | valid = parameters[0]->fType == *fContext.fHalf4_Type && |
905 | parameters[0]->fModifiers.fFlags == (Modifiers::kIn_Flag | |
906 | Modifiers::kOut_Flag); |
907 | break; |
908 | default: |
909 | valid = false; |
910 | } |
911 | if (!valid) { |
912 | fErrors.error(f.fOffset, "pipeline stage 'main' must be declared main(float2, " |
913 | "inout half4) or main(inout half4)" ); |
914 | return; |
915 | } |
916 | break; |
917 | } |
918 | case Program::kFragmentProcessor_Kind: { |
919 | bool valid = parameters.size() <= 1; |
920 | if (parameters.size() == 1) { |
921 | valid = parameters[0]->fType == *fContext.fFloat2_Type && |
922 | parameters[0]->fModifiers.fFlags == 0; |
923 | } |
924 | |
925 | if (!valid) { |
926 | fErrors.error(f.fOffset, ".fp 'main' must be declared main() or main(float2)" ); |
927 | return; |
928 | } |
929 | break; |
930 | } |
931 | case Program::kGeneric_Kind: |
932 | break; |
933 | default: |
934 | if (parameters.size()) { |
935 | fErrors.error(f.fOffset, "shader 'main' must have zero parameters" ); |
936 | } |
937 | } |
938 | } |
939 | |
940 | // find existing declaration |
941 | const FunctionDeclaration* decl = nullptr; |
942 | auto entry = (*fSymbolTable)[fd.fName]; |
943 | if (entry) { |
944 | std::vector<const FunctionDeclaration*> functions; |
945 | switch (entry->fKind) { |
946 | case Symbol::kUnresolvedFunction_Kind: |
947 | functions = ((UnresolvedFunction*) entry)->fFunctions; |
948 | break; |
949 | case Symbol::kFunctionDeclaration_Kind: |
950 | functions.push_back((FunctionDeclaration*) entry); |
951 | break; |
952 | default: |
953 | fErrors.error(f.fOffset, "symbol '" + fd.fName + "' was already defined" ); |
954 | return; |
955 | } |
956 | for (const auto& other : functions) { |
957 | SkASSERT(other->fName == fd.fName); |
958 | if (parameters.size() == other->fParameters.size()) { |
959 | bool match = true; |
960 | for (size_t i = 0; i < parameters.size(); i++) { |
961 | if (parameters[i]->fType != other->fParameters[i]->fType) { |
962 | match = false; |
963 | break; |
964 | } |
965 | } |
966 | if (match) { |
967 | if (*returnType != other->fReturnType) { |
968 | FunctionDeclaration newDecl(f.fOffset, fd.fModifiers, fd.fName, parameters, |
969 | *returnType, fIsBuiltinCode); |
970 | fErrors.error(f.fOffset, "functions '" + newDecl.description() + |
971 | "' and '" + other->description() + |
972 | "' differ only in return type" ); |
973 | return; |
974 | } |
975 | decl = other; |
976 | for (size_t i = 0; i < parameters.size(); i++) { |
977 | if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) { |
978 | fErrors.error(f.fOffset, "modifiers on parameter " + |
979 | to_string((uint64_t) i + 1) + |
980 | " differ between declaration and " |
981 | "definition" ); |
982 | return; |
983 | } |
984 | } |
985 | if (other->fDefinition && !other->fBuiltin) { |
986 | fErrors.error(f.fOffset, "duplicate definition of " + |
987 | other->description()); |
988 | } |
989 | break; |
990 | } |
991 | } |
992 | } |
993 | } |
994 | if (!decl) { |
995 | // couldn't find an existing declaration |
996 | decl = fSymbolTable->add(fd.fName, |
997 | std::make_unique<FunctionDeclaration>(f.fOffset, |
998 | fd.fModifiers, |
999 | fd.fName, |
1000 | parameters, |
1001 | *returnType, |
1002 | fIsBuiltinCode)); |
1003 | } |
1004 | if (iter != f.end()) { |
1005 | // compile body |
1006 | SkASSERT(!fCurrentFunction); |
1007 | fCurrentFunction = decl; |
1008 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
1009 | AutoSymbolTable table(this); |
1010 | if (fd.fName == "main" && fKind == Program::kPipelineStage_Kind) { |
1011 | if (parameters.size() == 2) { |
1012 | parameters[0]->fModifiers.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN; |
1013 | parameters[1]->fModifiers.fLayout.fBuiltin = SK_OUTCOLOR_BUILTIN; |
1014 | } else { |
1015 | SkASSERT(parameters.size() == 1); |
1016 | parameters[0]->fModifiers.fLayout.fBuiltin = SK_OUTCOLOR_BUILTIN; |
1017 | } |
1018 | } else if (fd.fName == "main" && fKind == Program::kFragmentProcessor_Kind) { |
1019 | if (parameters.size() == 1) { |
1020 | parameters[0]->fModifiers.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN; |
1021 | } |
1022 | } |
1023 | for (size_t i = 0; i < parameters.size(); i++) { |
1024 | fSymbolTable->addWithoutOwnership(parameters[i]->fName, decl->fParameters[i]); |
1025 | } |
1026 | bool needInvocationIDWorkaround = fInvocations != -1 && fd.fName == "main" && |
1027 | fSettings->fCaps && |
1028 | !fSettings->fCaps->gsInvocationsSupport(); |
1029 | std::unique_ptr<Block> body = this->convertBlock(*iter); |
1030 | fCurrentFunction = nullptr; |
1031 | if (!body) { |
1032 | return; |
1033 | } |
1034 | if (needInvocationIDWorkaround) { |
1035 | body = this->applyInvocationIDWorkaround(std::move(body)); |
1036 | } |
1037 | // conservatively assume all user-defined functions have side effects |
1038 | ((Modifiers&) decl->fModifiers).fFlags |= Modifiers::kHasSideEffects_Flag; |
1039 | if (Program::kVertex_Kind == fKind && fd.fName == "main" && fRTAdjust) { |
1040 | body->fStatements.insert(body->fStatements.end(), this->getNormalizeSkPositionCode()); |
1041 | } |
1042 | auto result = std::make_unique<FunctionDefinition>(f.fOffset, *decl, std::move(body), |
1043 | std::move(fReferencedIntrinsics)); |
1044 | decl->fDefinition = result.get(); |
1045 | result->fSource = &f; |
1046 | fProgramElements->push_back(std::move(result)); |
1047 | } |
1048 | } |
1049 | |
1050 | std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTNode& intf) { |
1051 | SkASSERT(intf.fKind == ASTNode::Kind::kInterfaceBlock); |
1052 | ASTNode::InterfaceBlockData id = intf.getInterfaceBlockData(); |
1053 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
1054 | this->pushSymbolTable(); |
1055 | std::shared_ptr<SymbolTable> symbols = fSymbolTable; |
1056 | std::vector<Type::Field> fields; |
1057 | bool haveRuntimeArray = false; |
1058 | bool foundRTAdjust = false; |
1059 | auto iter = intf.begin(); |
1060 | for (size_t i = 0; i < id.fDeclarationCount; ++i) { |
1061 | std::unique_ptr<VarDeclarations> decl = this->convertVarDeclarations( |
1062 | *(iter++), |
1063 | Variable::kInterfaceBlock_Storage); |
1064 | if (!decl) { |
1065 | return nullptr; |
1066 | } |
1067 | for (const auto& stmt : decl->fVars) { |
1068 | VarDeclaration& vd = (VarDeclaration&) *stmt; |
1069 | if (haveRuntimeArray) { |
1070 | fErrors.error(decl->fOffset, |
1071 | "only the last entry in an interface block may be a runtime-sized " |
1072 | "array" ); |
1073 | } |
1074 | if (vd.fVar == fRTAdjust) { |
1075 | foundRTAdjust = true; |
1076 | SkASSERT(vd.fVar->fType == *fContext.fFloat4_Type); |
1077 | fRTAdjustFieldIndex = fields.size(); |
1078 | } |
1079 | fields.push_back(Type::Field(vd.fVar->fModifiers, vd.fVar->fName, |
1080 | &vd.fVar->fType)); |
1081 | if (vd.fValue) { |
1082 | fErrors.error(decl->fOffset, |
1083 | "initializers are not permitted on interface block fields" ); |
1084 | } |
1085 | if (vd.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | |
1086 | Modifiers::kOut_Flag | |
1087 | Modifiers::kUniform_Flag | |
1088 | Modifiers::kBuffer_Flag | |
1089 | Modifiers::kConst_Flag)) { |
1090 | fErrors.error(decl->fOffset, |
1091 | "interface block fields may not have storage qualifiers" ); |
1092 | } |
1093 | if (vd.fVar->fType.kind() == Type::kArray_Kind && |
1094 | vd.fVar->fType.columns() == -1) { |
1095 | haveRuntimeArray = true; |
1096 | } |
1097 | } |
1098 | } |
1099 | this->popSymbolTable(); |
1100 | const Type* type = |
1101 | old->takeOwnershipOfSymbol(std::make_unique<Type>(intf.fOffset, id.fTypeName, fields)); |
1102 | std::vector<std::unique_ptr<Expression>> sizes; |
1103 | for (size_t i = 0; i < id.fSizeCount; ++i) { |
1104 | const ASTNode& size = *(iter++); |
1105 | if (size) { |
1106 | std::unique_ptr<Expression> converted = this->convertExpression(size); |
1107 | if (!converted) { |
1108 | return nullptr; |
1109 | } |
1110 | String name = type->fName; |
1111 | int64_t count; |
1112 | if (converted->fKind == Expression::kIntLiteral_Kind) { |
1113 | count = ((IntLiteral&) *converted).fValue; |
1114 | if (count <= 0) { |
1115 | fErrors.error(converted->fOffset, "array size must be positive" ); |
1116 | return nullptr; |
1117 | } |
1118 | name += "[" + to_string(count) + "]" ; |
1119 | } else { |
1120 | fErrors.error(intf.fOffset, "array size must be specified" ); |
1121 | return nullptr; |
1122 | } |
1123 | type = symbols->takeOwnershipOfSymbol( |
1124 | std::make_unique<Type>(name, Type::kArray_Kind, *type, (int)count)); |
1125 | sizes.push_back(std::move(converted)); |
1126 | } else { |
1127 | fErrors.error(intf.fOffset, "array size must be specified" ); |
1128 | return nullptr; |
1129 | } |
1130 | } |
1131 | const Variable* var = old->takeOwnershipOfSymbol( |
1132 | std::make_unique<Variable>(intf.fOffset, |
1133 | id.fModifiers, |
1134 | id.fInstanceName.fLength ? id.fInstanceName : id.fTypeName, |
1135 | *type, |
1136 | Variable::kGlobal_Storage)); |
1137 | if (foundRTAdjust) { |
1138 | fRTAdjustInterfaceBlock = var; |
1139 | } |
1140 | if (id.fInstanceName.fLength) { |
1141 | old->addWithoutOwnership(id.fInstanceName, var); |
1142 | } else { |
1143 | for (size_t i = 0; i < fields.size(); i++) { |
1144 | old->add(fields[i].fName, std::make_unique<Field>(intf.fOffset, *var, (int)i)); |
1145 | } |
1146 | } |
1147 | return std::make_unique<InterfaceBlock>(intf.fOffset, |
1148 | var, |
1149 | id.fTypeName, |
1150 | id.fInstanceName, |
1151 | std::move(sizes), |
1152 | symbols); |
1153 | } |
1154 | |
1155 | bool IRGenerator::getConstantInt(const Expression& value, int64_t* out) { |
1156 | switch (value.fKind) { |
1157 | case Expression::kIntLiteral_Kind: |
1158 | *out = static_cast<const IntLiteral&>(value).fValue; |
1159 | return true; |
1160 | case Expression::kVariableReference_Kind: { |
1161 | const Variable& var = static_cast<const VariableReference&>(value).fVariable; |
1162 | return (var.fModifiers.fFlags & Modifiers::kConst_Flag) && |
1163 | var.fInitialValue && |
1164 | this->getConstantInt(*var.fInitialValue, out); |
1165 | } |
1166 | default: |
1167 | return false; |
1168 | } |
1169 | } |
1170 | |
1171 | void IRGenerator::convertEnum(const ASTNode& e) { |
1172 | SkASSERT(e.fKind == ASTNode::Kind::kEnum); |
1173 | int64_t currentValue = 0; |
1174 | Layout layout; |
1175 | ASTNode enumType(e.fNodes, e.fOffset, ASTNode::Kind::kType, |
1176 | ASTNode::TypeData(e.getString(), false, false)); |
1177 | const Type* type = this->convertType(enumType); |
1178 | Modifiers modifiers(layout, Modifiers::kConst_Flag); |
1179 | AutoSymbolTable table(this); |
1180 | for (auto iter = e.begin(); iter != e.end(); ++iter) { |
1181 | const ASTNode& child = *iter; |
1182 | SkASSERT(child.fKind == ASTNode::Kind::kEnumCase); |
1183 | std::unique_ptr<Expression> value; |
1184 | if (child.begin() != child.end()) { |
1185 | value = this->convertExpression(*child.begin()); |
1186 | if (!value) { |
1187 | return; |
1188 | } |
1189 | if (!this->getConstantInt(*value, ¤tValue)) { |
1190 | fErrors.error(value->fOffset, "enum value must be a constant integer" ); |
1191 | return; |
1192 | } |
1193 | } |
1194 | value = std::unique_ptr<Expression>(new IntLiteral(fContext, e.fOffset, currentValue)); |
1195 | ++currentValue; |
1196 | fSymbolTable->add(child.getString(), |
1197 | std::make_unique<Variable>(e.fOffset, modifiers, child.getString(), *type, |
1198 | Variable::kGlobal_Storage, value.get())); |
1199 | fSymbolTable->takeOwnershipOfIRNode(std::move(value)); |
1200 | } |
1201 | fProgramElements->push_back(std::unique_ptr<ProgramElement>( |
1202 | new Enum(e.fOffset, e.getString(), fSymbolTable, fIsBuiltinCode))); |
1203 | } |
1204 | |
1205 | const Type* IRGenerator::convertType(const ASTNode& type) { |
1206 | ASTNode::TypeData td = type.getTypeData(); |
1207 | const Symbol* result = (*fSymbolTable)[td.fName]; |
1208 | if (result && result->fKind == Symbol::kType_Kind) { |
1209 | if (td.fIsNullable) { |
1210 | if (((Type&) *result) == *fContext.fFragmentProcessor_Type) { |
1211 | if (type.begin() != type.end()) { |
1212 | fErrors.error(type.fOffset, "type '" + td.fName + "' may not be used in " |
1213 | "an array" ); |
1214 | } |
1215 | result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>( |
1216 | String(result->fName) + "?" , Type::kNullable_Kind, (const Type&)*result)); |
1217 | } else { |
1218 | fErrors.error(type.fOffset, "type '" + td.fName + "' may not be nullable" ); |
1219 | } |
1220 | } |
1221 | for (const auto& size : type) { |
1222 | String name(result->fName); |
1223 | name += "[" ; |
1224 | if (size) { |
1225 | name += to_string(size.getInt()); |
1226 | } |
1227 | name += "]" ; |
1228 | result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>( |
1229 | name, Type::kArray_Kind, (const Type&)*result, size ? size.getInt() : 0)); |
1230 | } |
1231 | return (const Type*) result; |
1232 | } |
1233 | fErrors.error(type.fOffset, "unknown type '" + td.fName + "'" ); |
1234 | return nullptr; |
1235 | } |
1236 | |
1237 | std::unique_ptr<Expression> IRGenerator::convertExpression(const ASTNode& expr) { |
1238 | switch (expr.fKind) { |
1239 | case ASTNode::Kind::kBinary: |
1240 | return this->convertBinaryExpression(expr); |
1241 | case ASTNode::Kind::kBool: |
1242 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, expr.fOffset, |
1243 | expr.getBool())); |
1244 | case ASTNode::Kind::kCall: |
1245 | return this->convertCallExpression(expr); |
1246 | case ASTNode::Kind::kField: |
1247 | return this->convertFieldExpression(expr); |
1248 | case ASTNode::Kind::kFloat: |
1249 | return std::unique_ptr<Expression>(new FloatLiteral(fContext, expr.fOffset, |
1250 | expr.getFloat())); |
1251 | case ASTNode::Kind::kIdentifier: |
1252 | return this->convertIdentifier(expr); |
1253 | case ASTNode::Kind::kIndex: |
1254 | return this->convertIndexExpression(expr); |
1255 | case ASTNode::Kind::kInt: |
1256 | return std::unique_ptr<Expression>(new IntLiteral(fContext, expr.fOffset, |
1257 | expr.getInt())); |
1258 | case ASTNode::Kind::kNull: |
1259 | return std::unique_ptr<Expression>(new NullLiteral(fContext, expr.fOffset)); |
1260 | case ASTNode::Kind::kPostfix: |
1261 | return this->convertPostfixExpression(expr); |
1262 | case ASTNode::Kind::kPrefix: |
1263 | return this->convertPrefixExpression(expr); |
1264 | case ASTNode::Kind::kTernary: |
1265 | return this->convertTernaryExpression(expr); |
1266 | default: |
1267 | #ifdef SK_DEBUG |
1268 | ABORT("unsupported expression: %s\n" , expr.description().c_str()); |
1269 | #endif |
1270 | return nullptr; |
1271 | } |
1272 | } |
1273 | |
1274 | std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identifier) { |
1275 | SkASSERT(identifier.fKind == ASTNode::Kind::kIdentifier); |
1276 | const Symbol* result = (*fSymbolTable)[identifier.getString()]; |
1277 | if (!result) { |
1278 | fErrors.error(identifier.fOffset, "unknown identifier '" + identifier.getString() + "'" ); |
1279 | return nullptr; |
1280 | } |
1281 | switch (result->fKind) { |
1282 | case Symbol::kFunctionDeclaration_Kind: { |
1283 | std::vector<const FunctionDeclaration*> f = { |
1284 | (const FunctionDeclaration*) result |
1285 | }; |
1286 | return std::make_unique<FunctionReference>(fContext, identifier.fOffset, f); |
1287 | } |
1288 | case Symbol::kUnresolvedFunction_Kind: { |
1289 | const UnresolvedFunction* f = (const UnresolvedFunction*) result; |
1290 | return std::make_unique<FunctionReference>(fContext, identifier.fOffset, f->fFunctions); |
1291 | } |
1292 | case Symbol::kVariable_Kind: { |
1293 | const Variable* var = (const Variable*) result; |
1294 | switch (var->fModifiers.fLayout.fBuiltin) { |
1295 | case SK_WIDTH_BUILTIN: |
1296 | fInputs.fRTWidth = true; |
1297 | break; |
1298 | case SK_HEIGHT_BUILTIN: |
1299 | fInputs.fRTHeight = true; |
1300 | break; |
1301 | #ifndef SKSL_STANDALONE |
1302 | case SK_FRAGCOORD_BUILTIN: |
1303 | fInputs.fFlipY = true; |
1304 | if (fSettings->fFlipY && |
1305 | (!fSettings->fCaps || |
1306 | !fSettings->fCaps->fragCoordConventionsExtensionString())) { |
1307 | fInputs.fRTHeight = true; |
1308 | } |
1309 | #endif |
1310 | } |
1311 | if (fKind == Program::kFragmentProcessor_Kind && |
1312 | (var->fModifiers.fFlags & Modifiers::kIn_Flag) && |
1313 | !(var->fModifiers.fFlags & Modifiers::kUniform_Flag) && |
1314 | !var->fModifiers.fLayout.fKey && |
1315 | var->fModifiers.fLayout.fBuiltin == -1 && |
1316 | var->fType.nonnullable() != *fContext.fFragmentProcessor_Type && |
1317 | var->fType.kind() != Type::kSampler_Kind) { |
1318 | bool valid = false; |
1319 | for (const auto& decl : fFile->root()) { |
1320 | if (decl.fKind == ASTNode::Kind::kSection) { |
1321 | ASTNode::SectionData section = decl.getSectionData(); |
1322 | if (section.fName == "setData" ) { |
1323 | valid = true; |
1324 | break; |
1325 | } |
1326 | } |
1327 | } |
1328 | if (!valid) { |
1329 | fErrors.error(identifier.fOffset, "'in' variable must be either 'uniform' or " |
1330 | "'layout(key)', or there must be a custom " |
1331 | "@setData function" ); |
1332 | } |
1333 | } |
1334 | // default to kRead_RefKind; this will be corrected later if the variable is written to |
1335 | return std::make_unique<VariableReference>(identifier.fOffset, |
1336 | *var, |
1337 | VariableReference::kRead_RefKind); |
1338 | } |
1339 | case Symbol::kField_Kind: { |
1340 | const Field* field = (const Field*) result; |
1341 | VariableReference* base = new VariableReference(identifier.fOffset, field->fOwner, |
1342 | VariableReference::kRead_RefKind); |
1343 | return std::unique_ptr<Expression>(new FieldAccess( |
1344 | std::unique_ptr<Expression>(base), |
1345 | field->fFieldIndex, |
1346 | FieldAccess::kAnonymousInterfaceBlock_OwnerKind)); |
1347 | } |
1348 | case Symbol::kType_Kind: { |
1349 | const Type* t = (const Type*) result; |
1350 | return std::make_unique<TypeReference>(fContext, identifier.fOffset, *t); |
1351 | } |
1352 | case Symbol::kExternal_Kind: { |
1353 | ExternalValue* r = (ExternalValue*) result; |
1354 | return std::make_unique<ExternalValueReference>(identifier.fOffset, r); |
1355 | } |
1356 | default: |
1357 | ABORT("unsupported symbol type %d\n" , result->fKind); |
1358 | } |
1359 | } |
1360 | |
1361 | std::unique_ptr<Section> IRGenerator::convertSection(const ASTNode& s) { |
1362 | ASTNode::SectionData section = s.getSectionData(); |
1363 | return std::make_unique<Section>(s.fOffset, section.fName, section.fArgument, |
1364 | section.fText); |
1365 | } |
1366 | |
1367 | |
1368 | std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr, |
1369 | const Type& type) { |
1370 | if (!expr) { |
1371 | return nullptr; |
1372 | } |
1373 | if (expr->fType == type) { |
1374 | return expr; |
1375 | } |
1376 | this->checkValid(*expr); |
1377 | if (expr->fType == *fContext.fInvalid_Type) { |
1378 | return nullptr; |
1379 | } |
1380 | if (expr->coercionCost(type) == INT_MAX) { |
1381 | fErrors.error(expr->fOffset, "expected '" + type.displayName() + "', but found '" + |
1382 | expr->fType.displayName() + "'" ); |
1383 | return nullptr; |
1384 | } |
1385 | if (type.kind() == Type::kScalar_Kind) { |
1386 | std::vector<std::unique_ptr<Expression>> args; |
1387 | args.push_back(std::move(expr)); |
1388 | std::unique_ptr<Expression> ctor; |
1389 | if (type == *fContext.fFloatLiteral_Type) { |
1390 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1391 | "float" )); |
1392 | } else if (type == *fContext.fIntLiteral_Type) { |
1393 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1394 | "int" )); |
1395 | } else { |
1396 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1397 | type.fName)); |
1398 | } |
1399 | if (!ctor) { |
1400 | printf("error, null identifier: %s\n" , String(type.fName).c_str()); |
1401 | } |
1402 | SkASSERT(ctor); |
1403 | return this->call(-1, std::move(ctor), std::move(args)); |
1404 | } |
1405 | if (expr->fKind == Expression::kNullLiteral_Kind) { |
1406 | SkASSERT(type.kind() == Type::kNullable_Kind); |
1407 | return std::unique_ptr<Expression>(new NullLiteral(expr->fOffset, type)); |
1408 | } |
1409 | std::vector<std::unique_ptr<Expression>> args; |
1410 | args.push_back(std::move(expr)); |
1411 | return std::unique_ptr<Expression>(new Constructor(-1, type, std::move(args))); |
1412 | } |
1413 | |
1414 | static bool is_matrix_multiply(const Type& left, const Type& right) { |
1415 | if (left.kind() == Type::kMatrix_Kind) { |
1416 | return right.kind() == Type::kMatrix_Kind || right.kind() == Type::kVector_Kind; |
1417 | } |
1418 | return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind; |
1419 | } |
1420 | |
1421 | /** |
1422 | * Determines the operand and result types of a binary expression. Returns true if the expression is |
1423 | * legal, false otherwise. If false, the values of the out parameters are undefined. |
1424 | */ |
1425 | static bool determine_binary_type(const Context& context, |
1426 | Token::Kind op, |
1427 | const Type& left, |
1428 | const Type& right, |
1429 | const Type** outLeftType, |
1430 | const Type** outRightType, |
1431 | const Type** outResultType, |
1432 | bool tryFlipped) { |
1433 | bool isLogical; |
1434 | bool validMatrixOrVectorOp; |
1435 | switch (op) { |
1436 | case Token::Kind::TK_EQ: |
1437 | *outLeftType = &left; |
1438 | *outRightType = &left; |
1439 | *outResultType = &left; |
1440 | return right.canCoerceTo(left); |
1441 | case Token::Kind::TK_EQEQ: // fall through |
1442 | case Token::Kind::TK_NEQ: |
1443 | if (right.canCoerceTo(left)) { |
1444 | *outLeftType = &left; |
1445 | *outRightType = &left; |
1446 | *outResultType = context.fBool_Type.get(); |
1447 | return true; |
1448 | } if (left.canCoerceTo(right)) { |
1449 | *outLeftType = &right; |
1450 | *outRightType = &right; |
1451 | *outResultType = context.fBool_Type.get(); |
1452 | return true; |
1453 | } |
1454 | return false; |
1455 | case Token::Kind::TK_LT: // fall through |
1456 | case Token::Kind::TK_GT: // fall through |
1457 | case Token::Kind::TK_LTEQ: // fall through |
1458 | case Token::Kind::TK_GTEQ: |
1459 | isLogical = true; |
1460 | validMatrixOrVectorOp = false; |
1461 | break; |
1462 | case Token::Kind::TK_LOGICALOR: // fall through |
1463 | case Token::Kind::TK_LOGICALAND: // fall through |
1464 | case Token::Kind::TK_LOGICALXOR: // fall through |
1465 | case Token::Kind::TK_LOGICALOREQ: // fall through |
1466 | case Token::Kind::TK_LOGICALANDEQ: // fall through |
1467 | case Token::Kind::TK_LOGICALXOREQ: |
1468 | *outLeftType = context.fBool_Type.get(); |
1469 | *outRightType = context.fBool_Type.get(); |
1470 | *outResultType = context.fBool_Type.get(); |
1471 | return left.canCoerceTo(*context.fBool_Type) && |
1472 | right.canCoerceTo(*context.fBool_Type); |
1473 | case Token::Kind::TK_STAREQ: |
1474 | if (left.kind() == Type::kScalar_Kind) { |
1475 | *outLeftType = &left; |
1476 | *outRightType = &left; |
1477 | *outResultType = &left; |
1478 | return right.canCoerceTo(left); |
1479 | } |
1480 | [[fallthrough]]; |
1481 | case Token::Kind::TK_STAR: |
1482 | if (is_matrix_multiply(left, right)) { |
1483 | // determine final component type |
1484 | if (determine_binary_type(context, Token::Kind::TK_STAR, left.componentType(), |
1485 | right.componentType(), outLeftType, outRightType, |
1486 | outResultType, false)) { |
1487 | *outLeftType = &(*outResultType)->toCompound(context, left.columns(), |
1488 | left.rows()); |
1489 | *outRightType = &(*outResultType)->toCompound(context, right.columns(), |
1490 | right.rows()); |
1491 | int leftColumns = left.columns(); |
1492 | int leftRows = left.rows(); |
1493 | int rightColumns; |
1494 | int rightRows; |
1495 | if (right.kind() == Type::kVector_Kind) { |
1496 | // matrix * vector treats the vector as a column vector, so we need to |
1497 | // transpose it |
1498 | rightColumns = right.rows(); |
1499 | rightRows = right.columns(); |
1500 | SkASSERT(rightColumns == 1); |
1501 | } else { |
1502 | rightColumns = right.columns(); |
1503 | rightRows = right.rows(); |
1504 | } |
1505 | if (rightColumns > 1) { |
1506 | *outResultType = &(*outResultType)->toCompound(context, rightColumns, |
1507 | leftRows); |
1508 | } else { |
1509 | // result was a column vector, transpose it back to a row |
1510 | *outResultType = &(*outResultType)->toCompound(context, leftRows, |
1511 | rightColumns); |
1512 | } |
1513 | return leftColumns == rightRows; |
1514 | } else { |
1515 | return false; |
1516 | } |
1517 | } |
1518 | isLogical = false; |
1519 | validMatrixOrVectorOp = true; |
1520 | break; |
1521 | case Token::Kind::TK_PLUSEQ: |
1522 | case Token::Kind::TK_MINUSEQ: |
1523 | case Token::Kind::TK_SLASHEQ: |
1524 | case Token::Kind::TK_PERCENTEQ: |
1525 | case Token::Kind::TK_SHLEQ: |
1526 | case Token::Kind::TK_SHREQ: |
1527 | if (left.kind() == Type::kScalar_Kind) { |
1528 | *outLeftType = &left; |
1529 | *outRightType = &left; |
1530 | *outResultType = &left; |
1531 | return right.canCoerceTo(left); |
1532 | } |
1533 | [[fallthrough]]; |
1534 | case Token::Kind::TK_PLUS: // fall through |
1535 | case Token::Kind::TK_MINUS: // fall through |
1536 | case Token::Kind::TK_SLASH: // fall through |
1537 | isLogical = false; |
1538 | validMatrixOrVectorOp = true; |
1539 | break; |
1540 | case Token::Kind::TK_COMMA: |
1541 | *outLeftType = &left; |
1542 | *outRightType = &right; |
1543 | *outResultType = &right; |
1544 | return true; |
1545 | default: |
1546 | isLogical = false; |
1547 | validMatrixOrVectorOp = false; |
1548 | } |
1549 | bool isVectorOrMatrix = left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind; |
1550 | if (left.kind() == Type::kScalar_Kind && right.kind() == Type::kScalar_Kind && |
1551 | right.canCoerceTo(left)) { |
1552 | if (left.priority() > right.priority()) { |
1553 | *outLeftType = &left; |
1554 | *outRightType = &left; |
1555 | } else { |
1556 | *outLeftType = &right; |
1557 | *outRightType = &right; |
1558 | } |
1559 | if (isLogical) { |
1560 | *outResultType = context.fBool_Type.get(); |
1561 | } else { |
1562 | *outResultType = &left; |
1563 | } |
1564 | return true; |
1565 | } |
1566 | if (right.canCoerceTo(left) && isVectorOrMatrix && validMatrixOrVectorOp) { |
1567 | *outLeftType = &left; |
1568 | *outRightType = &left; |
1569 | if (isLogical) { |
1570 | *outResultType = context.fBool_Type.get(); |
1571 | } else { |
1572 | *outResultType = &left; |
1573 | } |
1574 | return true; |
1575 | } |
1576 | if ((left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind) && |
1577 | (right.kind() == Type::kScalar_Kind)) { |
1578 | if (determine_binary_type(context, op, left.componentType(), right, outLeftType, |
1579 | outRightType, outResultType, false)) { |
1580 | *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows()); |
1581 | if (!isLogical) { |
1582 | *outResultType = &(*outResultType)->toCompound(context, left.columns(), |
1583 | left.rows()); |
1584 | } |
1585 | return true; |
1586 | } |
1587 | return false; |
1588 | } |
1589 | if (tryFlipped) { |
1590 | return determine_binary_type(context, op, right, left, outRightType, outLeftType, |
1591 | outResultType, false); |
1592 | } |
1593 | return false; |
1594 | } |
1595 | |
1596 | static std::unique_ptr<Expression> short_circuit_boolean(const Context& context, |
1597 | const Expression& left, |
1598 | Token::Kind op, |
1599 | const Expression& right) { |
1600 | SkASSERT(left.fKind == Expression::kBoolLiteral_Kind); |
1601 | bool leftVal = ((BoolLiteral&) left).fValue; |
1602 | if (op == Token::Kind::TK_LOGICALAND) { |
1603 | // (true && expr) -> (expr) and (false && expr) -> (false) |
1604 | return leftVal ? right.clone() |
1605 | : std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, false)); |
1606 | } else if (op == Token::Kind::TK_LOGICALOR) { |
1607 | // (true || expr) -> (true) and (false || expr) -> (expr) |
1608 | return leftVal ? std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, true)) |
1609 | : right.clone(); |
1610 | } else if (op == Token::Kind::TK_LOGICALXOR) { |
1611 | // (true ^^ expr) -> !(expr) and (false ^^ expr) -> (expr) |
1612 | return leftVal ? std::unique_ptr<Expression>(new PrefixExpression( |
1613 | Token::Kind::TK_LOGICALNOT, |
1614 | right.clone())) |
1615 | : right.clone(); |
1616 | } else { |
1617 | return nullptr; |
1618 | } |
1619 | } |
1620 | |
1621 | std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left, |
1622 | Token::Kind op, |
1623 | const Expression& right) const { |
1624 | // If the left side is a constant boolean literal, the right side does not need to be constant |
1625 | // for short circuit optimizations to allow the constant to be folded. |
1626 | if (left.fKind == Expression::kBoolLiteral_Kind && !right.isCompileTimeConstant()) { |
1627 | return short_circuit_boolean(fContext, left, op, right); |
1628 | } else if (right.fKind == Expression::kBoolLiteral_Kind && !left.isCompileTimeConstant()) { |
1629 | // There aren't side effects in SKSL within expressions, so (left OP right) is equivalent to |
1630 | // (right OP left) for short-circuit optimizations |
1631 | return short_circuit_boolean(fContext, right, op, left); |
1632 | } |
1633 | |
1634 | // Other than the short-circuit cases above, constant folding requires both sides to be constant |
1635 | if (!left.isCompileTimeConstant() || !right.isCompileTimeConstant()) { |
1636 | return nullptr; |
1637 | } |
1638 | // Note that we expressly do not worry about precision and overflow here -- we use the maximum |
1639 | // precision to calculate the results and hope the result makes sense. The plan is to move the |
1640 | // Skia caps into SkSL, so we have access to all of them including the precisions of the various |
1641 | // types, which will let us be more intelligent about this. |
1642 | if (left.fKind == Expression::kBoolLiteral_Kind && |
1643 | right.fKind == Expression::kBoolLiteral_Kind) { |
1644 | bool leftVal = ((BoolLiteral&) left).fValue; |
1645 | bool rightVal = ((BoolLiteral&) right).fValue; |
1646 | bool result; |
1647 | switch (op) { |
1648 | case Token::Kind::TK_LOGICALAND: result = leftVal && rightVal; break; |
1649 | case Token::Kind::TK_LOGICALOR: result = leftVal || rightVal; break; |
1650 | case Token::Kind::TK_LOGICALXOR: result = leftVal ^ rightVal; break; |
1651 | default: return nullptr; |
1652 | } |
1653 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, left.fOffset, result)); |
1654 | } |
1655 | #define RESULT(t, op) std::make_unique<t ## Literal>(fContext, left.fOffset, \ |
1656 | leftVal op rightVal) |
1657 | #define URESULT(t, op) std::make_unique<t ## Literal>(fContext, left.fOffset, \ |
1658 | (uint32_t) leftVal op \ |
1659 | (uint32_t) rightVal) |
1660 | if (left.fKind == Expression::kIntLiteral_Kind && right.fKind == Expression::kIntLiteral_Kind) { |
1661 | int64_t leftVal = ((IntLiteral&) left).fValue; |
1662 | int64_t rightVal = ((IntLiteral&) right).fValue; |
1663 | switch (op) { |
1664 | case Token::Kind::TK_PLUS: return URESULT(Int, +); |
1665 | case Token::Kind::TK_MINUS: return URESULT(Int, -); |
1666 | case Token::Kind::TK_STAR: return URESULT(Int, *); |
1667 | case Token::Kind::TK_SLASH: |
1668 | if (leftVal == std::numeric_limits<int64_t>::min() && rightVal == -1) { |
1669 | fErrors.error(right.fOffset, "arithmetic overflow" ); |
1670 | return nullptr; |
1671 | } |
1672 | if (!rightVal) { |
1673 | fErrors.error(right.fOffset, "division by zero" ); |
1674 | return nullptr; |
1675 | } |
1676 | return RESULT(Int, /); |
1677 | case Token::Kind::TK_PERCENT: |
1678 | if (leftVal == std::numeric_limits<int64_t>::min() && rightVal == -1) { |
1679 | fErrors.error(right.fOffset, "arithmetic overflow" ); |
1680 | return nullptr; |
1681 | } |
1682 | if (!rightVal) { |
1683 | fErrors.error(right.fOffset, "division by zero" ); |
1684 | return nullptr; |
1685 | } |
1686 | return RESULT(Int, %); |
1687 | case Token::Kind::TK_BITWISEAND: return RESULT(Int, &); |
1688 | case Token::Kind::TK_BITWISEOR: return RESULT(Int, |); |
1689 | case Token::Kind::TK_BITWISEXOR: return RESULT(Int, ^); |
1690 | case Token::Kind::TK_EQEQ: return RESULT(Bool, ==); |
1691 | case Token::Kind::TK_NEQ: return RESULT(Bool, !=); |
1692 | case Token::Kind::TK_GT: return RESULT(Bool, >); |
1693 | case Token::Kind::TK_GTEQ: return RESULT(Bool, >=); |
1694 | case Token::Kind::TK_LT: return RESULT(Bool, <); |
1695 | case Token::Kind::TK_LTEQ: return RESULT(Bool, <=); |
1696 | case Token::Kind::TK_SHL: |
1697 | if (rightVal >= 0 && rightVal <= 31) { |
1698 | return URESULT(Int, <<); |
1699 | } |
1700 | fErrors.error(right.fOffset, "shift value out of range" ); |
1701 | return nullptr; |
1702 | case Token::Kind::TK_SHR: |
1703 | if (rightVal >= 0 && rightVal <= 31) { |
1704 | return URESULT(Int, >>); |
1705 | } |
1706 | fErrors.error(right.fOffset, "shift value out of range" ); |
1707 | return nullptr; |
1708 | |
1709 | default: |
1710 | return nullptr; |
1711 | } |
1712 | } |
1713 | if (left.fKind == Expression::kFloatLiteral_Kind && |
1714 | right.fKind == Expression::kFloatLiteral_Kind) { |
1715 | double leftVal = ((FloatLiteral&) left).fValue; |
1716 | double rightVal = ((FloatLiteral&) right).fValue; |
1717 | switch (op) { |
1718 | case Token::Kind::TK_PLUS: return RESULT(Float, +); |
1719 | case Token::Kind::TK_MINUS: return RESULT(Float, -); |
1720 | case Token::Kind::TK_STAR: return RESULT(Float, *); |
1721 | case Token::Kind::TK_SLASH: |
1722 | if (rightVal) { |
1723 | return RESULT(Float, /); |
1724 | } |
1725 | fErrors.error(right.fOffset, "division by zero" ); |
1726 | return nullptr; |
1727 | case Token::Kind::TK_EQEQ: return RESULT(Bool, ==); |
1728 | case Token::Kind::TK_NEQ: return RESULT(Bool, !=); |
1729 | case Token::Kind::TK_GT: return RESULT(Bool, >); |
1730 | case Token::Kind::TK_GTEQ: return RESULT(Bool, >=); |
1731 | case Token::Kind::TK_LT: return RESULT(Bool, <); |
1732 | case Token::Kind::TK_LTEQ: return RESULT(Bool, <=); |
1733 | default: return nullptr; |
1734 | } |
1735 | } |
1736 | if (left.fType.kind() == Type::kVector_Kind && left.fType.componentType().isFloat() && |
1737 | left.fType == right.fType) { |
1738 | std::vector<std::unique_ptr<Expression>> args; |
1739 | #define RETURN_VEC_COMPONENTWISE_RESULT(op) \ |
1740 | for (int i = 0; i < left.fType.columns(); i++) { \ |
1741 | float value = left.getFVecComponent(i) op \ |
1742 | right.getFVecComponent(i); \ |
1743 | args.emplace_back(new FloatLiteral(fContext, -1, value)); \ |
1744 | } \ |
1745 | return std::unique_ptr<Expression>(new Constructor(-1, left.fType, \ |
1746 | std::move(args))) |
1747 | switch (op) { |
1748 | case Token::Kind::TK_EQEQ: |
1749 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1750 | left.compareConstant(fContext, right))); |
1751 | case Token::Kind::TK_NEQ: |
1752 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1753 | !left.compareConstant(fContext, right))); |
1754 | case Token::Kind::TK_PLUS: RETURN_VEC_COMPONENTWISE_RESULT(+); |
1755 | case Token::Kind::TK_MINUS: RETURN_VEC_COMPONENTWISE_RESULT(-); |
1756 | case Token::Kind::TK_STAR: RETURN_VEC_COMPONENTWISE_RESULT(*); |
1757 | case Token::Kind::TK_SLASH: |
1758 | for (int i = 0; i < left.fType.columns(); i++) { |
1759 | SKSL_FLOAT rvalue = right.getFVecComponent(i); |
1760 | if (rvalue == 0.0) { |
1761 | fErrors.error(right.fOffset, "division by zero" ); |
1762 | return nullptr; |
1763 | } |
1764 | float value = left.getFVecComponent(i) / rvalue; |
1765 | args.emplace_back(new FloatLiteral(fContext, -1, value)); |
1766 | } |
1767 | return std::unique_ptr<Expression>(new Constructor(-1, left.fType, |
1768 | std::move(args))); |
1769 | default: return nullptr; |
1770 | } |
1771 | } |
1772 | if (left.fType.kind() == Type::kMatrix_Kind && |
1773 | right.fType.kind() == Type::kMatrix_Kind && |
1774 | left.fKind == right.fKind) { |
1775 | switch (op) { |
1776 | case Token::Kind::TK_EQEQ: |
1777 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1778 | left.compareConstant(fContext, right))); |
1779 | case Token::Kind::TK_NEQ: |
1780 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1781 | !left.compareConstant(fContext, right))); |
1782 | default: |
1783 | return nullptr; |
1784 | } |
1785 | } |
1786 | #undef RESULT |
1787 | return nullptr; |
1788 | } |
1789 | |
1790 | std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode& expression) { |
1791 | SkASSERT(expression.fKind == ASTNode::Kind::kBinary); |
1792 | auto iter = expression.begin(); |
1793 | std::unique_ptr<Expression> left = this->convertExpression(*(iter++)); |
1794 | if (!left) { |
1795 | return nullptr; |
1796 | } |
1797 | Token::Kind op = expression.getToken().fKind; |
1798 | std::unique_ptr<Expression> right; |
1799 | { |
1800 | // Can't inline the right side of a short-circuiting boolean, because our inlining |
1801 | // approach runs things out of order. |
1802 | AutoDisableInline disableInline(this, /*canInline=*/(op != Token::Kind::TK_LOGICALAND && |
1803 | op != Token::Kind::TK_LOGICALOR)); |
1804 | right = this->convertExpression(*(iter++)); |
1805 | } |
1806 | if (!right) { |
1807 | return nullptr; |
1808 | } |
1809 | const Type* leftType; |
1810 | const Type* rightType; |
1811 | const Type* resultType; |
1812 | const Type* rawLeftType; |
1813 | if (left->fKind == Expression::kIntLiteral_Kind && right->fType.isInteger()) { |
1814 | rawLeftType = &right->fType; |
1815 | } else { |
1816 | rawLeftType = &left->fType; |
1817 | } |
1818 | const Type* rawRightType; |
1819 | if (right->fKind == Expression::kIntLiteral_Kind && left->fType.isInteger()) { |
1820 | rawRightType = &left->fType; |
1821 | } else { |
1822 | rawRightType = &right->fType; |
1823 | } |
1824 | if (!determine_binary_type(fContext, op, *rawLeftType, *rawRightType, &leftType, &rightType, |
1825 | &resultType, !Compiler::IsAssignment(op))) { |
1826 | fErrors.error(expression.fOffset, String("type mismatch: '" ) + |
1827 | Compiler::OperatorName(expression.getToken().fKind) + |
1828 | "' cannot operate on '" + left->fType.displayName() + |
1829 | "', '" + right->fType.displayName() + "'" ); |
1830 | return nullptr; |
1831 | } |
1832 | if (Compiler::IsAssignment(op)) { |
1833 | if (!this->setRefKind(*left, op != Token::Kind::TK_EQ |
1834 | ? VariableReference::kReadWrite_RefKind |
1835 | : VariableReference::kWrite_RefKind)) { |
1836 | return nullptr; |
1837 | } |
1838 | } |
1839 | left = this->coerce(std::move(left), *leftType); |
1840 | right = this->coerce(std::move(right), *rightType); |
1841 | if (!left || !right) { |
1842 | return nullptr; |
1843 | } |
1844 | std::unique_ptr<Expression> result = this->constantFold(*left.get(), op, *right.get()); |
1845 | if (!result) { |
1846 | result = std::make_unique<BinaryExpression>(expression.fOffset, std::move(left), op, |
1847 | std::move(right), *resultType); |
1848 | } |
1849 | return result; |
1850 | } |
1851 | |
1852 | std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(const ASTNode& node) { |
1853 | SkASSERT(node.fKind == ASTNode::Kind::kTernary); |
1854 | auto iter = node.begin(); |
1855 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
1856 | *fContext.fBool_Type); |
1857 | if (!test) { |
1858 | return nullptr; |
1859 | } |
1860 | std::unique_ptr<Expression> ifTrue = this->convertExpression(*(iter++)); |
1861 | if (!ifTrue) { |
1862 | return nullptr; |
1863 | } |
1864 | std::unique_ptr<Expression> ifFalse = this->convertExpression(*(iter++)); |
1865 | if (!ifFalse) { |
1866 | return nullptr; |
1867 | } |
1868 | const Type* trueType; |
1869 | const Type* falseType; |
1870 | const Type* resultType; |
1871 | if (!determine_binary_type(fContext, Token::Kind::TK_EQEQ, ifTrue->fType, ifFalse->fType, |
1872 | &trueType, &falseType, &resultType, true) || trueType != falseType) { |
1873 | fErrors.error(node.fOffset, "ternary operator result mismatch: '" + |
1874 | ifTrue->fType.displayName() + "', '" + |
1875 | ifFalse->fType.displayName() + "'" ); |
1876 | return nullptr; |
1877 | } |
1878 | if (trueType->nonnullable() == *fContext.fFragmentProcessor_Type) { |
1879 | fErrors.error(node.fOffset, |
1880 | "ternary expression of type '" + trueType->displayName() + "' not allowed" ); |
1881 | return nullptr; |
1882 | } |
1883 | ifTrue = this->coerce(std::move(ifTrue), *trueType); |
1884 | if (!ifTrue) { |
1885 | return nullptr; |
1886 | } |
1887 | ifFalse = this->coerce(std::move(ifFalse), *falseType); |
1888 | if (!ifFalse) { |
1889 | return nullptr; |
1890 | } |
1891 | if (test->fKind == Expression::kBoolLiteral_Kind) { |
1892 | // static boolean test, just return one of the branches |
1893 | if (((BoolLiteral&) *test).fValue) { |
1894 | return ifTrue; |
1895 | } else { |
1896 | return ifFalse; |
1897 | } |
1898 | } |
1899 | return std::unique_ptr<Expression>(new TernaryExpression(node.fOffset, |
1900 | std::move(test), |
1901 | std::move(ifTrue), |
1902 | std::move(ifFalse))); |
1903 | } |
1904 | |
1905 | std::unique_ptr<Expression> IRGenerator::inlineExpression( |
1906 | int offset, |
1907 | std::unordered_map<const Variable*, const Variable*>* varMap, |
1908 | const Expression& expression) { |
1909 | auto expr = [&](const std::unique_ptr<Expression>& e) -> std::unique_ptr<Expression> { |
1910 | if (e) { |
1911 | return this->inlineExpression(offset, varMap, *e); |
1912 | } |
1913 | return nullptr; |
1914 | }; |
1915 | switch (expression.fKind) { |
1916 | case Expression::kBinary_Kind: { |
1917 | const BinaryExpression& b = (const BinaryExpression&) expression; |
1918 | return std::unique_ptr<Expression>(new BinaryExpression(offset, |
1919 | expr(b.fLeft), |
1920 | b.fOperator, |
1921 | expr(b.fRight), |
1922 | b.fType)); |
1923 | } |
1924 | case Expression::kBoolLiteral_Kind: |
1925 | case Expression::kIntLiteral_Kind: |
1926 | case Expression::kFloatLiteral_Kind: |
1927 | case Expression::kNullLiteral_Kind: |
1928 | return expression.clone(); |
1929 | case Expression::kConstructor_Kind: { |
1930 | const Constructor& c = (const Constructor&) expression; |
1931 | std::vector<std::unique_ptr<Expression>> args; |
1932 | for (const auto& arg : c.fArguments) { |
1933 | args.push_back(expr(arg)); |
1934 | } |
1935 | return std::unique_ptr<Expression>(new Constructor(offset, c.fType, std::move(args))); |
1936 | } |
1937 | case Expression::kExternalFunctionCall_Kind: { |
1938 | const ExternalFunctionCall& e = (const ExternalFunctionCall&) expression; |
1939 | std::vector<std::unique_ptr<Expression>> args; |
1940 | for (const auto& arg : e.fArguments) { |
1941 | args.push_back(expr(arg)); |
1942 | } |
1943 | return std::unique_ptr<Expression>(new ExternalFunctionCall(offset, e.fType, |
1944 | e.fFunction, |
1945 | std::move(args))); |
1946 | } |
1947 | case Expression::kExternalValue_Kind: |
1948 | return expression.clone(); |
1949 | case Expression::kFieldAccess_Kind: { |
1950 | const FieldAccess& f = (const FieldAccess&) expression; |
1951 | return std::unique_ptr<Expression>(new FieldAccess(expr(f.fBase), f.fFieldIndex, |
1952 | f.fOwnerKind)); |
1953 | } |
1954 | case Expression::kFunctionCall_Kind: { |
1955 | const FunctionCall& c = (const FunctionCall&) expression; |
1956 | std::vector<std::unique_ptr<Expression>> args; |
1957 | for (const auto& arg : c.fArguments) { |
1958 | args.push_back(expr(arg)); |
1959 | } |
1960 | return std::unique_ptr<Expression>(new FunctionCall(offset, c.fType, c.fFunction, |
1961 | std::move(args))); |
1962 | } |
1963 | case Expression::kIndex_Kind: { |
1964 | const IndexExpression& idx = (const IndexExpression&) expression; |
1965 | return std::unique_ptr<Expression>(new IndexExpression(fContext, expr(idx.fBase), |
1966 | expr(idx.fIndex))); |
1967 | } |
1968 | case Expression::kPrefix_Kind: { |
1969 | const PrefixExpression& p = (const PrefixExpression&) expression; |
1970 | return std::unique_ptr<Expression>(new PrefixExpression(p.fOperator, expr(p.fOperand))); |
1971 | } |
1972 | case Expression::kPostfix_Kind: { |
1973 | const PostfixExpression& p = (const PostfixExpression&) expression; |
1974 | return std::unique_ptr<Expression>(new PostfixExpression(expr(p.fOperand), |
1975 | p.fOperator)); |
1976 | } |
1977 | case Expression::kSetting_Kind: |
1978 | return expression.clone(); |
1979 | case Expression::kSwizzle_Kind: { |
1980 | const Swizzle& s = (const Swizzle&) expression; |
1981 | return std::unique_ptr<Expression>(new Swizzle(fContext, expr(s.fBase), s.fComponents)); |
1982 | } |
1983 | case Expression::kTernary_Kind: { |
1984 | const TernaryExpression& t = (const TernaryExpression&) expression; |
1985 | return std::unique_ptr<Expression>(new TernaryExpression(offset, expr(t.fTest), |
1986 | expr(t.fIfTrue), |
1987 | expr(t.fIfFalse))); |
1988 | } |
1989 | case Expression::kVariableReference_Kind: { |
1990 | const VariableReference& v = (const VariableReference&) expression; |
1991 | auto found = varMap->find(&v.fVariable); |
1992 | if (found != varMap->end()) { |
1993 | return std::unique_ptr<Expression>(new VariableReference(offset, |
1994 | *found->second, |
1995 | v.fRefKind)); |
1996 | } |
1997 | return v.clone(); |
1998 | } |
1999 | default: |
2000 | SkASSERT(false); |
2001 | return nullptr; |
2002 | } |
2003 | } |
2004 | |
2005 | static const Type* copy_if_needed(const Type* src, SymbolTable& symbolTable) { |
2006 | if (src->kind() == Type::kArray_Kind) { |
2007 | return symbolTable.takeOwnershipOfSymbol(std::make_unique<Type>(*src)); |
2008 | } |
2009 | return src; |
2010 | } |
2011 | |
2012 | std::unique_ptr<Statement> IRGenerator::inlineStatement( |
2013 | int offset, |
2014 | std::unordered_map<const Variable*, const Variable*>* varMap, |
2015 | const Variable* returnVar, |
2016 | bool haveEarlyReturns, |
2017 | const Statement& statement) { |
2018 | auto stmt = [&](const std::unique_ptr<Statement>& s) -> std::unique_ptr<Statement> { |
2019 | if (s) { |
2020 | return this->inlineStatement(offset, varMap, returnVar, haveEarlyReturns, *s); |
2021 | } |
2022 | return nullptr; |
2023 | }; |
2024 | auto stmts = [&](const std::vector<std::unique_ptr<Statement>>& ss) { |
2025 | std::vector<std::unique_ptr<Statement>> result; |
2026 | for (const auto& s : ss) { |
2027 | result.push_back(stmt(s)); |
2028 | } |
2029 | return result; |
2030 | }; |
2031 | auto expr = [&](const std::unique_ptr<Expression>& e) -> std::unique_ptr<Expression> { |
2032 | if (e) { |
2033 | return this->inlineExpression(offset, varMap, *e); |
2034 | } |
2035 | return nullptr; |
2036 | }; |
2037 | switch (statement.fKind) { |
2038 | case Statement::kBlock_Kind: { |
2039 | const Block& b = static_cast<const Block&>(statement); |
2040 | return std::make_unique<Block>(offset, stmts(b.fStatements), b.fSymbols, b.fIsScope); |
2041 | } |
2042 | |
2043 | case Statement::kBreak_Kind: |
2044 | case Statement::kContinue_Kind: |
2045 | case Statement::kDiscard_Kind: |
2046 | return statement.clone(); |
2047 | |
2048 | case Statement::kDo_Kind: { |
2049 | const DoStatement& d = static_cast<const DoStatement&>(statement); |
2050 | return std::make_unique<DoStatement>(offset, stmt(d.fStatement), expr(d.fTest)); |
2051 | } |
2052 | case Statement::kExpression_Kind: { |
2053 | const ExpressionStatement& e = static_cast<const ExpressionStatement&>(statement); |
2054 | return std::make_unique<ExpressionStatement>(expr(e.fExpression)); |
2055 | } |
2056 | case Statement::kFor_Kind: { |
2057 | const ForStatement& f = static_cast<const ForStatement&>(statement); |
2058 | // need to ensure initializer is evaluated first so that we've already remapped its |
2059 | // declarations by the time we evaluate test & next |
2060 | std::unique_ptr<Statement> initializer = stmt(f.fInitializer); |
2061 | return std::make_unique<ForStatement>(offset, std::move(initializer), expr(f.fTest), |
2062 | expr(f.fNext), stmt(f.fStatement), f.fSymbols); |
2063 | } |
2064 | case Statement::kIf_Kind: { |
2065 | const IfStatement& i = static_cast<const IfStatement&>(statement); |
2066 | return std::make_unique<IfStatement>(offset, i.fIsStatic, expr(i.fTest), |
2067 | stmt(i.fIfTrue), stmt(i.fIfFalse)); |
2068 | } |
2069 | case Statement::kNop_Kind: |
2070 | return statement.clone(); |
2071 | case Statement::kReturn_Kind: { |
2072 | const ReturnStatement& r = static_cast<const ReturnStatement&>(statement); |
2073 | if (r.fExpression) { |
2074 | auto assignment = std::make_unique<ExpressionStatement>( |
2075 | std::make_unique<BinaryExpression>( |
2076 | offset, |
2077 | std::make_unique<VariableReference>(offset, *returnVar, |
2078 | VariableReference::kWrite_RefKind), |
2079 | Token::Kind::TK_EQ, |
2080 | expr(r.fExpression), |
2081 | returnVar->fType)); |
2082 | if (haveEarlyReturns) { |
2083 | std::vector<std::unique_ptr<Statement>> block; |
2084 | block.push_back(std::move(assignment)); |
2085 | block.emplace_back(new BreakStatement(offset)); |
2086 | return std::make_unique<Block>(offset, std::move(block), /*symbols=*/nullptr, |
2087 | /*isScope=*/true); |
2088 | } else { |
2089 | return std::move(assignment); |
2090 | } |
2091 | } else { |
2092 | if (haveEarlyReturns) { |
2093 | return std::make_unique<BreakStatement>(offset); |
2094 | } else { |
2095 | return std::make_unique<Nop>(); |
2096 | } |
2097 | } |
2098 | } |
2099 | case Statement::kSwitch_Kind: { |
2100 | const SwitchStatement& ss = static_cast<const SwitchStatement&>(statement); |
2101 | std::vector<std::unique_ptr<SwitchCase>> cases; |
2102 | for (const auto& sc : ss.fCases) { |
2103 | cases.emplace_back(new SwitchCase(offset, expr(sc->fValue), |
2104 | stmts(sc->fStatements))); |
2105 | } |
2106 | return std::make_unique<SwitchStatement>(offset, ss.fIsStatic, expr(ss.fValue), |
2107 | std::move(cases), ss.fSymbols); |
2108 | } |
2109 | case Statement::kVarDeclaration_Kind: { |
2110 | const VarDeclaration& decl = static_cast<const VarDeclaration&>(statement); |
2111 | std::vector<std::unique_ptr<Expression>> sizes; |
2112 | for (const auto& size : decl.fSizes) { |
2113 | sizes.push_back(expr(size)); |
2114 | } |
2115 | std::unique_ptr<Expression> initialValue = expr(decl.fValue); |
2116 | const Variable* old = decl.fVar; |
2117 | // need to copy the var name in case the originating function is discarded and we lose |
2118 | // its symbols |
2119 | std::unique_ptr<String> name(new String(old->fName)); |
2120 | const String* namePtr = fSymbolTable->takeOwnershipOfString(std::move(name)); |
2121 | const Type* typePtr = copy_if_needed(&old->fType, *fSymbolTable); |
2122 | const Variable* clone = fSymbolTable->takeOwnershipOfSymbol( |
2123 | std::make_unique<Variable>(offset, |
2124 | old->fModifiers, |
2125 | namePtr->c_str(), |
2126 | *typePtr, |
2127 | old->fStorage, |
2128 | initialValue.get())); |
2129 | (*varMap)[old] = clone; |
2130 | return std::make_unique<VarDeclaration>(clone, std::move(sizes), |
2131 | std::move(initialValue)); |
2132 | } |
2133 | case Statement::kVarDeclarations_Kind: { |
2134 | const VarDeclarations& decls = |
2135 | *static_cast<const VarDeclarationsStatement&>(statement).fDeclaration; |
2136 | std::vector<std::unique_ptr<VarDeclaration>> vars; |
2137 | for (const auto& var : decls.fVars) { |
2138 | vars.emplace_back((VarDeclaration*) stmt(var).release()); |
2139 | } |
2140 | const Type* typePtr = copy_if_needed(&decls.fBaseType, *fSymbolTable); |
2141 | return std::unique_ptr<Statement>(new VarDeclarationsStatement( |
2142 | std::make_unique<VarDeclarations>(offset, typePtr, std::move(vars)))); |
2143 | } |
2144 | case Statement::kWhile_Kind: { |
2145 | const WhileStatement& w = static_cast<const WhileStatement&>(statement); |
2146 | return std::make_unique<WhileStatement>(offset, expr(w.fTest), stmt(w.fStatement)); |
2147 | } |
2148 | default: |
2149 | SkASSERT(false); |
2150 | return nullptr; |
2151 | } |
2152 | } |
2153 | |
2154 | template <bool countTopLevelReturns> |
2155 | static int return_count(const Statement& statement, bool inLoopOrSwitch) { |
2156 | switch (statement.fKind) { |
2157 | case Statement::kBlock_Kind: { |
2158 | const Block& b = static_cast<const Block&>(statement); |
2159 | int result = 0; |
2160 | for (const std::unique_ptr<Statement>& s : b.fStatements) { |
2161 | result += return_count<countTopLevelReturns>(*s, inLoopOrSwitch); |
2162 | } |
2163 | return result; |
2164 | } |
2165 | case Statement::kDo_Kind: { |
2166 | const DoStatement& d = static_cast<const DoStatement&>(statement); |
2167 | return return_count<countTopLevelReturns>(*d.fStatement, /*inLoopOrSwitch=*/true); |
2168 | } |
2169 | case Statement::kFor_Kind: { |
2170 | const ForStatement& f = static_cast<const ForStatement&>(statement); |
2171 | return return_count<countTopLevelReturns>(*f.fStatement, /*inLoopOrSwitch=*/true); |
2172 | } |
2173 | case Statement::kIf_Kind: { |
2174 | const IfStatement& i = static_cast<const IfStatement&>(statement); |
2175 | int result = return_count<countTopLevelReturns>(*i.fIfTrue, inLoopOrSwitch); |
2176 | if (i.fIfFalse) { |
2177 | result += return_count<countTopLevelReturns>(*i.fIfFalse, inLoopOrSwitch); |
2178 | } |
2179 | return result; |
2180 | } |
2181 | case Statement::kReturn_Kind: |
2182 | return (countTopLevelReturns || inLoopOrSwitch) ? 1 : 0; |
2183 | case Statement::kSwitch_Kind: { |
2184 | const SwitchStatement& ss = static_cast<const SwitchStatement&>(statement); |
2185 | int result = 0; |
2186 | for (const std::unique_ptr<SwitchCase>& sc : ss.fCases) { |
2187 | for (const std::unique_ptr<Statement>& s : sc->fStatements) { |
2188 | result += return_count<countTopLevelReturns>(*s, /*inLoopOrSwitch=*/true); |
2189 | } |
2190 | } |
2191 | return result; |
2192 | } |
2193 | case Statement::kWhile_Kind: { |
2194 | const WhileStatement& w = static_cast<const WhileStatement&>(statement); |
2195 | return return_count<countTopLevelReturns>(*w.fStatement, /*inLoopOrSwitch=*/true); |
2196 | } |
2197 | case Statement::kBreak_Kind: |
2198 | case Statement::kContinue_Kind: |
2199 | case Statement::kDiscard_Kind: |
2200 | case Statement::kExpression_Kind: |
2201 | case Statement::kNop_Kind: |
2202 | case Statement::kVarDeclaration_Kind: |
2203 | case Statement::kVarDeclarations_Kind: |
2204 | return 0; |
2205 | default: |
2206 | SkASSERT(false); |
2207 | return 0; |
2208 | } |
2209 | } |
2210 | |
2211 | static bool has_early_return(const FunctionDefinition& f) { |
2212 | int returnCount = |
2213 | return_count</*countTopLevelReturns=*/true>(*f.fBody, /*inLoopOrSwitch=*/false); |
2214 | if (returnCount == 0) { |
2215 | return false; |
2216 | } |
2217 | if (returnCount > 1) { |
2218 | return true; |
2219 | } |
2220 | SkASSERT(f.fBody->fKind == Statement::kBlock_Kind); |
2221 | return static_cast<Block&>(*f.fBody).fStatements.back()->fKind != Statement::kReturn_Kind; |
2222 | } |
2223 | |
2224 | static bool has_return_in_breakable_construct(const FunctionDefinition& f) { |
2225 | int returnCount = |
2226 | return_count</*countTopLevelReturns=*/false>(*f.fBody, /*inLoopOrSwitch=*/false); |
2227 | return returnCount > 0; |
2228 | } |
2229 | |
2230 | std::unique_ptr<Expression> IRGenerator::inlineCall( |
2231 | int offset, |
2232 | const FunctionDefinition& function, |
2233 | std::vector<std::unique_ptr<Expression>> arguments) { |
2234 | // Inlining is more complicated here than in a typical compiler, because we have to have a |
2235 | // high-level IR and can't just drop statements into the middle of an expression or even use |
2236 | // gotos. |
2237 | // |
2238 | // Since we can't insert statements into an expression, we run the inline function as extra |
2239 | // statements before the statement we're currently processing, relying on a lack of execution |
2240 | // order guarantees. Since we can't use gotos (which are normally used to replace return |
2241 | // statements), we wrap the whole function in a loop and use break statements to jump to the |
2242 | // end. |
2243 | |
2244 | // Use unique variable names based on the function signature. Otherwise there are situations in |
2245 | // which an inlined function is later inlined into another function, and we end up with |
2246 | // duplicate names like 'inlineResult0' because the counter was reset. (skbug.com/10526) |
2247 | String raw = function.fDeclaration.description(); |
2248 | String inlineSalt; |
2249 | for (size_t i = 0; i < raw.length(); ++i) { |
2250 | char c = raw[i]; |
2251 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || |
2252 | c == '_') { |
2253 | inlineSalt += c; |
2254 | } |
2255 | } |
2256 | |
2257 | const Variable* resultVar = nullptr; |
2258 | if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) { |
2259 | std::unique_ptr<String> name(new String()); |
2260 | int varIndex = fInlineVarCounter++; |
2261 | name->appendf("_inlineResult%s%d" , inlineSalt.c_str(), varIndex); |
2262 | const String* namePtr = fSymbolTable->takeOwnershipOfString(std::move(name)); |
2263 | StringFragment nameFrag{namePtr->c_str(), namePtr->length()}; |
2264 | resultVar = fSymbolTable->add( |
2265 | nameFrag, |
2266 | std::make_unique<Variable>( |
2267 | /*offset=*/-1, Modifiers(), nameFrag, function.fDeclaration.fReturnType, |
2268 | Variable::kLocal_Storage, /*initialValue=*/nullptr)); |
2269 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
2270 | variables.emplace_back(new VarDeclaration(resultVar, {}, nullptr)); |
2271 | fExtraStatements.emplace_back( |
2272 | new VarDeclarationsStatement(std::make_unique<VarDeclarations>( |
2273 | offset, &resultVar->fType, std::move(variables)))); |
2274 | |
2275 | } |
2276 | std::unordered_map<const Variable*, const Variable*> varMap; |
2277 | // create variables to hold the arguments and assign the arguments to them |
2278 | int argIndex = fInlineVarCounter++; |
2279 | for (int i = 0; i < (int) arguments.size(); ++i) { |
2280 | std::unique_ptr<String> argName(new String()); |
2281 | argName->appendf("_inlineArg%s%d_%d" , inlineSalt.c_str(), argIndex, i); |
2282 | const String* argNamePtr = fSymbolTable->takeOwnershipOfString(std::move(argName)); |
2283 | StringFragment argNameFrag{argNamePtr->c_str(), argNamePtr->length()}; |
2284 | const Variable* argVar = fSymbolTable->add( |
2285 | argNameFrag, std::make_unique<Variable>( |
2286 | /*offset=*/-1, Modifiers(), argNameFrag, arguments[i]->fType, |
2287 | Variable::kLocal_Storage, arguments[i].get())); |
2288 | varMap[function.fDeclaration.fParameters[i]] = argVar; |
2289 | std::vector<std::unique_ptr<VarDeclaration>> vars; |
2290 | if (function.fDeclaration.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) { |
2291 | vars.emplace_back(new VarDeclaration(argVar, {}, arguments[i]->clone())); |
2292 | } else { |
2293 | vars.emplace_back(new VarDeclaration(argVar, {}, std::move(arguments[i]))); |
2294 | } |
2295 | fExtraStatements.emplace_back(new VarDeclarationsStatement( |
2296 | std::make_unique<VarDeclarations>(offset, &argVar->fType, std::move(vars)))); |
2297 | } |
2298 | SkASSERT(function.fBody->fKind == Statement::kBlock_Kind); |
2299 | const Block& body = (Block&) *function.fBody; |
2300 | bool hasEarlyReturn = has_early_return(function); |
2301 | std::vector<std::unique_ptr<Statement>> inlined; |
2302 | for (const auto& s : body.fStatements) { |
2303 | inlined.push_back(this->inlineStatement(offset, &varMap, resultVar, hasEarlyReturn, *s)); |
2304 | } |
2305 | if (hasEarlyReturn) { |
2306 | // Since we output to backends that don't have a goto statement (which would normally be |
2307 | // used to perform an early return), we fake it by wrapping the function in a |
2308 | // do { } while (false); and then use break statements to jump to the end in order to |
2309 | // emulate a goto. |
2310 | fExtraStatements.emplace_back(new DoStatement(-1, |
2311 | std::unique_ptr<Statement>(new Block(-1, std::move(inlined))), |
2312 | std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false)))); |
2313 | } else { |
2314 | // No early returns, so we can just dump the code in. We need to use a block so we don't get |
2315 | // name conflicts with locals. |
2316 | fExtraStatements.emplace_back(std::unique_ptr<Statement>(new Block(-1, |
2317 | std::move(inlined)))); |
2318 | } |
2319 | // copy the values of out parameters into their destinations |
2320 | for (size_t i = 0; i < arguments.size(); ++i) { |
2321 | const Variable* p = function.fDeclaration.fParameters[i]; |
2322 | if (p->fModifiers.fFlags & Modifiers::kOut_Flag) { |
2323 | std::unique_ptr<Expression> varRef(new VariableReference(offset, *varMap[p])); |
2324 | fExtraStatements.emplace_back(new ExpressionStatement( |
2325 | std::unique_ptr<Expression>(new BinaryExpression(offset, |
2326 | arguments[i]->clone(), |
2327 | Token::Kind::TK_EQ, |
2328 | std::move(varRef), |
2329 | arguments[i]->fType)))); |
2330 | } |
2331 | } |
2332 | if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) { |
2333 | return std::unique_ptr<Expression>(new VariableReference(-1, *resultVar)); |
2334 | } else { |
2335 | // it's a void function, so it doesn't actually result in anything, but we have to return |
2336 | // something non-null as a standin |
2337 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false)); |
2338 | } |
2339 | } |
2340 | |
2341 | void IRGenerator::copyIntrinsicIfNeeded(const FunctionDeclaration& function) { |
2342 | auto found = fIntrinsics->find(function.description()); |
2343 | if (found != fIntrinsics->end() && !found->second.second) { |
2344 | found->second.second = true; |
2345 | FunctionDefinition& original = ((FunctionDefinition&) *found->second.first); |
2346 | for (const FunctionDeclaration* f : original.fReferencedIntrinsics) { |
2347 | this->copyIntrinsicIfNeeded(*f); |
2348 | } |
2349 | fProgramElements->push_back(original.clone()); |
2350 | } |
2351 | } |
2352 | |
2353 | bool IRGenerator::isSafeToInline(const FunctionDefinition& functionDef) { |
2354 | if (!fCanInline) { |
2355 | // Inlining has been explicitly disabled by the IR generator. |
2356 | return false; |
2357 | } |
2358 | if (functionDef.inlinedFunctionSize() >= fSettings->fInlineThreshold) { |
2359 | // The function exceeds our maximum inline size. |
2360 | return false; |
2361 | } |
2362 | if (!fSettings->fCaps || !fSettings->fCaps->canUseDoLoops()) { |
2363 | // We don't have do-while loops. We use do-while loops to simulate early returns, so we |
2364 | // can't inline functions that have an early return. |
2365 | return !has_early_return(functionDef); |
2366 | } |
2367 | // We have do-while loops, but we don't have any mechanism to simulate early returns within a |
2368 | // breakable construct (switch/for/do/while), so we can't inline if there's a return inside one. |
2369 | return !has_return_in_breakable_construct(functionDef); |
2370 | } |
2371 | |
2372 | std::unique_ptr<Expression> IRGenerator::call(int offset, |
2373 | const FunctionDeclaration& function, |
2374 | std::vector<std::unique_ptr<Expression>> arguments) { |
2375 | if (function.fBuiltin) { |
2376 | if (function.fDefinition) { |
2377 | fReferencedIntrinsics.insert(&function); |
2378 | } |
2379 | if (!fIsBuiltinCode) { |
2380 | this->copyIntrinsicIfNeeded(function); |
2381 | } |
2382 | } |
2383 | if (function.fParameters.size() != arguments.size()) { |
2384 | String msg = "call to '" + function.fName + "' expected " + |
2385 | to_string((uint64_t) function.fParameters.size()) + |
2386 | " argument" ; |
2387 | if (function.fParameters.size() != 1) { |
2388 | msg += "s" ; |
2389 | } |
2390 | msg += ", but found " + to_string((uint64_t) arguments.size()); |
2391 | fErrors.error(offset, msg); |
2392 | return nullptr; |
2393 | } |
2394 | if (fKind == Program::kPipelineStage_Kind && !function.fDefinition && !function.fBuiltin) { |
2395 | String msg = "call to undefined function '" + function.fName + "'" ; |
2396 | fErrors.error(offset, msg); |
2397 | return nullptr; |
2398 | } |
2399 | std::vector<const Type*> types; |
2400 | const Type* returnType; |
2401 | if (!function.determineFinalTypes(arguments, &types, &returnType)) { |
2402 | String msg = "no match for " + function.fName + "(" ; |
2403 | String separator; |
2404 | for (size_t i = 0; i < arguments.size(); i++) { |
2405 | msg += separator; |
2406 | separator = ", " ; |
2407 | msg += arguments[i]->fType.displayName(); |
2408 | } |
2409 | msg += ")" ; |
2410 | fErrors.error(offset, msg); |
2411 | return nullptr; |
2412 | } |
2413 | for (size_t i = 0; i < arguments.size(); i++) { |
2414 | arguments[i] = this->coerce(std::move(arguments[i]), *types[i]); |
2415 | if (!arguments[i]) { |
2416 | return nullptr; |
2417 | } |
2418 | if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) { |
2419 | this->setRefKind(*arguments[i], |
2420 | function.fParameters[i]->fModifiers.fFlags & Modifiers::kIn_Flag ? |
2421 | VariableReference::kReadWrite_RefKind : |
2422 | VariableReference::kPointer_RefKind); |
2423 | } |
2424 | } |
2425 | if (function.fDefinition && this->isSafeToInline(*function.fDefinition)) { |
2426 | return this->inlineCall(offset, *function.fDefinition, std::move(arguments)); |
2427 | } |
2428 | |
2429 | return std::make_unique<FunctionCall>(offset, *returnType, function, std::move(arguments)); |
2430 | } |
2431 | |
2432 | /** |
2433 | * Determines the cost of coercing the arguments of a function to the required types. Cost has no |
2434 | * particular meaning other than "lower costs are preferred". Returns INT_MAX if the call is not |
2435 | * valid. |
2436 | */ |
2437 | int IRGenerator::callCost(const FunctionDeclaration& function, |
2438 | const std::vector<std::unique_ptr<Expression>>& arguments) { |
2439 | if (function.fParameters.size() != arguments.size()) { |
2440 | return INT_MAX; |
2441 | } |
2442 | int total = 0; |
2443 | std::vector<const Type*> types; |
2444 | const Type* ignored; |
2445 | if (!function.determineFinalTypes(arguments, &types, &ignored)) { |
2446 | return INT_MAX; |
2447 | } |
2448 | for (size_t i = 0; i < arguments.size(); i++) { |
2449 | int cost = arguments[i]->coercionCost(*types[i]); |
2450 | if (cost != INT_MAX) { |
2451 | total += cost; |
2452 | } else { |
2453 | return INT_MAX; |
2454 | } |
2455 | } |
2456 | return total; |
2457 | } |
2458 | |
2459 | std::unique_ptr<Expression> IRGenerator::call(int offset, |
2460 | std::unique_ptr<Expression> functionValue, |
2461 | std::vector<std::unique_ptr<Expression>> arguments) { |
2462 | switch (functionValue->fKind) { |
2463 | case Expression::kTypeReference_Kind: |
2464 | return this->convertConstructor(offset, |
2465 | ((TypeReference&) *functionValue).fValue, |
2466 | std::move(arguments)); |
2467 | case Expression::kExternalValue_Kind: { |
2468 | ExternalValue* v = ((ExternalValueReference&) *functionValue).fValue; |
2469 | if (!v->canCall()) { |
2470 | fErrors.error(offset, "this external value is not a function" ); |
2471 | return nullptr; |
2472 | } |
2473 | int count = v->callParameterCount(); |
2474 | if (count != (int) arguments.size()) { |
2475 | fErrors.error(offset, "external function expected " + to_string(count) + |
2476 | " arguments, but found " + to_string((int) arguments.size())); |
2477 | return nullptr; |
2478 | } |
2479 | static constexpr int PARAMETER_MAX = 16; |
2480 | SkASSERT(count < PARAMETER_MAX); |
2481 | const Type* types[PARAMETER_MAX]; |
2482 | v->getCallParameterTypes(types); |
2483 | for (int i = 0; i < count; ++i) { |
2484 | arguments[i] = this->coerce(std::move(arguments[i]), *types[i]); |
2485 | if (!arguments[i]) { |
2486 | return nullptr; |
2487 | } |
2488 | } |
2489 | return std::unique_ptr<Expression>(new ExternalFunctionCall(offset, v->callReturnType(), |
2490 | v, std::move(arguments))); |
2491 | } |
2492 | case Expression::kFunctionReference_Kind: { |
2493 | FunctionReference* ref = (FunctionReference*) functionValue.get(); |
2494 | int bestCost = INT_MAX; |
2495 | const FunctionDeclaration* best = nullptr; |
2496 | if (ref->fFunctions.size() > 1) { |
2497 | for (const auto& f : ref->fFunctions) { |
2498 | int cost = this->callCost(*f, arguments); |
2499 | if (cost < bestCost) { |
2500 | bestCost = cost; |
2501 | best = f; |
2502 | } |
2503 | } |
2504 | if (best) { |
2505 | return this->call(offset, *best, std::move(arguments)); |
2506 | } |
2507 | String msg = "no match for " + ref->fFunctions[0]->fName + "(" ; |
2508 | String separator; |
2509 | for (size_t i = 0; i < arguments.size(); i++) { |
2510 | msg += separator; |
2511 | separator = ", " ; |
2512 | msg += arguments[i]->fType.displayName(); |
2513 | } |
2514 | msg += ")" ; |
2515 | fErrors.error(offset, msg); |
2516 | return nullptr; |
2517 | } |
2518 | return this->call(offset, *ref->fFunctions[0], std::move(arguments)); |
2519 | } |
2520 | default: |
2521 | fErrors.error(offset, "not a function" ); |
2522 | return nullptr; |
2523 | } |
2524 | } |
2525 | |
2526 | std::unique_ptr<Expression> IRGenerator::convertNumberConstructor( |
2527 | int offset, |
2528 | const Type& type, |
2529 | std::vector<std::unique_ptr<Expression>> args) { |
2530 | SkASSERT(type.isNumber()); |
2531 | if (args.size() != 1) { |
2532 | fErrors.error(offset, "invalid arguments to '" + type.displayName() + |
2533 | "' constructor, (expected exactly 1 argument, but found " + |
2534 | to_string((uint64_t) args.size()) + ")" ); |
2535 | return nullptr; |
2536 | } |
2537 | if (type == args[0]->fType) { |
2538 | return std::move(args[0]); |
2539 | } |
2540 | if (type.isFloat() && args.size() == 1 && args[0]->fKind == Expression::kFloatLiteral_Kind) { |
2541 | double value = ((FloatLiteral&) *args[0]).fValue; |
2542 | return std::unique_ptr<Expression>(new FloatLiteral(offset, value, &type)); |
2543 | } |
2544 | if (type.isFloat() && args.size() == 1 && args[0]->fKind == Expression::kIntLiteral_Kind) { |
2545 | int64_t value = ((IntLiteral&) *args[0]).fValue; |
2546 | return std::unique_ptr<Expression>(new FloatLiteral(offset, (double) value, &type)); |
2547 | } |
2548 | if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type || |
2549 | type == *fContext.fUInt_Type)) { |
2550 | return std::unique_ptr<Expression>(new IntLiteral(offset, |
2551 | ((IntLiteral&) *args[0]).fValue, |
2552 | &type)); |
2553 | } |
2554 | if (args[0]->fType == *fContext.fBool_Type) { |
2555 | std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, offset, 0)); |
2556 | std::unique_ptr<IntLiteral> one(new IntLiteral(fContext, offset, 1)); |
2557 | return std::unique_ptr<Expression>( |
2558 | new TernaryExpression(offset, std::move(args[0]), |
2559 | this->coerce(std::move(one), type), |
2560 | this->coerce(std::move(zero), |
2561 | type))); |
2562 | } |
2563 | if (!args[0]->fType.isNumber()) { |
2564 | fErrors.error(offset, "invalid argument to '" + type.displayName() + |
2565 | "' constructor (expected a number or bool, but found '" + |
2566 | args[0]->fType.displayName() + "')" ); |
2567 | return nullptr; |
2568 | } |
2569 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2570 | } |
2571 | |
2572 | static int component_count(const Type& type) { |
2573 | switch (type.kind()) { |
2574 | case Type::kVector_Kind: |
2575 | return type.columns(); |
2576 | case Type::kMatrix_Kind: |
2577 | return type.columns() * type.rows(); |
2578 | default: |
2579 | return 1; |
2580 | } |
2581 | } |
2582 | |
2583 | std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor( |
2584 | int offset, |
2585 | const Type& type, |
2586 | std::vector<std::unique_ptr<Expression>> args) { |
2587 | SkASSERT(type.kind() == Type::kVector_Kind || type.kind() == Type::kMatrix_Kind); |
2588 | if (type.kind() == Type::kMatrix_Kind && args.size() == 1 && |
2589 | args[0]->fType.kind() == Type::kMatrix_Kind) { |
2590 | // matrix from matrix is always legal |
2591 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2592 | } |
2593 | int actual = 0; |
2594 | int expected = type.rows() * type.columns(); |
2595 | if (args.size() != 1 || expected != component_count(args[0]->fType) || |
2596 | type.componentType().isNumber() != args[0]->fType.componentType().isNumber()) { |
2597 | for (size_t i = 0; i < args.size(); i++) { |
2598 | if (args[i]->fType.kind() == Type::kVector_Kind) { |
2599 | if (type.componentType().isNumber() != |
2600 | args[i]->fType.componentType().isNumber()) { |
2601 | fErrors.error(offset, "'" + args[i]->fType.displayName() + "' is not a valid " |
2602 | "parameter to '" + type.displayName() + |
2603 | "' constructor" ); |
2604 | return nullptr; |
2605 | } |
2606 | actual += args[i]->fType.columns(); |
2607 | } else if (args[i]->fType.kind() == Type::kScalar_Kind) { |
2608 | actual += 1; |
2609 | if (type.kind() != Type::kScalar_Kind) { |
2610 | args[i] = this->coerce(std::move(args[i]), type.componentType()); |
2611 | if (!args[i]) { |
2612 | return nullptr; |
2613 | } |
2614 | } |
2615 | } else { |
2616 | fErrors.error(offset, "'" + args[i]->fType.displayName() + "' is not a valid " |
2617 | "parameter to '" + type.displayName() + "' constructor" ); |
2618 | return nullptr; |
2619 | } |
2620 | } |
2621 | if (actual != 1 && actual != expected) { |
2622 | fErrors.error(offset, "invalid arguments to '" + type.displayName() + |
2623 | "' constructor (expected " + to_string(expected) + |
2624 | " scalars, but found " + to_string(actual) + ")" ); |
2625 | return nullptr; |
2626 | } |
2627 | } |
2628 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2629 | } |
2630 | |
2631 | std::unique_ptr<Expression> IRGenerator::convertConstructor( |
2632 | int offset, |
2633 | const Type& type, |
2634 | std::vector<std::unique_ptr<Expression>> args) { |
2635 | // FIXME: add support for structs |
2636 | if (args.size() == 1 && args[0]->fType == type && |
2637 | type.nonnullable() != *fContext.fFragmentProcessor_Type) { |
2638 | // argument is already the right type, just return it |
2639 | return std::move(args[0]); |
2640 | } |
2641 | Type::Kind kind = type.kind(); |
2642 | if (type.isNumber()) { |
2643 | return this->convertNumberConstructor(offset, type, std::move(args)); |
2644 | } else if (kind == Type::kArray_Kind) { |
2645 | const Type& base = type.componentType(); |
2646 | for (size_t i = 0; i < args.size(); i++) { |
2647 | args[i] = this->coerce(std::move(args[i]), base); |
2648 | if (!args[i]) { |
2649 | return nullptr; |
2650 | } |
2651 | } |
2652 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2653 | } else if (kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) { |
2654 | return this->convertCompoundConstructor(offset, type, std::move(args)); |
2655 | } else { |
2656 | fErrors.error(offset, "cannot construct '" + type.displayName() + "'" ); |
2657 | return nullptr; |
2658 | } |
2659 | } |
2660 | |
2661 | std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(const ASTNode& expression) { |
2662 | SkASSERT(expression.fKind == ASTNode::Kind::kPrefix); |
2663 | std::unique_ptr<Expression> base = this->convertExpression(*expression.begin()); |
2664 | if (!base) { |
2665 | return nullptr; |
2666 | } |
2667 | switch (expression.getToken().fKind) { |
2668 | case Token::Kind::TK_PLUS: |
2669 | if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind && |
2670 | base->fType != *fContext.fFloatLiteral_Type) { |
2671 | fErrors.error(expression.fOffset, |
2672 | "'+' cannot operate on '" + base->fType.displayName() + "'" ); |
2673 | return nullptr; |
2674 | } |
2675 | return base; |
2676 | case Token::Kind::TK_MINUS: |
2677 | if (base->fKind == Expression::kIntLiteral_Kind) { |
2678 | return std::unique_ptr<Expression>(new IntLiteral(fContext, base->fOffset, |
2679 | -((IntLiteral&) *base).fValue)); |
2680 | } |
2681 | if (base->fKind == Expression::kFloatLiteral_Kind) { |
2682 | double value = -((FloatLiteral&) *base).fValue; |
2683 | return std::unique_ptr<Expression>(new FloatLiteral(fContext, base->fOffset, |
2684 | value)); |
2685 | } |
2686 | if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) { |
2687 | fErrors.error(expression.fOffset, |
2688 | "'-' cannot operate on '" + base->fType.displayName() + "'" ); |
2689 | return nullptr; |
2690 | } |
2691 | return std::unique_ptr<Expression>(new PrefixExpression(Token::Kind::TK_MINUS, |
2692 | std::move(base))); |
2693 | case Token::Kind::TK_PLUSPLUS: |
2694 | if (!base->fType.isNumber()) { |
2695 | fErrors.error(expression.fOffset, |
2696 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2697 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2698 | return nullptr; |
2699 | } |
2700 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
2701 | break; |
2702 | case Token::Kind::TK_MINUSMINUS: |
2703 | if (!base->fType.isNumber()) { |
2704 | fErrors.error(expression.fOffset, |
2705 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2706 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2707 | return nullptr; |
2708 | } |
2709 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
2710 | break; |
2711 | case Token::Kind::TK_LOGICALNOT: |
2712 | if (base->fType != *fContext.fBool_Type) { |
2713 | fErrors.error(expression.fOffset, |
2714 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2715 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2716 | return nullptr; |
2717 | } |
2718 | if (base->fKind == Expression::kBoolLiteral_Kind) { |
2719 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, base->fOffset, |
2720 | !((BoolLiteral&) *base).fValue)); |
2721 | } |
2722 | break; |
2723 | case Token::Kind::TK_BITWISENOT: |
2724 | if (base->fType != *fContext.fInt_Type && base->fType != *fContext.fUInt_Type) { |
2725 | fErrors.error(expression.fOffset, |
2726 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2727 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2728 | return nullptr; |
2729 | } |
2730 | break; |
2731 | default: |
2732 | ABORT("unsupported prefix operator\n" ); |
2733 | } |
2734 | return std::unique_ptr<Expression>(new PrefixExpression(expression.getToken().fKind, |
2735 | std::move(base))); |
2736 | } |
2737 | |
2738 | std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression> base, |
2739 | const ASTNode& index) { |
2740 | if (base->fKind == Expression::kTypeReference_Kind) { |
2741 | if (index.fKind == ASTNode::Kind::kInt) { |
2742 | const Type& oldType = ((TypeReference&) *base).fValue; |
2743 | SKSL_INT size = index.getInt(); |
2744 | const Type* newType = fSymbolTable->takeOwnershipOfSymbol( |
2745 | std::make_unique<Type>(oldType.name() + "[" + to_string(size) + "]" , |
2746 | Type::kArray_Kind, oldType, size)); |
2747 | return std::make_unique<TypeReference>(fContext, base->fOffset, *newType); |
2748 | |
2749 | } else { |
2750 | fErrors.error(base->fOffset, "array size must be a constant" ); |
2751 | return nullptr; |
2752 | } |
2753 | } |
2754 | if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind && |
2755 | base->fType.kind() != Type::kVector_Kind) { |
2756 | fErrors.error(base->fOffset, "expected array, but found '" + base->fType.displayName() + |
2757 | "'" ); |
2758 | return nullptr; |
2759 | } |
2760 | std::unique_ptr<Expression> converted = this->convertExpression(index); |
2761 | if (!converted) { |
2762 | return nullptr; |
2763 | } |
2764 | if (converted->fType != *fContext.fUInt_Type) { |
2765 | converted = this->coerce(std::move(converted), *fContext.fInt_Type); |
2766 | if (!converted) { |
2767 | return nullptr; |
2768 | } |
2769 | } |
2770 | return std::unique_ptr<Expression>(new IndexExpression(fContext, std::move(base), |
2771 | std::move(converted))); |
2772 | } |
2773 | |
2774 | std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base, |
2775 | StringFragment field) { |
2776 | if (base->fKind == Expression::kExternalValue_Kind) { |
2777 | ExternalValue& ev = *((ExternalValueReference&) *base).fValue; |
2778 | ExternalValue* result = ev.getChild(String(field).c_str()); |
2779 | if (!result) { |
2780 | fErrors.error(base->fOffset, "external value does not have a child named '" + field + |
2781 | "'" ); |
2782 | return nullptr; |
2783 | } |
2784 | return std::unique_ptr<Expression>(new ExternalValueReference(base->fOffset, result)); |
2785 | } |
2786 | auto fields = base->fType.fields(); |
2787 | for (size_t i = 0; i < fields.size(); i++) { |
2788 | if (fields[i].fName == field) { |
2789 | return std::unique_ptr<Expression>(new FieldAccess(std::move(base), (int) i)); |
2790 | } |
2791 | } |
2792 | fErrors.error(base->fOffset, "type '" + base->fType.displayName() + "' does not have a " |
2793 | "field named '" + field + "" ); |
2794 | return nullptr; |
2795 | } |
2796 | |
2797 | // counts the number of chunks of contiguous 'x's in a swizzle, e.g. xxx1 has one and x0xx has two |
2798 | static int count_contiguous_swizzle_chunks(const std::vector<int>& components) { |
2799 | int chunkCount = 0; |
2800 | for (size_t i = 0; i < components.size(); ++i) { |
2801 | SkASSERT(components[i] <= 0); |
2802 | if (components[i] == 0) { |
2803 | ++chunkCount; |
2804 | while (i + 1 < components.size() && components[i + 1] == 0) { |
2805 | ++i; |
2806 | } |
2807 | } |
2808 | } |
2809 | return chunkCount; |
2810 | } |
2811 | |
2812 | std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base, |
2813 | StringFragment fields) { |
2814 | if (base->fType.kind() != Type::kVector_Kind && !base->fType.isNumber()) { |
2815 | fErrors.error(base->fOffset, "cannot swizzle value of type '" + base->fType.displayName() + |
2816 | "'" ); |
2817 | return nullptr; |
2818 | } |
2819 | std::vector<int> swizzleComponents; |
2820 | for (size_t i = 0; i < fields.fLength; i++) { |
2821 | switch (fields[i]) { |
2822 | case '0': |
2823 | swizzleComponents.push_back(SKSL_SWIZZLE_0); |
2824 | break; |
2825 | case '1': |
2826 | swizzleComponents.push_back(SKSL_SWIZZLE_1); |
2827 | break; |
2828 | case 'x': |
2829 | case 'r': |
2830 | case 's': |
2831 | case 'L': |
2832 | swizzleComponents.push_back(0); |
2833 | break; |
2834 | case 'y': |
2835 | case 'g': |
2836 | case 't': |
2837 | case 'T': |
2838 | if (base->fType.columns() >= 2) { |
2839 | swizzleComponents.push_back(1); |
2840 | break; |
2841 | } |
2842 | [[fallthrough]]; |
2843 | case 'z': |
2844 | case 'b': |
2845 | case 'p': |
2846 | case 'R': |
2847 | if (base->fType.columns() >= 3) { |
2848 | swizzleComponents.push_back(2); |
2849 | break; |
2850 | } |
2851 | [[fallthrough]]; |
2852 | case 'w': |
2853 | case 'a': |
2854 | case 'q': |
2855 | case 'B': |
2856 | if (base->fType.columns() >= 4) { |
2857 | swizzleComponents.push_back(3); |
2858 | break; |
2859 | } |
2860 | [[fallthrough]]; |
2861 | default: |
2862 | fErrors.error(base->fOffset, String::printf("invalid swizzle component '%c'" , |
2863 | fields[i])); |
2864 | return nullptr; |
2865 | } |
2866 | } |
2867 | SkASSERT(swizzleComponents.size() > 0); |
2868 | if (swizzleComponents.size() > 4) { |
2869 | fErrors.error(base->fOffset, "too many components in swizzle mask '" + fields + "'" ); |
2870 | return nullptr; |
2871 | } |
2872 | if (base->fType.isNumber()) { |
2873 | // Swizzling a single scalar. Something like foo.x0x1 is equivalent to float4(foo, 0, foo, |
2874 | // 1) |
2875 | int offset = base->fOffset; |
2876 | std::unique_ptr<Expression> expr; |
2877 | switch (base->fKind) { |
2878 | case Expression::kVariableReference_Kind: |
2879 | case Expression::kFloatLiteral_Kind: |
2880 | case Expression::kIntLiteral_Kind: |
2881 | // the value being swizzled is just a constant or variable reference, so we can |
2882 | // safely re-use copies of it without reevaluation concerns |
2883 | expr = std::move(base); |
2884 | break; |
2885 | default: |
2886 | // It's a value we can't safely re-use multiple times. If it's all in one contiguous |
2887 | // chunk it's easy (e.g. foo.xxx0 can be turned into half4(half3(x), 0)), but |
2888 | // for multiple discontiguous chunks we'll need to copy it into a temporary value. |
2889 | int chunkCount = count_contiguous_swizzle_chunks(swizzleComponents); |
2890 | if (chunkCount <= 1) { |
2891 | // no copying needed, so we can just use the value directly |
2892 | expr = std::move(base); |
2893 | } else { |
2894 | // store the value in a temporary variable so we can re-use it |
2895 | int varIndex = fInlineVarCounter++; |
2896 | auto name = std::make_unique<String>(); |
2897 | name->appendf("_tmpSwizzle%d" , varIndex); |
2898 | const String* namePtr = fSymbolTable->takeOwnershipOfString(std::move(name)); |
2899 | const Variable* var = fSymbolTable->takeOwnershipOfSymbol( |
2900 | std::make_unique<Variable>(offset, |
2901 | Modifiers(), |
2902 | namePtr->c_str(), |
2903 | base->fType, |
2904 | Variable::kLocal_Storage, |
2905 | base.get())); |
2906 | expr = std::make_unique<VariableReference>(offset, *var); |
2907 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
2908 | variables.emplace_back(new VarDeclaration(var, {}, std::move(base))); |
2909 | fExtraStatements.emplace_back(new VarDeclarationsStatement( |
2910 | std::make_unique<VarDeclarations>(offset, &expr->fType, |
2911 | std::move(variables)))); |
2912 | } |
2913 | } |
2914 | std::vector<std::unique_ptr<Expression>> args; |
2915 | for (size_t i = 0; i < swizzleComponents.size(); ++i) { |
2916 | switch (swizzleComponents[i]) { |
2917 | case 0: { |
2918 | args.push_back(expr->clone()); |
2919 | int count = 1; |
2920 | while (i + 1 < swizzleComponents.size() && swizzleComponents[i + 1] == 0) { |
2921 | ++i; |
2922 | ++count; |
2923 | } |
2924 | if (count > 1) { |
2925 | std::vector<std::unique_ptr<Expression>> constructorArgs; |
2926 | constructorArgs.push_back(std::move(args.back())); |
2927 | args.pop_back(); |
2928 | args.emplace_back(new Constructor(offset, expr->fType.toCompound(fContext, |
2929 | count, |
2930 | 1), |
2931 | std::move(constructorArgs))); |
2932 | } |
2933 | break; |
2934 | } |
2935 | case SKSL_SWIZZLE_0: |
2936 | args.emplace_back(new IntLiteral(fContext, offset, 0)); |
2937 | break; |
2938 | case SKSL_SWIZZLE_1: |
2939 | args.emplace_back(new IntLiteral(fContext, offset, 1)); |
2940 | break; |
2941 | } |
2942 | } |
2943 | return std::unique_ptr<Expression>(new Constructor(offset, |
2944 | expr->fType.toCompound( |
2945 | fContext, |
2946 | swizzleComponents.size(), |
2947 | 1), |
2948 | std::move(args))); |
2949 | } |
2950 | return std::unique_ptr<Expression>(new Swizzle(fContext, std::move(base), swizzleComponents)); |
2951 | } |
2952 | |
2953 | std::unique_ptr<Expression> IRGenerator::getCap(int offset, String name) { |
2954 | auto found = fCapsMap.find(name); |
2955 | if (found == fCapsMap.end()) { |
2956 | fErrors.error(offset, "unknown capability flag '" + name + "'" ); |
2957 | return nullptr; |
2958 | } |
2959 | String fullName = "sk_Caps." + name; |
2960 | return std::unique_ptr<Expression>(new Setting(offset, fullName, |
2961 | found->second.literal(fContext, offset))); |
2962 | } |
2963 | |
2964 | std::unique_ptr<Expression> IRGenerator::findEnumRef( |
2965 | int offset, |
2966 | const Type& type, |
2967 | StringFragment field, |
2968 | std::vector<std::unique_ptr<ProgramElement>>& elements) { |
2969 | for (const auto& e : elements) { |
2970 | if (e->fKind == ProgramElement::kEnum_Kind && type.name() == ((Enum&) *e).fTypeName) { |
2971 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
2972 | fSymbolTable = ((Enum&) *e).fSymbols; |
2973 | std::unique_ptr<Expression> result = convertIdentifier(ASTNode(&fFile->fNodes, offset, |
2974 | ASTNode::Kind::kIdentifier, |
2975 | field)); |
2976 | if (result) { |
2977 | SkASSERT(result->fKind == Expression::kVariableReference_Kind); |
2978 | const Variable& v = ((VariableReference&) *result).fVariable; |
2979 | SkASSERT(v.fInitialValue); |
2980 | SkASSERT(v.fInitialValue->fKind == Expression::kIntLiteral_Kind); |
2981 | result = std::make_unique<IntLiteral>( |
2982 | offset, ((IntLiteral&)*v.fInitialValue).fValue, &type); |
2983 | } |
2984 | fSymbolTable = old; |
2985 | return result; |
2986 | } |
2987 | } |
2988 | return nullptr; |
2989 | } |
2990 | |
2991 | std::unique_ptr<Expression> IRGenerator::convertTypeField(int offset, const Type& type, |
2992 | StringFragment field) { |
2993 | std::unique_ptr<Expression> result = this->findEnumRef(offset, type, field, *fProgramElements); |
2994 | if (fInherited && !result) { |
2995 | result = this->findEnumRef(offset, type, field, *fInherited); |
2996 | } |
2997 | if (!result) { |
2998 | auto found = fIntrinsics->find(type.fName); |
2999 | if (found != fIntrinsics->end()) { |
3000 | SkASSERT(!found->second.second); |
3001 | found->second.second = true; |
3002 | fProgramElements->push_back(found->second.first->clone()); |
3003 | return this->convertTypeField(offset, type, field); |
3004 | } |
3005 | fErrors.error(offset, "type '" + type.fName + "' does not have a field named '" + field + |
3006 | "'" ); |
3007 | } |
3008 | return result; |
3009 | } |
3010 | |
3011 | std::unique_ptr<Expression> IRGenerator::convertIndexExpression(const ASTNode& index) { |
3012 | SkASSERT(index.fKind == ASTNode::Kind::kIndex); |
3013 | auto iter = index.begin(); |
3014 | std::unique_ptr<Expression> base = this->convertExpression(*(iter++)); |
3015 | if (!base) { |
3016 | return nullptr; |
3017 | } |
3018 | if (iter != index.end()) { |
3019 | return this->convertIndex(std::move(base), *(iter++)); |
3020 | } else if (base->fKind == Expression::kTypeReference_Kind) { |
3021 | const Type& oldType = ((TypeReference&) *base).fValue; |
3022 | const Type* newType = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>( |
3023 | oldType.name() + "[]" , Type::kArray_Kind, oldType, /*columns=*/-1)); |
3024 | return std::unique_ptr<Expression>(new TypeReference(fContext, base->fOffset, |
3025 | *newType)); |
3026 | } |
3027 | fErrors.error(index.fOffset, "'[]' must follow a type name" ); |
3028 | return nullptr; |
3029 | } |
3030 | |
3031 | std::unique_ptr<Expression> IRGenerator::convertCallExpression(const ASTNode& callNode) { |
3032 | SkASSERT(callNode.fKind == ASTNode::Kind::kCall); |
3033 | auto iter = callNode.begin(); |
3034 | std::unique_ptr<Expression> base = this->convertExpression(*(iter++)); |
3035 | if (!base) { |
3036 | return nullptr; |
3037 | } |
3038 | std::vector<std::unique_ptr<Expression>> arguments; |
3039 | for (; iter != callNode.end(); ++iter) { |
3040 | std::unique_ptr<Expression> converted = this->convertExpression(*iter); |
3041 | if (!converted) { |
3042 | return nullptr; |
3043 | } |
3044 | arguments.push_back(std::move(converted)); |
3045 | } |
3046 | return this->call(callNode.fOffset, std::move(base), std::move(arguments)); |
3047 | } |
3048 | |
3049 | std::unique_ptr<Expression> IRGenerator::convertFieldExpression(const ASTNode& fieldNode) { |
3050 | std::unique_ptr<Expression> base = this->convertExpression(*fieldNode.begin()); |
3051 | if (!base) { |
3052 | return nullptr; |
3053 | } |
3054 | StringFragment field = fieldNode.getString(); |
3055 | if (base->fType == *fContext.fSkCaps_Type) { |
3056 | return this->getCap(fieldNode.fOffset, field); |
3057 | } |
3058 | if (base->fKind == Expression::kTypeReference_Kind) { |
3059 | return this->convertTypeField(base->fOffset, ((TypeReference&) *base).fValue, |
3060 | field); |
3061 | } |
3062 | if (base->fKind == Expression::kExternalValue_Kind) { |
3063 | return this->convertField(std::move(base), field); |
3064 | } |
3065 | switch (base->fType.kind()) { |
3066 | case Type::kOther_Kind: |
3067 | case Type::kStruct_Kind: |
3068 | return this->convertField(std::move(base), field); |
3069 | default: |
3070 | return this->convertSwizzle(std::move(base), field); |
3071 | } |
3072 | } |
3073 | |
3074 | std::unique_ptr<Expression> IRGenerator::convertPostfixExpression(const ASTNode& expression) { |
3075 | std::unique_ptr<Expression> base = this->convertExpression(*expression.begin()); |
3076 | if (!base) { |
3077 | return nullptr; |
3078 | } |
3079 | if (!base->fType.isNumber()) { |
3080 | fErrors.error(expression.fOffset, |
3081 | "'" + String(Compiler::OperatorName(expression.getToken().fKind)) + |
3082 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
3083 | return nullptr; |
3084 | } |
3085 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
3086 | return std::unique_ptr<Expression>(new PostfixExpression(std::move(base), |
3087 | expression.getToken().fKind)); |
3088 | } |
3089 | |
3090 | void IRGenerator::checkValid(const Expression& expr) { |
3091 | switch (expr.fKind) { |
3092 | case Expression::kFunctionReference_Kind: |
3093 | fErrors.error(expr.fOffset, "expected '(' to begin function call" ); |
3094 | break; |
3095 | case Expression::kTypeReference_Kind: |
3096 | fErrors.error(expr.fOffset, "expected '(' to begin constructor invocation" ); |
3097 | break; |
3098 | default: |
3099 | if (expr.fType == *fContext.fInvalid_Type) { |
3100 | fErrors.error(expr.fOffset, "invalid expression" ); |
3101 | } |
3102 | } |
3103 | } |
3104 | |
3105 | bool IRGenerator::checkSwizzleWrite(const Swizzle& swizzle) { |
3106 | int bits = 0; |
3107 | for (int idx : swizzle.fComponents) { |
3108 | if (idx < 0) { |
3109 | fErrors.error(swizzle.fOffset, "cannot write to a swizzle mask containing a constant" ); |
3110 | return false; |
3111 | } |
3112 | SkASSERT(idx <= 3); |
3113 | int bit = 1 << idx; |
3114 | if (bits & bit) { |
3115 | fErrors.error(swizzle.fOffset, |
3116 | "cannot write to the same swizzle field more than once" ); |
3117 | return false; |
3118 | } |
3119 | bits |= bit; |
3120 | } |
3121 | return true; |
3122 | } |
3123 | |
3124 | bool IRGenerator::setRefKind(const Expression& expr, VariableReference::RefKind kind) { |
3125 | switch (expr.fKind) { |
3126 | case Expression::kVariableReference_Kind: { |
3127 | const Variable& var = ((VariableReference&) expr).fVariable; |
3128 | if (var.fModifiers.fFlags & |
3129 | (Modifiers::kConst_Flag | Modifiers::kUniform_Flag | Modifiers::kVarying_Flag)) { |
3130 | fErrors.error(expr.fOffset, "cannot modify immutable variable '" + var.fName + "'" ); |
3131 | return false; |
3132 | } |
3133 | ((VariableReference&) expr).setRefKind(kind); |
3134 | return true; |
3135 | } |
3136 | case Expression::kFieldAccess_Kind: |
3137 | return this->setRefKind(*((FieldAccess&) expr).fBase, kind); |
3138 | case Expression::kSwizzle_Kind: { |
3139 | const Swizzle& swizzle = (Swizzle&) expr; |
3140 | return this->checkSwizzleWrite(swizzle) && this->setRefKind(*swizzle.fBase, kind); |
3141 | } |
3142 | case Expression::kIndex_Kind: |
3143 | return this->setRefKind(*((IndexExpression&) expr).fBase, kind); |
3144 | case Expression::kTernary_Kind: { |
3145 | TernaryExpression& t = (TernaryExpression&) expr; |
3146 | return this->setRefKind(*t.fIfTrue, kind) && this->setRefKind(*t.fIfFalse, kind); |
3147 | } |
3148 | case Expression::kExternalValue_Kind: { |
3149 | const ExternalValue& v = *((ExternalValueReference&) expr).fValue; |
3150 | if (!v.canWrite()) { |
3151 | fErrors.error(expr.fOffset, |
3152 | "cannot modify immutable external value '" + v.fName + "'" ); |
3153 | return false; |
3154 | } |
3155 | return true; |
3156 | } |
3157 | default: |
3158 | fErrors.error(expr.fOffset, "cannot assign to this expression" ); |
3159 | return false; |
3160 | } |
3161 | } |
3162 | |
3163 | void IRGenerator::convertProgram(Program::Kind kind, |
3164 | const char* text, |
3165 | size_t length, |
3166 | std::vector<std::unique_ptr<ProgramElement>>* out) { |
3167 | fKind = kind; |
3168 | fProgramElements = out; |
3169 | Parser parser(text, length, *fSymbolTable, fErrors); |
3170 | fFile = parser.file(); |
3171 | if (fErrors.errorCount()) { |
3172 | return; |
3173 | } |
3174 | this->pushSymbolTable(); // this is popped by Compiler upon completion |
3175 | SkASSERT(fFile); |
3176 | for (const auto& decl : fFile->root()) { |
3177 | switch (decl.fKind) { |
3178 | case ASTNode::Kind::kVarDeclarations: { |
3179 | std::unique_ptr<VarDeclarations> s = this->convertVarDeclarations( |
3180 | decl, |
3181 | Variable::kGlobal_Storage); |
3182 | if (s) { |
3183 | fProgramElements->push_back(std::move(s)); |
3184 | } |
3185 | break; |
3186 | } |
3187 | case ASTNode::Kind::kEnum: { |
3188 | this->convertEnum(decl); |
3189 | break; |
3190 | } |
3191 | case ASTNode::Kind::kFunction: { |
3192 | this->convertFunction(decl); |
3193 | break; |
3194 | } |
3195 | case ASTNode::Kind::kModifiers: { |
3196 | std::unique_ptr<ModifiersDeclaration> f = this->convertModifiersDeclaration(decl); |
3197 | if (f) { |
3198 | fProgramElements->push_back(std::move(f)); |
3199 | } |
3200 | break; |
3201 | } |
3202 | case ASTNode::Kind::kInterfaceBlock: { |
3203 | std::unique_ptr<InterfaceBlock> i = this->convertInterfaceBlock(decl); |
3204 | if (i) { |
3205 | fProgramElements->push_back(std::move(i)); |
3206 | } |
3207 | break; |
3208 | } |
3209 | case ASTNode::Kind::kExtension: { |
3210 | std::unique_ptr<Extension> e = this->convertExtension(decl.fOffset, |
3211 | decl.getString()); |
3212 | if (e) { |
3213 | fProgramElements->push_back(std::move(e)); |
3214 | } |
3215 | break; |
3216 | } |
3217 | case ASTNode::Kind::kSection: { |
3218 | std::unique_ptr<Section> s = this->convertSection(decl); |
3219 | if (s) { |
3220 | fProgramElements->push_back(std::move(s)); |
3221 | } |
3222 | break; |
3223 | } |
3224 | default: |
3225 | #ifdef SK_DEBUG |
3226 | ABORT("unsupported declaration: %s\n" , decl.description().c_str()); |
3227 | #endif |
3228 | break; |
3229 | } |
3230 | } |
3231 | } |
3232 | |
3233 | |
3234 | } // namespace SkSL |
3235 | |