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 <unordered_set> |
12 | |
13 | #include "src/sksl/SkSLCompiler.h" |
14 | #include "src/sksl/SkSLParser.h" |
15 | #include "src/sksl/ir/SkSLBinaryExpression.h" |
16 | #include "src/sksl/ir/SkSLBoolLiteral.h" |
17 | #include "src/sksl/ir/SkSLBreakStatement.h" |
18 | #include "src/sksl/ir/SkSLConstructor.h" |
19 | #include "src/sksl/ir/SkSLContinueStatement.h" |
20 | #include "src/sksl/ir/SkSLDiscardStatement.h" |
21 | #include "src/sksl/ir/SkSLDoStatement.h" |
22 | #include "src/sksl/ir/SkSLEnum.h" |
23 | #include "src/sksl/ir/SkSLExpressionStatement.h" |
24 | #include "src/sksl/ir/SkSLExternalFunctionCall.h" |
25 | #include "src/sksl/ir/SkSLExternalValueReference.h" |
26 | #include "src/sksl/ir/SkSLField.h" |
27 | #include "src/sksl/ir/SkSLFieldAccess.h" |
28 | #include "src/sksl/ir/SkSLFloatLiteral.h" |
29 | #include "src/sksl/ir/SkSLForStatement.h" |
30 | #include "src/sksl/ir/SkSLFunctionCall.h" |
31 | #include "src/sksl/ir/SkSLFunctionDeclaration.h" |
32 | #include "src/sksl/ir/SkSLFunctionDefinition.h" |
33 | #include "src/sksl/ir/SkSLFunctionReference.h" |
34 | #include "src/sksl/ir/SkSLIfStatement.h" |
35 | #include "src/sksl/ir/SkSLIndexExpression.h" |
36 | #include "src/sksl/ir/SkSLIntLiteral.h" |
37 | #include "src/sksl/ir/SkSLInterfaceBlock.h" |
38 | #include "src/sksl/ir/SkSLLayout.h" |
39 | #include "src/sksl/ir/SkSLNop.h" |
40 | #include "src/sksl/ir/SkSLNullLiteral.h" |
41 | #include "src/sksl/ir/SkSLPostfixExpression.h" |
42 | #include "src/sksl/ir/SkSLPrefixExpression.h" |
43 | #include "src/sksl/ir/SkSLReturnStatement.h" |
44 | #include "src/sksl/ir/SkSLSetting.h" |
45 | #include "src/sksl/ir/SkSLSwitchCase.h" |
46 | #include "src/sksl/ir/SkSLSwitchStatement.h" |
47 | #include "src/sksl/ir/SkSLSwizzle.h" |
48 | #include "src/sksl/ir/SkSLTernaryExpression.h" |
49 | #include "src/sksl/ir/SkSLUnresolvedFunction.h" |
50 | #include "src/sksl/ir/SkSLVarDeclarations.h" |
51 | #include "src/sksl/ir/SkSLVarDeclarationsStatement.h" |
52 | #include "src/sksl/ir/SkSLVariable.h" |
53 | #include "src/sksl/ir/SkSLVariableReference.h" |
54 | #include "src/sksl/ir/SkSLWhileStatement.h" |
55 | |
56 | namespace SkSL { |
57 | |
58 | class AutoSymbolTable { |
59 | public: |
60 | AutoSymbolTable(IRGenerator* ir) |
61 | : fIR(ir) |
62 | , fPrevious(fIR->fSymbolTable) { |
63 | fIR->pushSymbolTable(); |
64 | } |
65 | |
66 | ~AutoSymbolTable() { |
67 | fIR->popSymbolTable(); |
68 | SkASSERT(fPrevious == fIR->fSymbolTable); |
69 | } |
70 | |
71 | IRGenerator* fIR; |
72 | std::shared_ptr<SymbolTable> fPrevious; |
73 | }; |
74 | |
75 | class AutoLoopLevel { |
76 | public: |
77 | AutoLoopLevel(IRGenerator* ir) |
78 | : fIR(ir) { |
79 | fIR->fLoopLevel++; |
80 | } |
81 | |
82 | ~AutoLoopLevel() { |
83 | fIR->fLoopLevel--; |
84 | } |
85 | |
86 | IRGenerator* fIR; |
87 | }; |
88 | |
89 | class AutoSwitchLevel { |
90 | public: |
91 | AutoSwitchLevel(IRGenerator* ir) |
92 | : fIR(ir) { |
93 | fIR->fSwitchLevel++; |
94 | } |
95 | |
96 | ~AutoSwitchLevel() { |
97 | fIR->fSwitchLevel--; |
98 | } |
99 | |
100 | IRGenerator* fIR; |
101 | }; |
102 | |
103 | IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> symbolTable, |
104 | ErrorReporter& errorReporter) |
105 | : fContext(*context) |
106 | , fCurrentFunction(nullptr) |
107 | , fRootSymbolTable(symbolTable) |
108 | , fSymbolTable(symbolTable) |
109 | , fLoopLevel(0) |
110 | , fSwitchLevel(0) |
111 | , fErrors(errorReporter) {} |
112 | |
113 | void IRGenerator::pushSymbolTable() { |
114 | fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable), &fErrors)); |
115 | } |
116 | |
117 | void IRGenerator::popSymbolTable() { |
118 | fSymbolTable = fSymbolTable->fParent; |
119 | } |
120 | |
121 | static void fill_caps(const SKSL_CAPS_CLASS& caps, |
122 | std::unordered_map<String, Program::Settings::Value>* capsMap) { |
123 | #define CAP(name) \ |
124 | capsMap->insert(std::make_pair(String(#name), Program::Settings::Value(caps.name()))) |
125 | CAP(fbFetchSupport); |
126 | CAP(fbFetchNeedsCustomOutput); |
127 | CAP(flatInterpolationSupport); |
128 | CAP(noperspectiveInterpolationSupport); |
129 | CAP(externalTextureSupport); |
130 | CAP(mustEnableAdvBlendEqs); |
131 | CAP(mustEnableSpecificAdvBlendEqs); |
132 | CAP(mustDeclareFragmentShaderOutput); |
133 | CAP(mustDoOpBetweenFloorAndAbs); |
134 | CAP(mustGuardDivisionEvenAfterExplicitZeroCheck); |
135 | CAP(inBlendModesFailRandomlyForAllZeroVec); |
136 | CAP(atan2ImplementedAsAtanYOverX); |
137 | CAP(canUseAnyFunctionInShader); |
138 | CAP(floatIs32Bits); |
139 | CAP(integerSupport); |
140 | #undef CAP |
141 | } |
142 | |
143 | void IRGenerator::start(const Program::Settings* settings, |
144 | std::vector<std::unique_ptr<ProgramElement>>* inherited) { |
145 | fSettings = settings; |
146 | fCapsMap.clear(); |
147 | if (settings->fCaps) { |
148 | fill_caps(*settings->fCaps, &fCapsMap); |
149 | } else { |
150 | fCapsMap.insert(std::make_pair(String("integerSupport" ), |
151 | Program::Settings::Value(true))); |
152 | } |
153 | this->pushSymbolTable(); |
154 | fInvocations = -1; |
155 | fInputs.reset(); |
156 | fSkPerVertex = nullptr; |
157 | fRTAdjust = nullptr; |
158 | fRTAdjustInterfaceBlock = nullptr; |
159 | if (inherited) { |
160 | for (const auto& e : *inherited) { |
161 | if (e->fKind == ProgramElement::kInterfaceBlock_Kind) { |
162 | InterfaceBlock& intf = (InterfaceBlock&) *e; |
163 | if (intf.fVariable.fName == Compiler::PERVERTEX_NAME) { |
164 | SkASSERT(!fSkPerVertex); |
165 | fSkPerVertex = &intf.fVariable; |
166 | } |
167 | } |
168 | } |
169 | } |
170 | SkASSERT(fIntrinsics); |
171 | for (auto& pair : *fIntrinsics) { |
172 | pair.second.second = false; |
173 | } |
174 | } |
175 | |
176 | std::unique_ptr<Extension> IRGenerator::convertExtension(int offset, StringFragment name) { |
177 | return std::unique_ptr<Extension>(new Extension(offset, name)); |
178 | } |
179 | |
180 | void IRGenerator::finish() { |
181 | this->popSymbolTable(); |
182 | fSettings = nullptr; |
183 | } |
184 | |
185 | std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) { |
186 | switch (statement.fKind) { |
187 | case ASTNode::Kind::kBlock: |
188 | return this->convertBlock(statement); |
189 | case ASTNode::Kind::kVarDeclarations: |
190 | return this->convertVarDeclarationStatement(statement); |
191 | case ASTNode::Kind::kIf: |
192 | return this->convertIf(statement); |
193 | case ASTNode::Kind::kFor: |
194 | return this->convertFor(statement); |
195 | case ASTNode::Kind::kWhile: |
196 | return this->convertWhile(statement); |
197 | case ASTNode::Kind::kDo: |
198 | return this->convertDo(statement); |
199 | case ASTNode::Kind::kSwitch: |
200 | return this->convertSwitch(statement); |
201 | case ASTNode::Kind::kReturn: |
202 | return this->convertReturn(statement); |
203 | case ASTNode::Kind::kBreak: |
204 | return this->convertBreak(statement); |
205 | case ASTNode::Kind::kContinue: |
206 | return this->convertContinue(statement); |
207 | case ASTNode::Kind::kDiscard: |
208 | return this->convertDiscard(statement); |
209 | default: |
210 | // it's an expression |
211 | std::unique_ptr<Statement> result = this->convertExpressionStatement(statement); |
212 | if (fRTAdjust && Program::kGeometry_Kind == fKind) { |
213 | SkASSERT(result->fKind == Statement::kExpression_Kind); |
214 | Expression& expr = *((ExpressionStatement&) *result).fExpression; |
215 | if (expr.fKind == Expression::kFunctionCall_Kind) { |
216 | FunctionCall& fc = (FunctionCall&) expr; |
217 | if (fc.fFunction.fBuiltin && fc.fFunction.fName == "EmitVertex" ) { |
218 | std::vector<std::unique_ptr<Statement>> statements; |
219 | statements.push_back(getNormalizeSkPositionCode()); |
220 | statements.push_back(std::move(result)); |
221 | return std::unique_ptr<Block>(new Block(statement.fOffset, |
222 | std::move(statements), |
223 | fSymbolTable)); |
224 | } |
225 | } |
226 | } |
227 | return result; |
228 | } |
229 | } |
230 | |
231 | std::unique_ptr<Block> IRGenerator::convertBlock(const ASTNode& block) { |
232 | SkASSERT(block.fKind == ASTNode::Kind::kBlock); |
233 | AutoSymbolTable table(this); |
234 | std::vector<std::unique_ptr<Statement>> statements; |
235 | for (const auto& child : block) { |
236 | std::unique_ptr<Statement> statement = this->convertStatement(child); |
237 | if (!statement) { |
238 | return nullptr; |
239 | } |
240 | statements.push_back(std::move(statement)); |
241 | } |
242 | return std::unique_ptr<Block>(new Block(block.fOffset, std::move(statements), fSymbolTable)); |
243 | } |
244 | |
245 | std::unique_ptr<Statement> IRGenerator::convertVarDeclarationStatement(const ASTNode& s) { |
246 | SkASSERT(s.fKind == ASTNode::Kind::kVarDeclarations); |
247 | auto decl = this->convertVarDeclarations(s, Variable::kLocal_Storage); |
248 | if (!decl) { |
249 | return nullptr; |
250 | } |
251 | return std::unique_ptr<Statement>(new VarDeclarationsStatement(std::move(decl))); |
252 | } |
253 | |
254 | std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTNode& decls, |
255 | Variable::Storage storage) { |
256 | SkASSERT(decls.fKind == ASTNode::Kind::kVarDeclarations); |
257 | auto iter = decls.begin(); |
258 | const Modifiers& modifiers = iter++->getModifiers(); |
259 | const ASTNode& rawType = *(iter++); |
260 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
261 | const Type* baseType = this->convertType(rawType); |
262 | if (!baseType) { |
263 | return nullptr; |
264 | } |
265 | if (fKind != Program::kFragmentProcessor_Kind) { |
266 | if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
267 | baseType->kind() == Type::Kind::kMatrix_Kind) { |
268 | fErrors.error(decls.fOffset, "'in' variables may not have matrix type" ); |
269 | } |
270 | if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
271 | (modifiers.fFlags & Modifiers::kUniform_Flag)) { |
272 | fErrors.error(decls.fOffset, |
273 | "'in uniform' variables only permitted within fragment processors" ); |
274 | } |
275 | if (modifiers.fLayout.fWhen.fLength) { |
276 | fErrors.error(decls.fOffset, "'when' is only permitted within fragment processors" ); |
277 | } |
278 | if (modifiers.fLayout.fFlags & Layout::kTracked_Flag) { |
279 | fErrors.error(decls.fOffset, "'tracked' is only permitted within fragment processors" ); |
280 | } |
281 | if (modifiers.fLayout.fCType != Layout::CType::kDefault) { |
282 | fErrors.error(decls.fOffset, "'ctype' is only permitted within fragment processors" ); |
283 | } |
284 | if (modifiers.fLayout.fKey) { |
285 | fErrors.error(decls.fOffset, "'key' is only permitted within fragment processors" ); |
286 | } |
287 | } |
288 | if (modifiers.fLayout.fKey && (modifiers.fFlags & Modifiers::kUniform_Flag)) { |
289 | fErrors.error(decls.fOffset, "'key' is not permitted on 'uniform' variables" ); |
290 | } |
291 | if (modifiers.fFlags & Modifiers::kVarying_Flag) { |
292 | if (fKind != Program::kPipelineStage_Kind) { |
293 | fErrors.error(decls.fOffset, "'varying' is only permitted in runtime effects" ); |
294 | } |
295 | if (!baseType->isFloat() && |
296 | !(baseType->kind() == Type::kVector_Kind && baseType->componentType().isFloat())) { |
297 | fErrors.error(decls.fOffset, "'varying' must be float scalar or vector" ); |
298 | } |
299 | } |
300 | for (; iter != decls.end(); ++iter) { |
301 | const ASTNode& varDecl = *iter; |
302 | if (modifiers.fLayout.fLocation == 0 && modifiers.fLayout.fIndex == 0 && |
303 | (modifiers.fFlags & Modifiers::kOut_Flag) && fKind == Program::kFragment_Kind && |
304 | varDecl.getVarData().fName != "sk_FragColor" ) { |
305 | fErrors.error(varDecl.fOffset, |
306 | "out location=0, index=0 is reserved for sk_FragColor" ); |
307 | } |
308 | const ASTNode::VarData& varData = varDecl.getVarData(); |
309 | const Type* type = baseType; |
310 | std::vector<std::unique_ptr<Expression>> sizes; |
311 | auto iter = varDecl.begin(); |
312 | if (varData.fSizeCount > 0 && (modifiers.fFlags & Modifiers::kIn_Flag)) { |
313 | fErrors.error(varDecl.fOffset, "'in' variables may not have array type" ); |
314 | } |
315 | for (size_t i = 0; i < varData.fSizeCount; ++i, ++iter) { |
316 | const ASTNode& rawSize = *iter; |
317 | if (rawSize) { |
318 | auto size = this->coerce(this->convertExpression(rawSize), *fContext.fInt_Type); |
319 | if (!size) { |
320 | return nullptr; |
321 | } |
322 | String name(type->fName); |
323 | int64_t count; |
324 | if (size->fKind == Expression::kIntLiteral_Kind) { |
325 | count = ((IntLiteral&) *size).fValue; |
326 | if (count <= 0) { |
327 | fErrors.error(size->fOffset, "array size must be positive" ); |
328 | return nullptr; |
329 | } |
330 | name += "[" + to_string(count) + "]" ; |
331 | } else { |
332 | fErrors.error(size->fOffset, "array size must be specified" ); |
333 | return nullptr; |
334 | } |
335 | type = (Type*) fSymbolTable->takeOwnership( |
336 | std::unique_ptr<Symbol>(new Type(name, |
337 | Type::kArray_Kind, |
338 | *type, |
339 | (int) count))); |
340 | sizes.push_back(std::move(size)); |
341 | } else { |
342 | type = (Type*) fSymbolTable->takeOwnership( |
343 | std::unique_ptr<Symbol>(new Type(type->name() + "[]" , |
344 | Type::kArray_Kind, |
345 | *type, |
346 | -1))); |
347 | sizes.push_back(nullptr); |
348 | } |
349 | } |
350 | auto var = std::unique_ptr<Variable>(new Variable(varDecl.fOffset, modifiers, |
351 | varData.fName, *type, storage)); |
352 | if (var->fName == Compiler::RTADJUST_NAME) { |
353 | SkASSERT(!fRTAdjust); |
354 | SkASSERT(var->fType == *fContext.fFloat4_Type); |
355 | fRTAdjust = var.get(); |
356 | } |
357 | std::unique_ptr<Expression> value; |
358 | if (iter != varDecl.end()) { |
359 | value = this->convertExpression(*iter); |
360 | if (!value) { |
361 | return nullptr; |
362 | } |
363 | value = this->coerce(std::move(value), *type); |
364 | if (!value) { |
365 | return nullptr; |
366 | } |
367 | var->fWriteCount = 1; |
368 | var->fInitialValue = value.get(); |
369 | } |
370 | if (storage == Variable::kGlobal_Storage && var->fName == "sk_FragColor" && |
371 | (*fSymbolTable)[var->fName]) { |
372 | // already defined, ignore |
373 | } else if (storage == Variable::kGlobal_Storage && (*fSymbolTable)[var->fName] && |
374 | (*fSymbolTable)[var->fName]->fKind == Symbol::kVariable_Kind && |
375 | ((Variable*) (*fSymbolTable)[var->fName])->fModifiers.fLayout.fBuiltin >= 0) { |
376 | // already defined, just update the modifiers |
377 | Variable* old = (Variable*) (*fSymbolTable)[var->fName]; |
378 | old->fModifiers = var->fModifiers; |
379 | } else { |
380 | variables.emplace_back(new VarDeclaration(var.get(), std::move(sizes), |
381 | std::move(value))); |
382 | StringFragment name = var->fName; |
383 | fSymbolTable->add(name, std::move(var)); |
384 | } |
385 | } |
386 | return std::unique_ptr<VarDeclarations>(new VarDeclarations(decls.fOffset, |
387 | baseType, |
388 | std::move(variables))); |
389 | } |
390 | |
391 | std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(const ASTNode& m) { |
392 | SkASSERT(m.fKind == ASTNode::Kind::kModifiers); |
393 | Modifiers modifiers = m.getModifiers(); |
394 | if (modifiers.fLayout.fInvocations != -1) { |
395 | if (fKind != Program::kGeometry_Kind) { |
396 | fErrors.error(m.fOffset, "'invocations' is only legal in geometry shaders" ); |
397 | return nullptr; |
398 | } |
399 | fInvocations = modifiers.fLayout.fInvocations; |
400 | if (fSettings->fCaps && !fSettings->fCaps->gsInvocationsSupport()) { |
401 | modifiers.fLayout.fInvocations = -1; |
402 | Variable* invocationId = (Variable*) (*fSymbolTable)["sk_InvocationID" ]; |
403 | SkASSERT(invocationId); |
404 | invocationId->fModifiers.fFlags = 0; |
405 | invocationId->fModifiers.fLayout.fBuiltin = -1; |
406 | if (modifiers.fLayout.description() == "" ) { |
407 | return nullptr; |
408 | } |
409 | } |
410 | } |
411 | if (modifiers.fLayout.fMaxVertices != -1 && fInvocations > 0 && fSettings->fCaps && |
412 | !fSettings->fCaps->gsInvocationsSupport()) { |
413 | modifiers.fLayout.fMaxVertices *= fInvocations; |
414 | } |
415 | return std::unique_ptr<ModifiersDeclaration>(new ModifiersDeclaration(modifiers)); |
416 | } |
417 | |
418 | std::unique_ptr<Statement> IRGenerator::convertIf(const ASTNode& n) { |
419 | SkASSERT(n.fKind == ASTNode::Kind::kIf); |
420 | auto iter = n.begin(); |
421 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
422 | *fContext.fBool_Type); |
423 | if (!test) { |
424 | return nullptr; |
425 | } |
426 | std::unique_ptr<Statement> ifTrue = this->convertStatement(*(iter++)); |
427 | if (!ifTrue) { |
428 | return nullptr; |
429 | } |
430 | std::unique_ptr<Statement> ifFalse; |
431 | if (iter != n.end()) { |
432 | ifFalse = this->convertStatement(*(iter++)); |
433 | if (!ifFalse) { |
434 | return nullptr; |
435 | } |
436 | } |
437 | if (test->fKind == Expression::kBoolLiteral_Kind) { |
438 | // static boolean value, fold down to a single branch |
439 | if (((BoolLiteral&) *test).fValue) { |
440 | return ifTrue; |
441 | } else if (ifFalse) { |
442 | return ifFalse; |
443 | } else { |
444 | // False & no else clause. Not an error, so don't return null! |
445 | std::vector<std::unique_ptr<Statement>> empty; |
446 | return std::unique_ptr<Statement>(new Block(n.fOffset, std::move(empty), |
447 | fSymbolTable)); |
448 | } |
449 | } |
450 | return std::unique_ptr<Statement>(new IfStatement(n.fOffset, n.getBool(), std::move(test), |
451 | std::move(ifTrue), std::move(ifFalse))); |
452 | } |
453 | |
454 | std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) { |
455 | SkASSERT(f.fKind == ASTNode::Kind::kFor); |
456 | AutoLoopLevel level(this); |
457 | AutoSymbolTable table(this); |
458 | std::unique_ptr<Statement> initializer; |
459 | auto iter = f.begin(); |
460 | if (*iter) { |
461 | initializer = this->convertStatement(*iter); |
462 | if (!initializer) { |
463 | return nullptr; |
464 | } |
465 | } |
466 | ++iter; |
467 | std::unique_ptr<Expression> test; |
468 | if (*iter) { |
469 | test = this->coerce(this->convertExpression(*iter), *fContext.fBool_Type); |
470 | if (!test) { |
471 | return nullptr; |
472 | } |
473 | } |
474 | ++iter; |
475 | std::unique_ptr<Expression> next; |
476 | if (*iter) { |
477 | next = this->convertExpression(*iter); |
478 | if (!next) { |
479 | return nullptr; |
480 | } |
481 | this->checkValid(*next); |
482 | } |
483 | ++iter; |
484 | std::unique_ptr<Statement> statement = this->convertStatement(*iter); |
485 | if (!statement) { |
486 | return nullptr; |
487 | } |
488 | return std::unique_ptr<Statement>(new ForStatement(f.fOffset, std::move(initializer), |
489 | std::move(test), std::move(next), |
490 | std::move(statement), fSymbolTable)); |
491 | } |
492 | |
493 | std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) { |
494 | SkASSERT(w.fKind == ASTNode::Kind::kWhile); |
495 | AutoLoopLevel level(this); |
496 | auto iter = w.begin(); |
497 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
498 | *fContext.fBool_Type); |
499 | if (!test) { |
500 | return nullptr; |
501 | } |
502 | std::unique_ptr<Statement> statement = this->convertStatement(*(iter++)); |
503 | if (!statement) { |
504 | return nullptr; |
505 | } |
506 | return std::unique_ptr<Statement>(new WhileStatement(w.fOffset, std::move(test), |
507 | std::move(statement))); |
508 | } |
509 | |
510 | std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) { |
511 | SkASSERT(d.fKind == ASTNode::Kind::kDo); |
512 | AutoLoopLevel level(this); |
513 | auto iter = d.begin(); |
514 | std::unique_ptr<Statement> statement = this->convertStatement(*(iter++)); |
515 | if (!statement) { |
516 | return nullptr; |
517 | } |
518 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
519 | *fContext.fBool_Type); |
520 | if (!test) { |
521 | return nullptr; |
522 | } |
523 | return std::unique_ptr<Statement>(new DoStatement(d.fOffset, std::move(statement), |
524 | std::move(test))); |
525 | } |
526 | |
527 | std::unique_ptr<Statement> IRGenerator::convertSwitch(const ASTNode& s) { |
528 | SkASSERT(s.fKind == ASTNode::Kind::kSwitch); |
529 | AutoSwitchLevel level(this); |
530 | auto iter = s.begin(); |
531 | std::unique_ptr<Expression> value = this->convertExpression(*(iter++)); |
532 | if (!value) { |
533 | return nullptr; |
534 | } |
535 | if (value->fType != *fContext.fUInt_Type && value->fType.kind() != Type::kEnum_Kind) { |
536 | value = this->coerce(std::move(value), *fContext.fInt_Type); |
537 | if (!value) { |
538 | return nullptr; |
539 | } |
540 | } |
541 | AutoSymbolTable table(this); |
542 | std::unordered_set<int> caseValues; |
543 | std::vector<std::unique_ptr<SwitchCase>> cases; |
544 | for (; iter != s.end(); ++iter) { |
545 | const ASTNode& c = *iter; |
546 | SkASSERT(c.fKind == ASTNode::Kind::kSwitchCase); |
547 | std::unique_ptr<Expression> caseValue; |
548 | auto childIter = c.begin(); |
549 | if (*childIter) { |
550 | caseValue = this->convertExpression(*childIter); |
551 | if (!caseValue) { |
552 | return nullptr; |
553 | } |
554 | caseValue = this->coerce(std::move(caseValue), value->fType); |
555 | if (!caseValue) { |
556 | return nullptr; |
557 | } |
558 | if (!caseValue->isConstant()) { |
559 | fErrors.error(caseValue->fOffset, "case value must be a constant" ); |
560 | return nullptr; |
561 | } |
562 | int64_t v; |
563 | this->getConstantInt(*caseValue, &v); |
564 | if (caseValues.find(v) != caseValues.end()) { |
565 | fErrors.error(caseValue->fOffset, "duplicate case value" ); |
566 | } |
567 | caseValues.insert(v); |
568 | } |
569 | ++childIter; |
570 | std::vector<std::unique_ptr<Statement>> statements; |
571 | for (; childIter != c.end(); ++childIter) { |
572 | std::unique_ptr<Statement> converted = this->convertStatement(*childIter); |
573 | if (!converted) { |
574 | return nullptr; |
575 | } |
576 | statements.push_back(std::move(converted)); |
577 | } |
578 | cases.emplace_back(new SwitchCase(c.fOffset, std::move(caseValue), |
579 | std::move(statements))); |
580 | } |
581 | return std::unique_ptr<Statement>(new SwitchStatement(s.fOffset, s.getBool(), |
582 | std::move(value), std::move(cases), |
583 | fSymbolTable)); |
584 | } |
585 | |
586 | std::unique_ptr<Statement> IRGenerator::convertExpressionStatement(const ASTNode& s) { |
587 | std::unique_ptr<Expression> e = this->convertExpression(s); |
588 | if (!e) { |
589 | return nullptr; |
590 | } |
591 | this->checkValid(*e); |
592 | return std::unique_ptr<Statement>(new ExpressionStatement(std::move(e))); |
593 | } |
594 | |
595 | std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTNode& r) { |
596 | SkASSERT(r.fKind == ASTNode::Kind::kReturn); |
597 | SkASSERT(fCurrentFunction); |
598 | // early returns from a vertex main function will bypass the sk_Position normalization, so |
599 | // SkASSERT that we aren't doing that. It is of course possible to fix this by adding a |
600 | // normalization before each return, but it will probably never actually be necessary. |
601 | SkASSERT(Program::kVertex_Kind != fKind || !fRTAdjust || "main" != fCurrentFunction->fName); |
602 | if (r.begin() != r.end()) { |
603 | std::unique_ptr<Expression> result = this->convertExpression(*r.begin()); |
604 | if (!result) { |
605 | return nullptr; |
606 | } |
607 | if (fCurrentFunction->fReturnType == *fContext.fVoid_Type) { |
608 | fErrors.error(result->fOffset, "may not return a value from a void function" ); |
609 | } else { |
610 | result = this->coerce(std::move(result), fCurrentFunction->fReturnType); |
611 | if (!result) { |
612 | return nullptr; |
613 | } |
614 | } |
615 | return std::unique_ptr<Statement>(new ReturnStatement(std::move(result))); |
616 | } else { |
617 | if (fCurrentFunction->fReturnType != *fContext.fVoid_Type) { |
618 | fErrors.error(r.fOffset, "expected function to return '" + |
619 | fCurrentFunction->fReturnType.displayName() + "'" ); |
620 | } |
621 | return std::unique_ptr<Statement>(new ReturnStatement(r.fOffset)); |
622 | } |
623 | } |
624 | |
625 | std::unique_ptr<Statement> IRGenerator::convertBreak(const ASTNode& b) { |
626 | SkASSERT(b.fKind == ASTNode::Kind::kBreak); |
627 | if (fLoopLevel > 0 || fSwitchLevel > 0) { |
628 | return std::unique_ptr<Statement>(new BreakStatement(b.fOffset)); |
629 | } else { |
630 | fErrors.error(b.fOffset, "break statement must be inside a loop or switch" ); |
631 | return nullptr; |
632 | } |
633 | } |
634 | |
635 | std::unique_ptr<Statement> IRGenerator::convertContinue(const ASTNode& c) { |
636 | SkASSERT(c.fKind == ASTNode::Kind::kContinue); |
637 | if (fLoopLevel > 0) { |
638 | return std::unique_ptr<Statement>(new ContinueStatement(c.fOffset)); |
639 | } else { |
640 | fErrors.error(c.fOffset, "continue statement must be inside a loop" ); |
641 | return nullptr; |
642 | } |
643 | } |
644 | |
645 | std::unique_ptr<Statement> IRGenerator::convertDiscard(const ASTNode& d) { |
646 | SkASSERT(d.fKind == ASTNode::Kind::kDiscard); |
647 | return std::unique_ptr<Statement>(new DiscardStatement(d.fOffset)); |
648 | } |
649 | |
650 | std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<Block> main) { |
651 | Layout invokeLayout; |
652 | Modifiers invokeModifiers(invokeLayout, Modifiers::kHasSideEffects_Flag); |
653 | FunctionDeclaration* invokeDecl = new FunctionDeclaration(-1, |
654 | invokeModifiers, |
655 | "_invoke" , |
656 | std::vector<const Variable*>(), |
657 | *fContext.fVoid_Type); |
658 | fProgramElements->push_back(std::unique_ptr<ProgramElement>( |
659 | new FunctionDefinition(-1, *invokeDecl, std::move(main)))); |
660 | fSymbolTable->add(invokeDecl->fName, std::unique_ptr<FunctionDeclaration>(invokeDecl)); |
661 | |
662 | std::vector<std::unique_ptr<VarDeclaration>> variables; |
663 | Variable* loopIdx = (Variable*) (*fSymbolTable)["sk_InvocationID" ]; |
664 | SkASSERT(loopIdx); |
665 | std::unique_ptr<Expression> test(new BinaryExpression(-1, |
666 | std::unique_ptr<Expression>(new VariableReference(-1, *loopIdx)), |
667 | Token::LT, |
668 | std::unique_ptr<IntLiteral>(new IntLiteral(fContext, -1, fInvocations)), |
669 | *fContext.fBool_Type)); |
670 | std::unique_ptr<Expression> next(new PostfixExpression( |
671 | std::unique_ptr<Expression>( |
672 | new VariableReference(-1, |
673 | *loopIdx, |
674 | VariableReference::kReadWrite_RefKind)), |
675 | Token::PLUSPLUS)); |
676 | ASTNode endPrimitiveID(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, "EndPrimitive" ); |
677 | std::unique_ptr<Expression> endPrimitive = this->convertExpression(endPrimitiveID); |
678 | SkASSERT(endPrimitive); |
679 | |
680 | std::vector<std::unique_ptr<Statement>> loopBody; |
681 | std::vector<std::unique_ptr<Expression>> invokeArgs; |
682 | loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement( |
683 | this->call(-1, |
684 | *invokeDecl, |
685 | std::vector<std::unique_ptr<Expression>>())))); |
686 | loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement( |
687 | this->call(-1, |
688 | std::move(endPrimitive), |
689 | std::vector<std::unique_ptr<Expression>>())))); |
690 | std::unique_ptr<Expression> assignment(new BinaryExpression(-1, |
691 | std::unique_ptr<Expression>(new VariableReference(-1, *loopIdx)), |
692 | Token::EQ, |
693 | std::unique_ptr<IntLiteral>(new IntLiteral(fContext, -1, 0)), |
694 | *fContext.fInt_Type)); |
695 | std::unique_ptr<Statement> initializer(new ExpressionStatement(std::move(assignment))); |
696 | std::unique_ptr<Statement> loop = std::unique_ptr<Statement>( |
697 | new ForStatement(-1, |
698 | std::move(initializer), |
699 | std::move(test), |
700 | std::move(next), |
701 | std::unique_ptr<Block>(new Block(-1, std::move(loopBody))), |
702 | fSymbolTable)); |
703 | std::vector<std::unique_ptr<Statement>> children; |
704 | children.push_back(std::move(loop)); |
705 | return std::unique_ptr<Block>(new Block(-1, std::move(children))); |
706 | } |
707 | |
708 | std::unique_ptr<Statement> IRGenerator::getNormalizeSkPositionCode() { |
709 | // sk_Position = float4(sk_Position.xy * rtAdjust.xz + sk_Position.ww * rtAdjust.yw, |
710 | // 0, |
711 | // sk_Position.w); |
712 | SkASSERT(fSkPerVertex && fRTAdjust); |
713 | #define REF(var) std::unique_ptr<Expression>(\ |
714 | new VariableReference(-1, *var, VariableReference::kRead_RefKind)) |
715 | #define FIELD(var, idx) std::unique_ptr<Expression>(\ |
716 | new FieldAccess(REF(var), idx, FieldAccess::kAnonymousInterfaceBlock_OwnerKind)) |
717 | #define POS std::unique_ptr<Expression>(new FieldAccess(REF(fSkPerVertex), 0, \ |
718 | FieldAccess::kAnonymousInterfaceBlock_OwnerKind)) |
719 | #define ADJUST (fRTAdjustInterfaceBlock ? \ |
720 | FIELD(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex) : \ |
721 | REF(fRTAdjust)) |
722 | #define SWIZZLE(expr, ...) std::unique_ptr<Expression>(new Swizzle(fContext, expr, \ |
723 | { __VA_ARGS__ })) |
724 | #define OP(left, op, right) std::unique_ptr<Expression>( \ |
725 | new BinaryExpression(-1, left, op, right, \ |
726 | *fContext.fFloat2_Type)) |
727 | std::vector<std::unique_ptr<Expression>> children; |
728 | children.push_back(OP(OP(SWIZZLE(POS, 0, 1), Token::STAR, SWIZZLE(ADJUST, 0, 2)), |
729 | Token::PLUS, |
730 | OP(SWIZZLE(POS, 3, 3), Token::STAR, SWIZZLE(ADJUST, 1, 3)))); |
731 | children.push_back(std::unique_ptr<Expression>(new FloatLiteral(fContext, -1, 0.0))); |
732 | children.push_back(SWIZZLE(POS, 3)); |
733 | std::unique_ptr<Expression> result = OP(POS, Token::EQ, |
734 | std::unique_ptr<Expression>(new Constructor(-1, |
735 | *fContext.fFloat4_Type, |
736 | std::move(children)))); |
737 | return std::unique_ptr<Statement>(new ExpressionStatement(std::move(result))); |
738 | } |
739 | |
740 | void IRGenerator::convertFunction(const ASTNode& f) { |
741 | auto iter = f.begin(); |
742 | const Type* returnType = this->convertType(*(iter++)); |
743 | if (!returnType) { |
744 | return; |
745 | } |
746 | const ASTNode::FunctionData& fd = f.getFunctionData(); |
747 | std::vector<const Variable*> parameters; |
748 | for (size_t i = 0; i < fd.fParameterCount; ++i) { |
749 | const ASTNode& param = *(iter++); |
750 | SkASSERT(param.fKind == ASTNode::Kind::kParameter); |
751 | ASTNode::ParameterData pd = param.getParameterData(); |
752 | auto paramIter = param.begin(); |
753 | const Type* type = this->convertType(*(paramIter++)); |
754 | if (!type) { |
755 | return; |
756 | } |
757 | for (int j = (int) pd.fSizeCount; j >= 1; j--) { |
758 | int size = (param.begin() + j)->getInt(); |
759 | String name = type->name() + "[" + to_string(size) + "]" ; |
760 | type = (Type*) fSymbolTable->takeOwnership( |
761 | std::unique_ptr<Symbol>(new Type(std::move(name), |
762 | Type::kArray_Kind, |
763 | *type, |
764 | size))); |
765 | } |
766 | StringFragment name = pd.fName; |
767 | Variable* var = (Variable*) fSymbolTable->takeOwnership( |
768 | std::unique_ptr<Symbol>(new Variable(param.fOffset, |
769 | pd.fModifiers, |
770 | name, |
771 | *type, |
772 | Variable::kParameter_Storage))); |
773 | parameters.push_back(var); |
774 | } |
775 | |
776 | if (fd.fName == "main" ) { |
777 | switch (fKind) { |
778 | case Program::kPipelineStage_Kind: { |
779 | bool valid; |
780 | switch (parameters.size()) { |
781 | case 2: |
782 | valid = parameters[0]->fType == *fContext.fFloat2_Type && |
783 | parameters[0]->fModifiers.fFlags == 0 && |
784 | parameters[1]->fType == *fContext.fHalf4_Type && |
785 | parameters[1]->fModifiers.fFlags == (Modifiers::kIn_Flag | |
786 | Modifiers::kOut_Flag); |
787 | break; |
788 | case 1: |
789 | valid = parameters[0]->fType == *fContext.fHalf4_Type && |
790 | parameters[0]->fModifiers.fFlags == (Modifiers::kIn_Flag | |
791 | Modifiers::kOut_Flag); |
792 | break; |
793 | default: |
794 | valid = false; |
795 | } |
796 | if (!valid) { |
797 | fErrors.error(f.fOffset, "pipeline stage 'main' must be declared main(float2, " |
798 | "inout half4) or main(inout half4)" ); |
799 | return; |
800 | } |
801 | break; |
802 | } |
803 | case Program::kGeneric_Kind: |
804 | break; |
805 | default: |
806 | if (parameters.size()) { |
807 | fErrors.error(f.fOffset, "shader 'main' must have zero parameters" ); |
808 | } |
809 | } |
810 | } |
811 | |
812 | // find existing declaration |
813 | const FunctionDeclaration* decl = nullptr; |
814 | auto entry = (*fSymbolTable)[fd.fName]; |
815 | if (entry) { |
816 | std::vector<const FunctionDeclaration*> functions; |
817 | switch (entry->fKind) { |
818 | case Symbol::kUnresolvedFunction_Kind: |
819 | functions = ((UnresolvedFunction*) entry)->fFunctions; |
820 | break; |
821 | case Symbol::kFunctionDeclaration_Kind: |
822 | functions.push_back((FunctionDeclaration*) entry); |
823 | break; |
824 | default: |
825 | fErrors.error(f.fOffset, "symbol '" + fd.fName + "' was already defined" ); |
826 | return; |
827 | } |
828 | for (const auto& other : functions) { |
829 | SkASSERT(other->fName == fd.fName); |
830 | if (parameters.size() == other->fParameters.size()) { |
831 | bool match = true; |
832 | for (size_t i = 0; i < parameters.size(); i++) { |
833 | if (parameters[i]->fType != other->fParameters[i]->fType) { |
834 | match = false; |
835 | break; |
836 | } |
837 | } |
838 | if (match) { |
839 | if (*returnType != other->fReturnType) { |
840 | FunctionDeclaration newDecl(f.fOffset, fd.fModifiers, fd.fName, parameters, |
841 | *returnType); |
842 | fErrors.error(f.fOffset, "functions '" + newDecl.declaration() + |
843 | "' and '" + other->declaration() + |
844 | "' differ only in return type" ); |
845 | return; |
846 | } |
847 | decl = other; |
848 | for (size_t i = 0; i < parameters.size(); i++) { |
849 | if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) { |
850 | fErrors.error(f.fOffset, "modifiers on parameter " + |
851 | to_string((uint64_t) i + 1) + |
852 | " differ between declaration and " |
853 | "definition" ); |
854 | return; |
855 | } |
856 | } |
857 | if (other->fDefined && !other->fBuiltin) { |
858 | fErrors.error(f.fOffset, "duplicate definition of " + |
859 | other->declaration()); |
860 | } |
861 | break; |
862 | } |
863 | } |
864 | } |
865 | } |
866 | if (!decl) { |
867 | // couldn't find an existing declaration |
868 | auto newDecl = std::unique_ptr<FunctionDeclaration>(new FunctionDeclaration(f.fOffset, |
869 | fd.fModifiers, |
870 | fd.fName, |
871 | parameters, |
872 | *returnType)); |
873 | decl = newDecl.get(); |
874 | fSymbolTable->add(decl->fName, std::move(newDecl)); |
875 | } |
876 | if (iter != f.end()) { |
877 | // compile body |
878 | SkASSERT(!fCurrentFunction); |
879 | fCurrentFunction = decl; |
880 | decl->fDefined = true; |
881 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
882 | AutoSymbolTable table(this); |
883 | if (fd.fName == "main" && fKind == Program::kPipelineStage_Kind) { |
884 | if (parameters.size() == 2) { |
885 | parameters[0]->fModifiers.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN; |
886 | parameters[1]->fModifiers.fLayout.fBuiltin = SK_OUTCOLOR_BUILTIN; |
887 | } else { |
888 | SkASSERT(parameters.size() == 1); |
889 | parameters[0]->fModifiers.fLayout.fBuiltin = SK_OUTCOLOR_BUILTIN; |
890 | } |
891 | } |
892 | for (size_t i = 0; i < parameters.size(); i++) { |
893 | fSymbolTable->addWithoutOwnership(parameters[i]->fName, decl->fParameters[i]); |
894 | } |
895 | bool needInvocationIDWorkaround = fInvocations != -1 && fd.fName == "main" && |
896 | fSettings->fCaps && |
897 | !fSettings->fCaps->gsInvocationsSupport(); |
898 | std::unique_ptr<Block> body = this->convertBlock(*iter); |
899 | fCurrentFunction = nullptr; |
900 | if (!body) { |
901 | return; |
902 | } |
903 | if (needInvocationIDWorkaround) { |
904 | body = this->applyInvocationIDWorkaround(std::move(body)); |
905 | } |
906 | // conservatively assume all user-defined functions have side effects |
907 | ((Modifiers&) decl->fModifiers).fFlags |= Modifiers::kHasSideEffects_Flag; |
908 | if (Program::kVertex_Kind == fKind && fd.fName == "main" && fRTAdjust) { |
909 | body->fStatements.insert(body->fStatements.end(), this->getNormalizeSkPositionCode()); |
910 | } |
911 | std::unique_ptr<FunctionDefinition> result(new FunctionDefinition(f.fOffset, *decl, |
912 | std::move(body))); |
913 | result->fSource = &f; |
914 | fProgramElements->push_back(std::move(result)); |
915 | } |
916 | } |
917 | |
918 | std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTNode& intf) { |
919 | SkASSERT(intf.fKind == ASTNode::Kind::kInterfaceBlock); |
920 | ASTNode::InterfaceBlockData id = intf.getInterfaceBlockData(); |
921 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
922 | this->pushSymbolTable(); |
923 | std::shared_ptr<SymbolTable> symbols = fSymbolTable; |
924 | std::vector<Type::Field> fields; |
925 | bool haveRuntimeArray = false; |
926 | bool foundRTAdjust = false; |
927 | auto iter = intf.begin(); |
928 | for (size_t i = 0; i < id.fDeclarationCount; ++i) { |
929 | std::unique_ptr<VarDeclarations> decl = this->convertVarDeclarations( |
930 | *(iter++), |
931 | Variable::kInterfaceBlock_Storage); |
932 | if (!decl) { |
933 | return nullptr; |
934 | } |
935 | for (const auto& stmt : decl->fVars) { |
936 | VarDeclaration& vd = (VarDeclaration&) *stmt; |
937 | if (haveRuntimeArray) { |
938 | fErrors.error(decl->fOffset, |
939 | "only the last entry in an interface block may be a runtime-sized " |
940 | "array" ); |
941 | } |
942 | if (vd.fVar == fRTAdjust) { |
943 | foundRTAdjust = true; |
944 | SkASSERT(vd.fVar->fType == *fContext.fFloat4_Type); |
945 | fRTAdjustFieldIndex = fields.size(); |
946 | } |
947 | fields.push_back(Type::Field(vd.fVar->fModifiers, vd.fVar->fName, |
948 | &vd.fVar->fType)); |
949 | if (vd.fValue) { |
950 | fErrors.error(decl->fOffset, |
951 | "initializers are not permitted on interface block fields" ); |
952 | } |
953 | if (vd.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | |
954 | Modifiers::kOut_Flag | |
955 | Modifiers::kUniform_Flag | |
956 | Modifiers::kBuffer_Flag | |
957 | Modifiers::kConst_Flag)) { |
958 | fErrors.error(decl->fOffset, |
959 | "interface block fields may not have storage qualifiers" ); |
960 | } |
961 | if (vd.fVar->fType.kind() == Type::kArray_Kind && |
962 | vd.fVar->fType.columns() == -1) { |
963 | haveRuntimeArray = true; |
964 | } |
965 | } |
966 | } |
967 | this->popSymbolTable(); |
968 | Type* type = (Type*) old->takeOwnership(std::unique_ptr<Symbol>(new Type(intf.fOffset, |
969 | id.fTypeName, |
970 | fields))); |
971 | std::vector<std::unique_ptr<Expression>> sizes; |
972 | for (size_t i = 0; i < id.fSizeCount; ++i) { |
973 | const ASTNode& size = *(iter++); |
974 | if (size) { |
975 | std::unique_ptr<Expression> converted = this->convertExpression(size); |
976 | if (!converted) { |
977 | return nullptr; |
978 | } |
979 | String name = type->fName; |
980 | int64_t count; |
981 | if (converted->fKind == Expression::kIntLiteral_Kind) { |
982 | count = ((IntLiteral&) *converted).fValue; |
983 | if (count <= 0) { |
984 | fErrors.error(converted->fOffset, "array size must be positive" ); |
985 | return nullptr; |
986 | } |
987 | name += "[" + to_string(count) + "]" ; |
988 | } else { |
989 | fErrors.error(intf.fOffset, "array size must be specified" ); |
990 | return nullptr; |
991 | } |
992 | type = (Type*) symbols->takeOwnership(std::unique_ptr<Symbol>( |
993 | new Type(name, |
994 | Type::kArray_Kind, |
995 | *type, |
996 | (int) count))); |
997 | sizes.push_back(std::move(converted)); |
998 | } else { |
999 | fErrors.error(intf.fOffset, "array size must be specified" ); |
1000 | return nullptr; |
1001 | } |
1002 | } |
1003 | Variable* var = (Variable*) old->takeOwnership(std::unique_ptr<Symbol>( |
1004 | new Variable(intf.fOffset, |
1005 | id.fModifiers, |
1006 | id.fInstanceName.fLength ? id.fInstanceName : id.fTypeName, |
1007 | *type, |
1008 | Variable::kGlobal_Storage))); |
1009 | if (foundRTAdjust) { |
1010 | fRTAdjustInterfaceBlock = var; |
1011 | } |
1012 | if (id.fInstanceName.fLength) { |
1013 | old->addWithoutOwnership(id.fInstanceName, var); |
1014 | } else { |
1015 | for (size_t i = 0; i < fields.size(); i++) { |
1016 | old->add(fields[i].fName, std::unique_ptr<Field>(new Field(intf.fOffset, *var, |
1017 | (int) i))); |
1018 | } |
1019 | } |
1020 | return std::unique_ptr<InterfaceBlock>(new InterfaceBlock(intf.fOffset, |
1021 | var, |
1022 | id.fTypeName, |
1023 | id.fInstanceName, |
1024 | std::move(sizes), |
1025 | symbols)); |
1026 | } |
1027 | |
1028 | void IRGenerator::getConstantInt(const Expression& value, int64_t* out) { |
1029 | switch (value.fKind) { |
1030 | case Expression::kIntLiteral_Kind: |
1031 | *out = ((const IntLiteral&) value).fValue; |
1032 | break; |
1033 | case Expression::kVariableReference_Kind: { |
1034 | const Variable& var = ((VariableReference&) value).fVariable; |
1035 | if ((var.fModifiers.fFlags & Modifiers::kConst_Flag) && |
1036 | var.fInitialValue) { |
1037 | this->getConstantInt(*var.fInitialValue, out); |
1038 | } |
1039 | break; |
1040 | } |
1041 | default: |
1042 | fErrors.error(value.fOffset, "expected a constant int" ); |
1043 | } |
1044 | } |
1045 | |
1046 | void IRGenerator::convertEnum(const ASTNode& e) { |
1047 | SkASSERT(e.fKind == ASTNode::Kind::kEnum); |
1048 | std::vector<Variable*> variables; |
1049 | int64_t currentValue = 0; |
1050 | Layout layout; |
1051 | ASTNode enumType(e.fNodes, e.fOffset, ASTNode::Kind::kType, |
1052 | ASTNode::TypeData(e.getString(), false, false)); |
1053 | const Type* type = this->convertType(enumType); |
1054 | Modifiers modifiers(layout, Modifiers::kConst_Flag); |
1055 | std::shared_ptr<SymbolTable> symbols(new SymbolTable(fSymbolTable, &fErrors)); |
1056 | fSymbolTable = symbols; |
1057 | for (auto iter = e.begin(); iter != e.end(); ++iter) { |
1058 | const ASTNode& child = *iter; |
1059 | SkASSERT(child.fKind == ASTNode::Kind::kEnumCase); |
1060 | std::unique_ptr<Expression> value; |
1061 | if (child.begin() != child.end()) { |
1062 | value = this->convertExpression(*child.begin()); |
1063 | if (!value) { |
1064 | fSymbolTable = symbols->fParent; |
1065 | return; |
1066 | } |
1067 | this->getConstantInt(*value, ¤tValue); |
1068 | } |
1069 | value = std::unique_ptr<Expression>(new IntLiteral(fContext, e.fOffset, currentValue)); |
1070 | ++currentValue; |
1071 | auto var = std::unique_ptr<Variable>(new Variable(e.fOffset, modifiers, child.getString(), |
1072 | *type, Variable::kGlobal_Storage, |
1073 | value.get())); |
1074 | variables.push_back(var.get()); |
1075 | symbols->add(child.getString(), std::move(var)); |
1076 | symbols->takeOwnership(std::move(value)); |
1077 | } |
1078 | fProgramElements->push_back(std::unique_ptr<ProgramElement>(new Enum(e.fOffset, e.getString(), |
1079 | symbols))); |
1080 | fSymbolTable = symbols->fParent; |
1081 | } |
1082 | |
1083 | const Type* IRGenerator::convertType(const ASTNode& type) { |
1084 | ASTNode::TypeData td = type.getTypeData(); |
1085 | const Symbol* result = (*fSymbolTable)[td.fName]; |
1086 | if (result && result->fKind == Symbol::kType_Kind) { |
1087 | if (td.fIsNullable) { |
1088 | if (((Type&) *result) == *fContext.fFragmentProcessor_Type) { |
1089 | if (type.begin() != type.end()) { |
1090 | fErrors.error(type.fOffset, "type '" + td.fName + "' may not be used in " |
1091 | "an array" ); |
1092 | } |
1093 | result = fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( |
1094 | new Type(String(result->fName) + "?" , |
1095 | Type::kNullable_Kind, |
1096 | (const Type&) *result))); |
1097 | } else { |
1098 | fErrors.error(type.fOffset, "type '" + td.fName + "' may not be nullable" ); |
1099 | } |
1100 | } |
1101 | for (const auto& size : type) { |
1102 | String name(result->fName); |
1103 | name += "[" ; |
1104 | if (size) { |
1105 | name += to_string(size.getInt()); |
1106 | } |
1107 | name += "]" ; |
1108 | result = (Type*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( |
1109 | new Type(name, |
1110 | Type::kArray_Kind, |
1111 | (const Type&) *result, |
1112 | size ? size.getInt() |
1113 | : 0))); |
1114 | } |
1115 | return (const Type*) result; |
1116 | } |
1117 | fErrors.error(type.fOffset, "unknown type '" + td.fName + "'" ); |
1118 | return nullptr; |
1119 | } |
1120 | |
1121 | std::unique_ptr<Expression> IRGenerator::convertExpression(const ASTNode& expr) { |
1122 | switch (expr.fKind) { |
1123 | case ASTNode::Kind::kBinary: |
1124 | return this->convertBinaryExpression(expr); |
1125 | case ASTNode::Kind::kBool: |
1126 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, expr.fOffset, |
1127 | expr.getBool())); |
1128 | case ASTNode::Kind::kCall: |
1129 | return this->convertCallExpression(expr); |
1130 | case ASTNode::Kind::kField: |
1131 | return this->convertFieldExpression(expr); |
1132 | case ASTNode::Kind::kFloat: |
1133 | return std::unique_ptr<Expression>(new FloatLiteral(fContext, expr.fOffset, |
1134 | expr.getFloat())); |
1135 | case ASTNode::Kind::kIdentifier: |
1136 | return this->convertIdentifier(expr); |
1137 | case ASTNode::Kind::kIndex: |
1138 | return this->convertIndexExpression(expr); |
1139 | case ASTNode::Kind::kInt: |
1140 | return std::unique_ptr<Expression>(new IntLiteral(fContext, expr.fOffset, |
1141 | expr.getInt())); |
1142 | case ASTNode::Kind::kNull: |
1143 | return std::unique_ptr<Expression>(new NullLiteral(fContext, expr.fOffset)); |
1144 | case ASTNode::Kind::kPostfix: |
1145 | return this->convertPostfixExpression(expr); |
1146 | case ASTNode::Kind::kPrefix: |
1147 | return this->convertPrefixExpression(expr); |
1148 | case ASTNode::Kind::kTernary: |
1149 | return this->convertTernaryExpression(expr); |
1150 | default: |
1151 | #ifdef SK_DEBUG |
1152 | ABORT("unsupported expression: %s\n" , expr.description().c_str()); |
1153 | #endif |
1154 | return nullptr; |
1155 | } |
1156 | } |
1157 | |
1158 | std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identifier) { |
1159 | SkASSERT(identifier.fKind == ASTNode::Kind::kIdentifier); |
1160 | const Symbol* result = (*fSymbolTable)[identifier.getString()]; |
1161 | if (!result) { |
1162 | fErrors.error(identifier.fOffset, "unknown identifier '" + identifier.getString() + "'" ); |
1163 | return nullptr; |
1164 | } |
1165 | switch (result->fKind) { |
1166 | case Symbol::kFunctionDeclaration_Kind: { |
1167 | std::vector<const FunctionDeclaration*> f = { |
1168 | (const FunctionDeclaration*) result |
1169 | }; |
1170 | return std::unique_ptr<FunctionReference>(new FunctionReference(fContext, |
1171 | identifier.fOffset, |
1172 | f)); |
1173 | } |
1174 | case Symbol::kUnresolvedFunction_Kind: { |
1175 | const UnresolvedFunction* f = (const UnresolvedFunction*) result; |
1176 | return std::unique_ptr<FunctionReference>(new FunctionReference(fContext, |
1177 | identifier.fOffset, |
1178 | f->fFunctions)); |
1179 | } |
1180 | case Symbol::kVariable_Kind: { |
1181 | const Variable* var = (const Variable*) result; |
1182 | switch (var->fModifiers.fLayout.fBuiltin) { |
1183 | case SK_WIDTH_BUILTIN: |
1184 | fInputs.fRTWidth = true; |
1185 | break; |
1186 | case SK_HEIGHT_BUILTIN: |
1187 | fInputs.fRTHeight = true; |
1188 | break; |
1189 | #ifndef SKSL_STANDALONE |
1190 | case SK_FRAGCOORD_BUILTIN: |
1191 | fInputs.fFlipY = true; |
1192 | if (fSettings->fFlipY && |
1193 | (!fSettings->fCaps || |
1194 | !fSettings->fCaps->fragCoordConventionsExtensionString())) { |
1195 | fInputs.fRTHeight = true; |
1196 | } |
1197 | #endif |
1198 | } |
1199 | if (fKind == Program::kFragmentProcessor_Kind && |
1200 | (var->fModifiers.fFlags & Modifiers::kIn_Flag) && |
1201 | !(var->fModifiers.fFlags & Modifiers::kUniform_Flag) && |
1202 | !var->fModifiers.fLayout.fKey && |
1203 | var->fModifiers.fLayout.fBuiltin == -1 && |
1204 | var->fType.nonnullable() != *fContext.fFragmentProcessor_Type && |
1205 | var->fType.kind() != Type::kSampler_Kind) { |
1206 | bool valid = false; |
1207 | for (const auto& decl : fFile->root()) { |
1208 | if (decl.fKind == ASTNode::Kind::kSection) { |
1209 | ASTNode::SectionData section = decl.getSectionData(); |
1210 | if (section.fName == "setData" ) { |
1211 | valid = true; |
1212 | break; |
1213 | } |
1214 | } |
1215 | } |
1216 | if (!valid) { |
1217 | fErrors.error(identifier.fOffset, "'in' variable must be either 'uniform' or " |
1218 | "'layout(key)', or there must be a custom " |
1219 | "@setData function" ); |
1220 | } |
1221 | } |
1222 | // default to kRead_RefKind; this will be corrected later if the variable is written to |
1223 | return std::unique_ptr<VariableReference>(new VariableReference( |
1224 | identifier.fOffset, |
1225 | *var, |
1226 | VariableReference::kRead_RefKind)); |
1227 | } |
1228 | case Symbol::kField_Kind: { |
1229 | const Field* field = (const Field*) result; |
1230 | VariableReference* base = new VariableReference(identifier.fOffset, field->fOwner, |
1231 | VariableReference::kRead_RefKind); |
1232 | return std::unique_ptr<Expression>(new FieldAccess( |
1233 | std::unique_ptr<Expression>(base), |
1234 | field->fFieldIndex, |
1235 | FieldAccess::kAnonymousInterfaceBlock_OwnerKind)); |
1236 | } |
1237 | case Symbol::kType_Kind: { |
1238 | const Type* t = (const Type*) result; |
1239 | return std::unique_ptr<TypeReference>(new TypeReference(fContext, identifier.fOffset, |
1240 | *t)); |
1241 | } |
1242 | case Symbol::kExternal_Kind: { |
1243 | ExternalValue* r = (ExternalValue*) result; |
1244 | return std::unique_ptr<ExternalValueReference>( |
1245 | new ExternalValueReference(identifier.fOffset, r)); |
1246 | } |
1247 | default: |
1248 | ABORT("unsupported symbol type %d\n" , result->fKind); |
1249 | } |
1250 | } |
1251 | |
1252 | std::unique_ptr<Section> IRGenerator::convertSection(const ASTNode& s) { |
1253 | ASTNode::SectionData section = s.getSectionData(); |
1254 | return std::unique_ptr<Section>(new Section(s.fOffset, section.fName, section.fArgument, |
1255 | section.fText)); |
1256 | } |
1257 | |
1258 | |
1259 | std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr, |
1260 | const Type& type) { |
1261 | if (!expr) { |
1262 | return nullptr; |
1263 | } |
1264 | if (expr->fType == type) { |
1265 | return expr; |
1266 | } |
1267 | this->checkValid(*expr); |
1268 | if (expr->fType == *fContext.fInvalid_Type) { |
1269 | return nullptr; |
1270 | } |
1271 | if (expr->coercionCost(type) == INT_MAX) { |
1272 | fErrors.error(expr->fOffset, "expected '" + type.displayName() + "', but found '" + |
1273 | expr->fType.displayName() + "'" ); |
1274 | return nullptr; |
1275 | } |
1276 | if (type.kind() == Type::kScalar_Kind) { |
1277 | std::vector<std::unique_ptr<Expression>> args; |
1278 | args.push_back(std::move(expr)); |
1279 | std::unique_ptr<Expression> ctor; |
1280 | if (type == *fContext.fFloatLiteral_Type) { |
1281 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1282 | "float" )); |
1283 | } else if (type == *fContext.fIntLiteral_Type) { |
1284 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1285 | "int" )); |
1286 | } else { |
1287 | ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, |
1288 | type.fName)); |
1289 | } |
1290 | if (!ctor) { |
1291 | printf("error, null identifier: %s\n" , String(type.fName).c_str()); |
1292 | } |
1293 | SkASSERT(ctor); |
1294 | return this->call(-1, std::move(ctor), std::move(args)); |
1295 | } |
1296 | if (expr->fKind == Expression::kNullLiteral_Kind) { |
1297 | SkASSERT(type.kind() == Type::kNullable_Kind); |
1298 | return std::unique_ptr<Expression>(new NullLiteral(expr->fOffset, type)); |
1299 | } |
1300 | std::vector<std::unique_ptr<Expression>> args; |
1301 | args.push_back(std::move(expr)); |
1302 | return std::unique_ptr<Expression>(new Constructor(-1, type, std::move(args))); |
1303 | } |
1304 | |
1305 | static bool is_matrix_multiply(const Type& left, const Type& right) { |
1306 | if (left.kind() == Type::kMatrix_Kind) { |
1307 | return right.kind() == Type::kMatrix_Kind || right.kind() == Type::kVector_Kind; |
1308 | } |
1309 | return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind; |
1310 | } |
1311 | |
1312 | /** |
1313 | * Determines the operand and result types of a binary expression. Returns true if the expression is |
1314 | * legal, false otherwise. If false, the values of the out parameters are undefined. |
1315 | */ |
1316 | static bool determine_binary_type(const Context& context, |
1317 | Token::Kind op, |
1318 | const Type& left, |
1319 | const Type& right, |
1320 | const Type** outLeftType, |
1321 | const Type** outRightType, |
1322 | const Type** outResultType, |
1323 | bool tryFlipped) { |
1324 | bool isLogical; |
1325 | bool validMatrixOrVectorOp; |
1326 | switch (op) { |
1327 | case Token::EQ: |
1328 | *outLeftType = &left; |
1329 | *outRightType = &left; |
1330 | *outResultType = &left; |
1331 | return right.canCoerceTo(left); |
1332 | case Token::EQEQ: // fall through |
1333 | case Token::NEQ: |
1334 | if (right.canCoerceTo(left)) { |
1335 | *outLeftType = &left; |
1336 | *outRightType = &left; |
1337 | *outResultType = context.fBool_Type.get(); |
1338 | return true; |
1339 | } if (left.canCoerceTo(right)) { |
1340 | *outLeftType = &right; |
1341 | *outRightType = &right; |
1342 | *outResultType = context.fBool_Type.get(); |
1343 | return true; |
1344 | } |
1345 | return false; |
1346 | case Token::LT: // fall through |
1347 | case Token::GT: // fall through |
1348 | case Token::LTEQ: // fall through |
1349 | case Token::GTEQ: |
1350 | isLogical = true; |
1351 | validMatrixOrVectorOp = false; |
1352 | break; |
1353 | case Token::LOGICALOR: // fall through |
1354 | case Token::LOGICALAND: // fall through |
1355 | case Token::LOGICALXOR: // fall through |
1356 | case Token::LOGICALOREQ: // fall through |
1357 | case Token::LOGICALANDEQ: // fall through |
1358 | case Token::LOGICALXOREQ: |
1359 | *outLeftType = context.fBool_Type.get(); |
1360 | *outRightType = context.fBool_Type.get(); |
1361 | *outResultType = context.fBool_Type.get(); |
1362 | return left.canCoerceTo(*context.fBool_Type) && |
1363 | right.canCoerceTo(*context.fBool_Type); |
1364 | case Token::STAREQ: |
1365 | if (left.kind() == Type::kScalar_Kind) { |
1366 | *outLeftType = &left; |
1367 | *outRightType = &left; |
1368 | *outResultType = &left; |
1369 | return right.canCoerceTo(left); |
1370 | } |
1371 | // fall through |
1372 | case Token::STAR: |
1373 | if (is_matrix_multiply(left, right)) { |
1374 | // determine final component type |
1375 | if (determine_binary_type(context, Token::STAR, left.componentType(), |
1376 | right.componentType(), outLeftType, outRightType, |
1377 | outResultType, false)) { |
1378 | *outLeftType = &(*outResultType)->toCompound(context, left.columns(), |
1379 | left.rows()); |
1380 | *outRightType = &(*outResultType)->toCompound(context, right.columns(), |
1381 | right.rows()); |
1382 | int leftColumns = left.columns(); |
1383 | int leftRows = left.rows(); |
1384 | int rightColumns; |
1385 | int rightRows; |
1386 | if (right.kind() == Type::kVector_Kind) { |
1387 | // matrix * vector treats the vector as a column vector, so we need to |
1388 | // transpose it |
1389 | rightColumns = right.rows(); |
1390 | rightRows = right.columns(); |
1391 | SkASSERT(rightColumns == 1); |
1392 | } else { |
1393 | rightColumns = right.columns(); |
1394 | rightRows = right.rows(); |
1395 | } |
1396 | if (rightColumns > 1) { |
1397 | *outResultType = &(*outResultType)->toCompound(context, rightColumns, |
1398 | leftRows); |
1399 | } else { |
1400 | // result was a column vector, transpose it back to a row |
1401 | *outResultType = &(*outResultType)->toCompound(context, leftRows, |
1402 | rightColumns); |
1403 | } |
1404 | return leftColumns == rightRows; |
1405 | } else { |
1406 | return false; |
1407 | } |
1408 | } |
1409 | isLogical = false; |
1410 | validMatrixOrVectorOp = true; |
1411 | break; |
1412 | case Token::PLUSEQ: |
1413 | case Token::MINUSEQ: |
1414 | case Token::SLASHEQ: |
1415 | case Token::PERCENTEQ: |
1416 | case Token::SHLEQ: |
1417 | case Token::SHREQ: |
1418 | if (left.kind() == Type::kScalar_Kind) { |
1419 | *outLeftType = &left; |
1420 | *outRightType = &left; |
1421 | *outResultType = &left; |
1422 | return right.canCoerceTo(left); |
1423 | } |
1424 | // fall through |
1425 | case Token::PLUS: // fall through |
1426 | case Token::MINUS: // fall through |
1427 | case Token::SLASH: // fall through |
1428 | isLogical = false; |
1429 | validMatrixOrVectorOp = true; |
1430 | break; |
1431 | case Token::COMMA: |
1432 | *outLeftType = &left; |
1433 | *outRightType = &right; |
1434 | *outResultType = &right; |
1435 | return true; |
1436 | default: |
1437 | isLogical = false; |
1438 | validMatrixOrVectorOp = false; |
1439 | } |
1440 | bool isVectorOrMatrix = left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind; |
1441 | if (left.kind() == Type::kScalar_Kind && right.kind() == Type::kScalar_Kind && |
1442 | right.canCoerceTo(left)) { |
1443 | if (left.priority() > right.priority()) { |
1444 | *outLeftType = &left; |
1445 | *outRightType = &left; |
1446 | } else { |
1447 | *outLeftType = &right; |
1448 | *outRightType = &right; |
1449 | } |
1450 | if (isLogical) { |
1451 | *outResultType = context.fBool_Type.get(); |
1452 | } else { |
1453 | *outResultType = &left; |
1454 | } |
1455 | return true; |
1456 | } |
1457 | if (right.canCoerceTo(left) && isVectorOrMatrix && validMatrixOrVectorOp) { |
1458 | *outLeftType = &left; |
1459 | *outRightType = &left; |
1460 | if (isLogical) { |
1461 | *outResultType = context.fBool_Type.get(); |
1462 | } else { |
1463 | *outResultType = &left; |
1464 | } |
1465 | return true; |
1466 | } |
1467 | if ((left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind) && |
1468 | (right.kind() == Type::kScalar_Kind)) { |
1469 | if (determine_binary_type(context, op, left.componentType(), right, outLeftType, |
1470 | outRightType, outResultType, false)) { |
1471 | *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows()); |
1472 | if (!isLogical) { |
1473 | *outResultType = &(*outResultType)->toCompound(context, left.columns(), |
1474 | left.rows()); |
1475 | } |
1476 | return true; |
1477 | } |
1478 | return false; |
1479 | } |
1480 | if (tryFlipped) { |
1481 | return determine_binary_type(context, op, right, left, outRightType, outLeftType, |
1482 | outResultType, false); |
1483 | } |
1484 | return false; |
1485 | } |
1486 | |
1487 | static std::unique_ptr<Expression> short_circuit_boolean(const Context& context, |
1488 | const Expression& left, |
1489 | Token::Kind op, |
1490 | const Expression& right) { |
1491 | SkASSERT(left.fKind == Expression::kBoolLiteral_Kind); |
1492 | bool leftVal = ((BoolLiteral&) left).fValue; |
1493 | if (op == Token::LOGICALAND) { |
1494 | // (true && expr) -> (expr) and (false && expr) -> (false) |
1495 | return leftVal ? right.clone() |
1496 | : std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, false)); |
1497 | } else if (op == Token::LOGICALOR) { |
1498 | // (true || expr) -> (true) and (false || expr) -> (expr) |
1499 | return leftVal ? std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, true)) |
1500 | : right.clone(); |
1501 | } else if (op == Token::LOGICALXOR) { |
1502 | // (true ^^ expr) -> !(expr) and (false ^^ expr) -> (expr) |
1503 | return leftVal ? std::unique_ptr<Expression>(new PrefixExpression(Token::LOGICALNOT, |
1504 | right.clone())) |
1505 | : right.clone(); |
1506 | } else { |
1507 | return nullptr; |
1508 | } |
1509 | } |
1510 | |
1511 | std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left, |
1512 | Token::Kind op, |
1513 | const Expression& right) const { |
1514 | // If the left side is a constant boolean literal, the right side does not need to be constant |
1515 | // for short circuit optimizations to allow the constant to be folded. |
1516 | if (left.fKind == Expression::kBoolLiteral_Kind && !right.isConstant()) { |
1517 | return short_circuit_boolean(fContext, left, op, right); |
1518 | } else if (right.fKind == Expression::kBoolLiteral_Kind && !left.isConstant()) { |
1519 | // There aren't side effects in SKSL within expressions, so (left OP right) is equivalent to |
1520 | // (right OP left) for short-circuit optimizations |
1521 | return short_circuit_boolean(fContext, right, op, left); |
1522 | } |
1523 | |
1524 | // Other than the short-circuit cases above, constant folding requires both sides to be constant |
1525 | if (!left.isConstant() || !right.isConstant()) { |
1526 | return nullptr; |
1527 | } |
1528 | // Note that we expressly do not worry about precision and overflow here -- we use the maximum |
1529 | // precision to calculate the results and hope the result makes sense. The plan is to move the |
1530 | // Skia caps into SkSL, so we have access to all of them including the precisions of the various |
1531 | // types, which will let us be more intelligent about this. |
1532 | if (left.fKind == Expression::kBoolLiteral_Kind && |
1533 | right.fKind == Expression::kBoolLiteral_Kind) { |
1534 | bool leftVal = ((BoolLiteral&) left).fValue; |
1535 | bool rightVal = ((BoolLiteral&) right).fValue; |
1536 | bool result; |
1537 | switch (op) { |
1538 | case Token::LOGICALAND: result = leftVal && rightVal; break; |
1539 | case Token::LOGICALOR: result = leftVal || rightVal; break; |
1540 | case Token::LOGICALXOR: result = leftVal ^ rightVal; break; |
1541 | default: return nullptr; |
1542 | } |
1543 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, left.fOffset, result)); |
1544 | } |
1545 | #define RESULT(t, op) std::unique_ptr<Expression>(new t ## Literal(fContext, left.fOffset, \ |
1546 | leftVal op rightVal)) |
1547 | if (left.fKind == Expression::kIntLiteral_Kind && right.fKind == Expression::kIntLiteral_Kind) { |
1548 | int64_t leftVal = ((IntLiteral&) left).fValue; |
1549 | int64_t rightVal = ((IntLiteral&) right).fValue; |
1550 | switch (op) { |
1551 | case Token::PLUS: return RESULT(Int, +); |
1552 | case Token::MINUS: return RESULT(Int, -); |
1553 | case Token::STAR: return RESULT(Int, *); |
1554 | case Token::SLASH: |
1555 | if (rightVal) { |
1556 | return RESULT(Int, /); |
1557 | } |
1558 | fErrors.error(right.fOffset, "division by zero" ); |
1559 | return nullptr; |
1560 | case Token::PERCENT: |
1561 | if (rightVal) { |
1562 | return RESULT(Int, %); |
1563 | } |
1564 | fErrors.error(right.fOffset, "division by zero" ); |
1565 | return nullptr; |
1566 | case Token::BITWISEAND: return RESULT(Int, &); |
1567 | case Token::BITWISEOR: return RESULT(Int, |); |
1568 | case Token::BITWISEXOR: return RESULT(Int, ^); |
1569 | case Token::EQEQ: return RESULT(Bool, ==); |
1570 | case Token::NEQ: return RESULT(Bool, !=); |
1571 | case Token::GT: return RESULT(Bool, >); |
1572 | case Token::GTEQ: return RESULT(Bool, >=); |
1573 | case Token::LT: return RESULT(Bool, <); |
1574 | case Token::LTEQ: return RESULT(Bool, <=); |
1575 | case Token::SHL: |
1576 | if (rightVal >= 0 && rightVal <= 31) { |
1577 | return RESULT(Int, <<); |
1578 | } |
1579 | fErrors.error(right.fOffset, "shift value out of range" ); |
1580 | return nullptr; |
1581 | case Token::SHR: |
1582 | if (rightVal >= 0 && rightVal <= 31) { |
1583 | return RESULT(Int, >>); |
1584 | } |
1585 | fErrors.error(right.fOffset, "shift value out of range" ); |
1586 | return nullptr; |
1587 | |
1588 | default: |
1589 | return nullptr; |
1590 | } |
1591 | } |
1592 | if (left.fKind == Expression::kFloatLiteral_Kind && |
1593 | right.fKind == Expression::kFloatLiteral_Kind) { |
1594 | double leftVal = ((FloatLiteral&) left).fValue; |
1595 | double rightVal = ((FloatLiteral&) right).fValue; |
1596 | switch (op) { |
1597 | case Token::PLUS: return RESULT(Float, +); |
1598 | case Token::MINUS: return RESULT(Float, -); |
1599 | case Token::STAR: return RESULT(Float, *); |
1600 | case Token::SLASH: |
1601 | if (rightVal) { |
1602 | return RESULT(Float, /); |
1603 | } |
1604 | fErrors.error(right.fOffset, "division by zero" ); |
1605 | return nullptr; |
1606 | case Token::EQEQ: return RESULT(Bool, ==); |
1607 | case Token::NEQ: return RESULT(Bool, !=); |
1608 | case Token::GT: return RESULT(Bool, >); |
1609 | case Token::GTEQ: return RESULT(Bool, >=); |
1610 | case Token::LT: return RESULT(Bool, <); |
1611 | case Token::LTEQ: return RESULT(Bool, <=); |
1612 | default: return nullptr; |
1613 | } |
1614 | } |
1615 | if (left.fType.kind() == Type::kVector_Kind && left.fType.componentType().isFloat() && |
1616 | left.fType == right.fType) { |
1617 | std::vector<std::unique_ptr<Expression>> args; |
1618 | #define RETURN_VEC_COMPONENTWISE_RESULT(op) \ |
1619 | for (int i = 0; i < left.fType.columns(); i++) { \ |
1620 | float value = left.getFVecComponent(i) op \ |
1621 | right.getFVecComponent(i); \ |
1622 | args.emplace_back(new FloatLiteral(fContext, -1, value)); \ |
1623 | } \ |
1624 | return std::unique_ptr<Expression>(new Constructor(-1, left.fType, \ |
1625 | std::move(args))) |
1626 | switch (op) { |
1627 | case Token::EQEQ: |
1628 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1629 | left.compareConstant(fContext, right))); |
1630 | case Token::NEQ: |
1631 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1632 | !left.compareConstant(fContext, right))); |
1633 | case Token::PLUS: RETURN_VEC_COMPONENTWISE_RESULT(+); |
1634 | case Token::MINUS: RETURN_VEC_COMPONENTWISE_RESULT(-); |
1635 | case Token::STAR: RETURN_VEC_COMPONENTWISE_RESULT(*); |
1636 | case Token::SLASH: |
1637 | for (int i = 0; i < left.fType.columns(); i++) { |
1638 | SKSL_FLOAT rvalue = right.getFVecComponent(i); |
1639 | if (rvalue == 0.0) { |
1640 | fErrors.error(right.fOffset, "division by zero" ); |
1641 | return nullptr; |
1642 | } |
1643 | float value = left.getFVecComponent(i) / rvalue; |
1644 | args.emplace_back(new FloatLiteral(fContext, -1, value)); |
1645 | } |
1646 | return std::unique_ptr<Expression>(new Constructor(-1, left.fType, |
1647 | std::move(args))); |
1648 | default: return nullptr; |
1649 | } |
1650 | } |
1651 | if (left.fType.kind() == Type::kMatrix_Kind && |
1652 | right.fType.kind() == Type::kMatrix_Kind && |
1653 | left.fKind == right.fKind) { |
1654 | switch (op) { |
1655 | case Token::EQEQ: |
1656 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1657 | left.compareConstant(fContext, right))); |
1658 | case Token::NEQ: |
1659 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, |
1660 | !left.compareConstant(fContext, right))); |
1661 | default: |
1662 | return nullptr; |
1663 | } |
1664 | } |
1665 | #undef RESULT |
1666 | return nullptr; |
1667 | } |
1668 | |
1669 | std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode& expression) { |
1670 | SkASSERT(expression.fKind == ASTNode::Kind::kBinary); |
1671 | auto iter = expression.begin(); |
1672 | std::unique_ptr<Expression> left = this->convertExpression(*(iter++)); |
1673 | if (!left) { |
1674 | return nullptr; |
1675 | } |
1676 | std::unique_ptr<Expression> right = this->convertExpression(*(iter++)); |
1677 | if (!right) { |
1678 | return nullptr; |
1679 | } |
1680 | const Type* leftType; |
1681 | const Type* rightType; |
1682 | const Type* resultType; |
1683 | const Type* rawLeftType; |
1684 | if (left->fKind == Expression::kIntLiteral_Kind && right->fType.isInteger()) { |
1685 | rawLeftType = &right->fType; |
1686 | } else { |
1687 | rawLeftType = &left->fType; |
1688 | } |
1689 | const Type* rawRightType; |
1690 | if (right->fKind == Expression::kIntLiteral_Kind && left->fType.isInteger()) { |
1691 | rawRightType = &left->fType; |
1692 | } else { |
1693 | rawRightType = &right->fType; |
1694 | } |
1695 | Token::Kind op = expression.getToken().fKind; |
1696 | if (!determine_binary_type(fContext, op, *rawLeftType, *rawRightType, &leftType, &rightType, |
1697 | &resultType, !Compiler::IsAssignment(op))) { |
1698 | fErrors.error(expression.fOffset, String("type mismatch: '" ) + |
1699 | Compiler::OperatorName(expression.getToken().fKind) + |
1700 | "' cannot operate on '" + left->fType.displayName() + |
1701 | "', '" + right->fType.displayName() + "'" ); |
1702 | return nullptr; |
1703 | } |
1704 | if (Compiler::IsAssignment(op)) { |
1705 | this->setRefKind(*left, op != Token::EQ ? VariableReference::kReadWrite_RefKind : |
1706 | VariableReference::kWrite_RefKind); |
1707 | } |
1708 | left = this->coerce(std::move(left), *leftType); |
1709 | right = this->coerce(std::move(right), *rightType); |
1710 | if (!left || !right) { |
1711 | return nullptr; |
1712 | } |
1713 | std::unique_ptr<Expression> result = this->constantFold(*left.get(), op, *right.get()); |
1714 | if (!result) { |
1715 | result = std::unique_ptr<Expression>(new BinaryExpression(expression.fOffset, |
1716 | std::move(left), |
1717 | op, |
1718 | std::move(right), |
1719 | *resultType)); |
1720 | } |
1721 | return result; |
1722 | } |
1723 | |
1724 | std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(const ASTNode& node) { |
1725 | SkASSERT(node.fKind == ASTNode::Kind::kTernary); |
1726 | auto iter = node.begin(); |
1727 | std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), |
1728 | *fContext.fBool_Type); |
1729 | if (!test) { |
1730 | return nullptr; |
1731 | } |
1732 | std::unique_ptr<Expression> ifTrue = this->convertExpression(*(iter++)); |
1733 | if (!ifTrue) { |
1734 | return nullptr; |
1735 | } |
1736 | std::unique_ptr<Expression> ifFalse = this->convertExpression(*(iter++)); |
1737 | if (!ifFalse) { |
1738 | return nullptr; |
1739 | } |
1740 | const Type* trueType; |
1741 | const Type* falseType; |
1742 | const Type* resultType; |
1743 | if (!determine_binary_type(fContext, Token::EQEQ, ifTrue->fType, ifFalse->fType, &trueType, |
1744 | &falseType, &resultType, true) || trueType != falseType) { |
1745 | fErrors.error(node.fOffset, "ternary operator result mismatch: '" + |
1746 | ifTrue->fType.displayName() + "', '" + |
1747 | ifFalse->fType.displayName() + "'" ); |
1748 | return nullptr; |
1749 | } |
1750 | ifTrue = this->coerce(std::move(ifTrue), *trueType); |
1751 | if (!ifTrue) { |
1752 | return nullptr; |
1753 | } |
1754 | ifFalse = this->coerce(std::move(ifFalse), *falseType); |
1755 | if (!ifFalse) { |
1756 | return nullptr; |
1757 | } |
1758 | if (test->fKind == Expression::kBoolLiteral_Kind) { |
1759 | // static boolean test, just return one of the branches |
1760 | if (((BoolLiteral&) *test).fValue) { |
1761 | return ifTrue; |
1762 | } else { |
1763 | return ifFalse; |
1764 | } |
1765 | } |
1766 | return std::unique_ptr<Expression>(new TernaryExpression(node.fOffset, |
1767 | std::move(test), |
1768 | std::move(ifTrue), |
1769 | std::move(ifFalse))); |
1770 | } |
1771 | |
1772 | std::unique_ptr<Expression> IRGenerator::call(int offset, |
1773 | const FunctionDeclaration& function, |
1774 | std::vector<std::unique_ptr<Expression>> arguments) { |
1775 | if (function.fBuiltin) { |
1776 | auto found = fIntrinsics->find(function.fName); |
1777 | if (found != fIntrinsics->end() && !found->second.second) { |
1778 | found->second.second = true; |
1779 | const FunctionDeclaration* old = fCurrentFunction; |
1780 | fCurrentFunction = nullptr; |
1781 | this->convertFunction(*((FunctionDefinition&) *found->second.first).fSource); |
1782 | fCurrentFunction = old; |
1783 | } |
1784 | } |
1785 | if (function.fParameters.size() != arguments.size()) { |
1786 | String msg = "call to '" + function.fName + "' expected " + |
1787 | to_string((uint64_t) function.fParameters.size()) + |
1788 | " argument" ; |
1789 | if (function.fParameters.size() != 1) { |
1790 | msg += "s" ; |
1791 | } |
1792 | msg += ", but found " + to_string((uint64_t) arguments.size()); |
1793 | fErrors.error(offset, msg); |
1794 | return nullptr; |
1795 | } |
1796 | if (fKind == Program::kPipelineStage_Kind && !function.fDefined && !function.fBuiltin) { |
1797 | String msg = "call to undefined function '" + function.fName + "'" ; |
1798 | fErrors.error(offset, msg); |
1799 | return nullptr; |
1800 | } |
1801 | std::vector<const Type*> types; |
1802 | const Type* returnType; |
1803 | if (!function.determineFinalTypes(arguments, &types, &returnType)) { |
1804 | String msg = "no match for " + function.fName + "(" ; |
1805 | String separator; |
1806 | for (size_t i = 0; i < arguments.size(); i++) { |
1807 | msg += separator; |
1808 | separator = ", " ; |
1809 | msg += arguments[i]->fType.displayName(); |
1810 | } |
1811 | msg += ")" ; |
1812 | fErrors.error(offset, msg); |
1813 | return nullptr; |
1814 | } |
1815 | for (size_t i = 0; i < arguments.size(); i++) { |
1816 | arguments[i] = this->coerce(std::move(arguments[i]), *types[i]); |
1817 | if (!arguments[i]) { |
1818 | return nullptr; |
1819 | } |
1820 | if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) { |
1821 | this->setRefKind(*arguments[i], |
1822 | function.fParameters[i]->fModifiers.fFlags & Modifiers::kIn_Flag ? |
1823 | VariableReference::kReadWrite_RefKind : |
1824 | VariableReference::kPointer_RefKind); |
1825 | } |
1826 | } |
1827 | return std::unique_ptr<FunctionCall>(new FunctionCall(offset, *returnType, function, |
1828 | std::move(arguments))); |
1829 | } |
1830 | |
1831 | /** |
1832 | * Determines the cost of coercing the arguments of a function to the required types. Cost has no |
1833 | * particular meaning other than "lower costs are preferred". Returns INT_MAX if the call is not |
1834 | * valid. |
1835 | */ |
1836 | int IRGenerator::callCost(const FunctionDeclaration& function, |
1837 | const std::vector<std::unique_ptr<Expression>>& arguments) { |
1838 | if (function.fParameters.size() != arguments.size()) { |
1839 | return INT_MAX; |
1840 | } |
1841 | int total = 0; |
1842 | std::vector<const Type*> types; |
1843 | const Type* ignored; |
1844 | if (!function.determineFinalTypes(arguments, &types, &ignored)) { |
1845 | return INT_MAX; |
1846 | } |
1847 | for (size_t i = 0; i < arguments.size(); i++) { |
1848 | int cost = arguments[i]->coercionCost(*types[i]); |
1849 | if (cost != INT_MAX) { |
1850 | total += cost; |
1851 | } else { |
1852 | return INT_MAX; |
1853 | } |
1854 | } |
1855 | return total; |
1856 | } |
1857 | |
1858 | std::unique_ptr<Expression> IRGenerator::call(int offset, |
1859 | std::unique_ptr<Expression> functionValue, |
1860 | std::vector<std::unique_ptr<Expression>> arguments) { |
1861 | switch (functionValue->fKind) { |
1862 | case Expression::kTypeReference_Kind: |
1863 | return this->convertConstructor(offset, |
1864 | ((TypeReference&) *functionValue).fValue, |
1865 | std::move(arguments)); |
1866 | case Expression::kExternalValue_Kind: { |
1867 | ExternalValue* v = ((ExternalValueReference&) *functionValue).fValue; |
1868 | if (!v->canCall()) { |
1869 | fErrors.error(offset, "this external value is not a function" ); |
1870 | return nullptr; |
1871 | } |
1872 | int count = v->callParameterCount(); |
1873 | if (count != (int) arguments.size()) { |
1874 | fErrors.error(offset, "external function expected " + to_string(count) + |
1875 | " arguments, but found " + to_string((int) arguments.size())); |
1876 | return nullptr; |
1877 | } |
1878 | static constexpr int PARAMETER_MAX = 16; |
1879 | SkASSERT(count < PARAMETER_MAX); |
1880 | const Type* types[PARAMETER_MAX]; |
1881 | v->getCallParameterTypes(types); |
1882 | for (int i = 0; i < count; ++i) { |
1883 | arguments[i] = this->coerce(std::move(arguments[i]), *types[i]); |
1884 | if (!arguments[i]) { |
1885 | return nullptr; |
1886 | } |
1887 | } |
1888 | return std::unique_ptr<Expression>(new ExternalFunctionCall(offset, v->callReturnType(), |
1889 | v, std::move(arguments))); |
1890 | } |
1891 | case Expression::kFunctionReference_Kind: { |
1892 | FunctionReference* ref = (FunctionReference*) functionValue.get(); |
1893 | int bestCost = INT_MAX; |
1894 | const FunctionDeclaration* best = nullptr; |
1895 | if (ref->fFunctions.size() > 1) { |
1896 | for (const auto& f : ref->fFunctions) { |
1897 | int cost = this->callCost(*f, arguments); |
1898 | if (cost < bestCost) { |
1899 | bestCost = cost; |
1900 | best = f; |
1901 | } |
1902 | } |
1903 | if (best) { |
1904 | return this->call(offset, *best, std::move(arguments)); |
1905 | } |
1906 | String msg = "no match for " + ref->fFunctions[0]->fName + "(" ; |
1907 | String separator; |
1908 | for (size_t i = 0; i < arguments.size(); i++) { |
1909 | msg += separator; |
1910 | separator = ", " ; |
1911 | msg += arguments[i]->fType.displayName(); |
1912 | } |
1913 | msg += ")" ; |
1914 | fErrors.error(offset, msg); |
1915 | return nullptr; |
1916 | } |
1917 | return this->call(offset, *ref->fFunctions[0], std::move(arguments)); |
1918 | } |
1919 | default: |
1920 | fErrors.error(offset, "not a function" ); |
1921 | return nullptr; |
1922 | } |
1923 | } |
1924 | |
1925 | std::unique_ptr<Expression> IRGenerator::convertNumberConstructor( |
1926 | int offset, |
1927 | const Type& type, |
1928 | std::vector<std::unique_ptr<Expression>> args) { |
1929 | SkASSERT(type.isNumber()); |
1930 | if (args.size() != 1) { |
1931 | fErrors.error(offset, "invalid arguments to '" + type.displayName() + |
1932 | "' constructor, (expected exactly 1 argument, but found " + |
1933 | to_string((uint64_t) args.size()) + ")" ); |
1934 | return nullptr; |
1935 | } |
1936 | if (type == args[0]->fType) { |
1937 | return std::move(args[0]); |
1938 | } |
1939 | if (type.isFloat() && args.size() == 1 && args[0]->fKind == Expression::kFloatLiteral_Kind) { |
1940 | double value = ((FloatLiteral&) *args[0]).fValue; |
1941 | return std::unique_ptr<Expression>(new FloatLiteral(offset, value, &type)); |
1942 | } |
1943 | if (type.isFloat() && args.size() == 1 && args[0]->fKind == Expression::kIntLiteral_Kind) { |
1944 | int64_t value = ((IntLiteral&) *args[0]).fValue; |
1945 | return std::unique_ptr<Expression>(new FloatLiteral(offset, (double) value, &type)); |
1946 | } |
1947 | if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type || |
1948 | type == *fContext.fUInt_Type)) { |
1949 | return std::unique_ptr<Expression>(new IntLiteral(offset, |
1950 | ((IntLiteral&) *args[0]).fValue, |
1951 | &type)); |
1952 | } |
1953 | if (args[0]->fType == *fContext.fBool_Type) { |
1954 | std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, offset, 0)); |
1955 | std::unique_ptr<IntLiteral> one(new IntLiteral(fContext, offset, 1)); |
1956 | return std::unique_ptr<Expression>( |
1957 | new TernaryExpression(offset, std::move(args[0]), |
1958 | this->coerce(std::move(one), type), |
1959 | this->coerce(std::move(zero), |
1960 | type))); |
1961 | } |
1962 | if (!args[0]->fType.isNumber()) { |
1963 | fErrors.error(offset, "invalid argument to '" + type.displayName() + |
1964 | "' constructor (expected a number or bool, but found '" + |
1965 | args[0]->fType.displayName() + "')" ); |
1966 | return nullptr; |
1967 | } |
1968 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
1969 | } |
1970 | |
1971 | int component_count(const Type& type) { |
1972 | switch (type.kind()) { |
1973 | case Type::kVector_Kind: |
1974 | return type.columns(); |
1975 | case Type::kMatrix_Kind: |
1976 | return type.columns() * type.rows(); |
1977 | default: |
1978 | return 1; |
1979 | } |
1980 | } |
1981 | |
1982 | std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor( |
1983 | int offset, |
1984 | const Type& type, |
1985 | std::vector<std::unique_ptr<Expression>> args) { |
1986 | SkASSERT(type.kind() == Type::kVector_Kind || type.kind() == Type::kMatrix_Kind); |
1987 | if (type.kind() == Type::kMatrix_Kind && args.size() == 1 && |
1988 | args[0]->fType.kind() == Type::kMatrix_Kind) { |
1989 | // matrix from matrix is always legal |
1990 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
1991 | } |
1992 | int actual = 0; |
1993 | int expected = type.rows() * type.columns(); |
1994 | if (args.size() != 1 || expected != component_count(args[0]->fType) || |
1995 | type.componentType().isNumber() != args[0]->fType.componentType().isNumber()) { |
1996 | for (size_t i = 0; i < args.size(); i++) { |
1997 | if (args[i]->fType.kind() == Type::kVector_Kind) { |
1998 | if (type.componentType().isNumber() != |
1999 | args[i]->fType.componentType().isNumber()) { |
2000 | fErrors.error(offset, "'" + args[i]->fType.displayName() + "' is not a valid " |
2001 | "parameter to '" + type.displayName() + |
2002 | "' constructor" ); |
2003 | return nullptr; |
2004 | } |
2005 | actual += args[i]->fType.columns(); |
2006 | } else if (args[i]->fType.kind() == Type::kScalar_Kind) { |
2007 | actual += 1; |
2008 | if (type.kind() != Type::kScalar_Kind) { |
2009 | args[i] = this->coerce(std::move(args[i]), type.componentType()); |
2010 | if (!args[i]) { |
2011 | return nullptr; |
2012 | } |
2013 | } |
2014 | } else { |
2015 | fErrors.error(offset, "'" + args[i]->fType.displayName() + "' is not a valid " |
2016 | "parameter to '" + type.displayName() + "' constructor" ); |
2017 | return nullptr; |
2018 | } |
2019 | } |
2020 | if (actual != 1 && actual != expected) { |
2021 | fErrors.error(offset, "invalid arguments to '" + type.displayName() + |
2022 | "' constructor (expected " + to_string(expected) + |
2023 | " scalars, but found " + to_string(actual) + ")" ); |
2024 | return nullptr; |
2025 | } |
2026 | } |
2027 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2028 | } |
2029 | |
2030 | std::unique_ptr<Expression> IRGenerator::convertConstructor( |
2031 | int offset, |
2032 | const Type& type, |
2033 | std::vector<std::unique_ptr<Expression>> args) { |
2034 | // FIXME: add support for structs |
2035 | Type::Kind kind = type.kind(); |
2036 | if (args.size() == 1 && args[0]->fType == type) { |
2037 | // argument is already the right type, just return it |
2038 | return std::move(args[0]); |
2039 | } |
2040 | if (type.isNumber()) { |
2041 | return this->convertNumberConstructor(offset, type, std::move(args)); |
2042 | } else if (kind == Type::kArray_Kind) { |
2043 | const Type& base = type.componentType(); |
2044 | for (size_t i = 0; i < args.size(); i++) { |
2045 | args[i] = this->coerce(std::move(args[i]), base); |
2046 | if (!args[i]) { |
2047 | return nullptr; |
2048 | } |
2049 | } |
2050 | return std::unique_ptr<Expression>(new Constructor(offset, type, std::move(args))); |
2051 | } else if (kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) { |
2052 | return this->convertCompoundConstructor(offset, type, std::move(args)); |
2053 | } else { |
2054 | fErrors.error(offset, "cannot construct '" + type.displayName() + "'" ); |
2055 | return nullptr; |
2056 | } |
2057 | } |
2058 | |
2059 | std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(const ASTNode& expression) { |
2060 | SkASSERT(expression.fKind == ASTNode::Kind::kPrefix); |
2061 | std::unique_ptr<Expression> base = this->convertExpression(*expression.begin()); |
2062 | if (!base) { |
2063 | return nullptr; |
2064 | } |
2065 | switch (expression.getToken().fKind) { |
2066 | case Token::PLUS: |
2067 | if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind && |
2068 | base->fType != *fContext.fFloatLiteral_Type) { |
2069 | fErrors.error(expression.fOffset, |
2070 | "'+' cannot operate on '" + base->fType.displayName() + "'" ); |
2071 | return nullptr; |
2072 | } |
2073 | return base; |
2074 | case Token::MINUS: |
2075 | if (base->fKind == Expression::kIntLiteral_Kind) { |
2076 | return std::unique_ptr<Expression>(new IntLiteral(fContext, base->fOffset, |
2077 | -((IntLiteral&) *base).fValue)); |
2078 | } |
2079 | if (base->fKind == Expression::kFloatLiteral_Kind) { |
2080 | double value = -((FloatLiteral&) *base).fValue; |
2081 | return std::unique_ptr<Expression>(new FloatLiteral(fContext, base->fOffset, |
2082 | value)); |
2083 | } |
2084 | if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) { |
2085 | fErrors.error(expression.fOffset, |
2086 | "'-' cannot operate on '" + base->fType.displayName() + "'" ); |
2087 | return nullptr; |
2088 | } |
2089 | return std::unique_ptr<Expression>(new PrefixExpression(Token::MINUS, std::move(base))); |
2090 | case Token::PLUSPLUS: |
2091 | if (!base->fType.isNumber()) { |
2092 | fErrors.error(expression.fOffset, |
2093 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2094 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2095 | return nullptr; |
2096 | } |
2097 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
2098 | break; |
2099 | case Token::MINUSMINUS: |
2100 | if (!base->fType.isNumber()) { |
2101 | fErrors.error(expression.fOffset, |
2102 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2103 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2104 | return nullptr; |
2105 | } |
2106 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
2107 | break; |
2108 | case Token::LOGICALNOT: |
2109 | if (base->fType != *fContext.fBool_Type) { |
2110 | fErrors.error(expression.fOffset, |
2111 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2112 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2113 | return nullptr; |
2114 | } |
2115 | if (base->fKind == Expression::kBoolLiteral_Kind) { |
2116 | return std::unique_ptr<Expression>(new BoolLiteral(fContext, base->fOffset, |
2117 | !((BoolLiteral&) *base).fValue)); |
2118 | } |
2119 | break; |
2120 | case Token::BITWISENOT: |
2121 | if (base->fType != *fContext.fInt_Type && base->fType != *fContext.fUInt_Type) { |
2122 | fErrors.error(expression.fOffset, |
2123 | String("'" ) + Compiler::OperatorName(expression.getToken().fKind) + |
2124 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2125 | return nullptr; |
2126 | } |
2127 | break; |
2128 | default: |
2129 | ABORT("unsupported prefix operator\n" ); |
2130 | } |
2131 | return std::unique_ptr<Expression>(new PrefixExpression(expression.getToken().fKind, |
2132 | std::move(base))); |
2133 | } |
2134 | |
2135 | std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression> base, |
2136 | const ASTNode& index) { |
2137 | if (base->fKind == Expression::kTypeReference_Kind) { |
2138 | if (index.fKind == ASTNode::Kind::kInt) { |
2139 | const Type& oldType = ((TypeReference&) *base).fValue; |
2140 | SKSL_INT size = index.getInt(); |
2141 | Type* newType = (Type*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( |
2142 | new Type(oldType.name() + "[" + to_string(size) + "]" , |
2143 | Type::kArray_Kind, oldType, size))); |
2144 | return std::unique_ptr<Expression>(new TypeReference(fContext, base->fOffset, |
2145 | *newType)); |
2146 | |
2147 | } else { |
2148 | fErrors.error(base->fOffset, "array size must be a constant" ); |
2149 | return nullptr; |
2150 | } |
2151 | } |
2152 | if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind && |
2153 | base->fType.kind() != Type::kVector_Kind) { |
2154 | fErrors.error(base->fOffset, "expected array, but found '" + base->fType.displayName() + |
2155 | "'" ); |
2156 | return nullptr; |
2157 | } |
2158 | std::unique_ptr<Expression> converted = this->convertExpression(index); |
2159 | if (!converted) { |
2160 | return nullptr; |
2161 | } |
2162 | if (converted->fType != *fContext.fUInt_Type) { |
2163 | converted = this->coerce(std::move(converted), *fContext.fInt_Type); |
2164 | if (!converted) { |
2165 | return nullptr; |
2166 | } |
2167 | } |
2168 | return std::unique_ptr<Expression>(new IndexExpression(fContext, std::move(base), |
2169 | std::move(converted))); |
2170 | } |
2171 | |
2172 | std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base, |
2173 | StringFragment field) { |
2174 | if (base->fKind == Expression::kExternalValue_Kind) { |
2175 | ExternalValue& ev = *((ExternalValueReference&) *base).fValue; |
2176 | ExternalValue* result = ev.getChild(String(field).c_str()); |
2177 | if (!result) { |
2178 | fErrors.error(base->fOffset, "external value does not have a child named '" + field + |
2179 | "'" ); |
2180 | return nullptr; |
2181 | } |
2182 | return std::unique_ptr<Expression>(new ExternalValueReference(base->fOffset, result)); |
2183 | } |
2184 | auto fields = base->fType.fields(); |
2185 | for (size_t i = 0; i < fields.size(); i++) { |
2186 | if (fields[i].fName == field) { |
2187 | return std::unique_ptr<Expression>(new FieldAccess(std::move(base), (int) i)); |
2188 | } |
2189 | } |
2190 | fErrors.error(base->fOffset, "type '" + base->fType.displayName() + "' does not have a " |
2191 | "field named '" + field + "" ); |
2192 | return nullptr; |
2193 | } |
2194 | |
2195 | std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base, |
2196 | StringFragment fields) { |
2197 | if (base->fType.kind() != Type::kVector_Kind) { |
2198 | fErrors.error(base->fOffset, "cannot swizzle type '" + base->fType.displayName() + "'" ); |
2199 | return nullptr; |
2200 | } |
2201 | std::vector<int> swizzleComponents; |
2202 | for (size_t i = 0; i < fields.fLength; i++) { |
2203 | switch (fields[i]) { |
2204 | case '0': |
2205 | swizzleComponents.push_back(SKSL_SWIZZLE_0); |
2206 | break; |
2207 | case '1': |
2208 | swizzleComponents.push_back(SKSL_SWIZZLE_1); |
2209 | break; |
2210 | case 'x': |
2211 | case 'r': |
2212 | case 's': |
2213 | case 'L': |
2214 | swizzleComponents.push_back(0); |
2215 | break; |
2216 | case 'y': |
2217 | case 'g': |
2218 | case 't': |
2219 | case 'T': |
2220 | if (base->fType.columns() >= 2) { |
2221 | swizzleComponents.push_back(1); |
2222 | break; |
2223 | } |
2224 | // fall through |
2225 | case 'z': |
2226 | case 'b': |
2227 | case 'p': |
2228 | case 'R': |
2229 | if (base->fType.columns() >= 3) { |
2230 | swizzleComponents.push_back(2); |
2231 | break; |
2232 | } |
2233 | // fall through |
2234 | case 'w': |
2235 | case 'a': |
2236 | case 'q': |
2237 | case 'B': |
2238 | if (base->fType.columns() >= 4) { |
2239 | swizzleComponents.push_back(3); |
2240 | break; |
2241 | } |
2242 | // fall through |
2243 | default: |
2244 | fErrors.error(base->fOffset, String::printf("invalid swizzle component '%c'" , |
2245 | fields[i])); |
2246 | return nullptr; |
2247 | } |
2248 | } |
2249 | SkASSERT(swizzleComponents.size() > 0); |
2250 | if (swizzleComponents.size() > 4) { |
2251 | fErrors.error(base->fOffset, "too many components in swizzle mask '" + fields + "'" ); |
2252 | return nullptr; |
2253 | } |
2254 | return std::unique_ptr<Expression>(new Swizzle(fContext, std::move(base), swizzleComponents)); |
2255 | } |
2256 | |
2257 | std::unique_ptr<Expression> IRGenerator::getCap(int offset, String name) { |
2258 | auto found = fCapsMap.find(name); |
2259 | if (found == fCapsMap.end()) { |
2260 | fErrors.error(offset, "unknown capability flag '" + name + "'" ); |
2261 | return nullptr; |
2262 | } |
2263 | String fullName = "sk_Caps." + name; |
2264 | return std::unique_ptr<Expression>(new Setting(offset, fullName, |
2265 | found->second.literal(fContext, offset))); |
2266 | } |
2267 | |
2268 | std::unique_ptr<Expression> IRGenerator::getArg(int offset, String name) const { |
2269 | auto found = fSettings->fArgs.find(name); |
2270 | if (found == fSettings->fArgs.end()) { |
2271 | return nullptr; |
2272 | } |
2273 | String fullName = "sk_Args." + name; |
2274 | return std::unique_ptr<Expression>(new Setting(offset, |
2275 | fullName, |
2276 | found->second.literal(fContext, offset))); |
2277 | } |
2278 | |
2279 | std::unique_ptr<Expression> IRGenerator::convertTypeField(int offset, const Type& type, |
2280 | StringFragment field) { |
2281 | std::unique_ptr<Expression> result; |
2282 | for (const auto& e : *fProgramElements) { |
2283 | if (e->fKind == ProgramElement::kEnum_Kind && type.name() == ((Enum&) *e).fTypeName) { |
2284 | std::shared_ptr<SymbolTable> old = fSymbolTable; |
2285 | fSymbolTable = ((Enum&) *e).fSymbols; |
2286 | result = convertIdentifier(ASTNode(&fFile->fNodes, offset, ASTNode::Kind::kIdentifier, |
2287 | field)); |
2288 | SkASSERT(result->fKind == Expression::kVariableReference_Kind); |
2289 | const Variable& v = ((VariableReference&) *result).fVariable; |
2290 | SkASSERT(v.fInitialValue); |
2291 | SkASSERT(v.fInitialValue->fKind == Expression::kIntLiteral_Kind); |
2292 | result.reset(new IntLiteral(offset, ((IntLiteral&) *v.fInitialValue).fValue, &type)); |
2293 | fSymbolTable = old; |
2294 | break; |
2295 | } |
2296 | } |
2297 | if (!result) { |
2298 | auto found = fIntrinsics->find(type.fName); |
2299 | if (found != fIntrinsics->end()) { |
2300 | SkASSERT(!found->second.second); |
2301 | found->second.second = true; |
2302 | fProgramElements->push_back(found->second.first->clone()); |
2303 | return this->convertTypeField(offset, type, field); |
2304 | } |
2305 | fErrors.error(offset, "type '" + type.fName + "' does not have a field named '" + field + |
2306 | "'" ); |
2307 | } |
2308 | return result; |
2309 | } |
2310 | |
2311 | std::unique_ptr<Expression> IRGenerator::convertIndexExpression(const ASTNode& index) { |
2312 | SkASSERT(index.fKind == ASTNode::Kind::kIndex); |
2313 | auto iter = index.begin(); |
2314 | std::unique_ptr<Expression> base = this->convertExpression(*(iter++)); |
2315 | if (!base) { |
2316 | return nullptr; |
2317 | } |
2318 | if (iter != index.end()) { |
2319 | return this->convertIndex(std::move(base), *(iter++)); |
2320 | } else if (base->fKind == Expression::kTypeReference_Kind) { |
2321 | const Type& oldType = ((TypeReference&) *base).fValue; |
2322 | Type* newType = (Type*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( |
2323 | new Type(oldType.name() + "[]" , |
2324 | Type::kArray_Kind, |
2325 | oldType, |
2326 | -1))); |
2327 | return std::unique_ptr<Expression>(new TypeReference(fContext, base->fOffset, |
2328 | *newType)); |
2329 | } |
2330 | fErrors.error(index.fOffset, "'[]' must follow a type name" ); |
2331 | return nullptr; |
2332 | } |
2333 | |
2334 | std::unique_ptr<Expression> IRGenerator::convertCallExpression(const ASTNode& callNode) { |
2335 | SkASSERT(callNode.fKind == ASTNode::Kind::kCall); |
2336 | auto iter = callNode.begin(); |
2337 | std::unique_ptr<Expression> base = this->convertExpression(*(iter++)); |
2338 | if (!base) { |
2339 | return nullptr; |
2340 | } |
2341 | std::vector<std::unique_ptr<Expression>> arguments; |
2342 | for (; iter != callNode.end(); ++iter) { |
2343 | std::unique_ptr<Expression> converted = this->convertExpression(*iter); |
2344 | if (!converted) { |
2345 | return nullptr; |
2346 | } |
2347 | arguments.push_back(std::move(converted)); |
2348 | } |
2349 | return this->call(callNode.fOffset, std::move(base), std::move(arguments)); |
2350 | } |
2351 | |
2352 | std::unique_ptr<Expression> IRGenerator::convertFieldExpression(const ASTNode& fieldNode) { |
2353 | std::unique_ptr<Expression> base = this->convertExpression(*fieldNode.begin()); |
2354 | if (!base) { |
2355 | return nullptr; |
2356 | } |
2357 | StringFragment field = fieldNode.getString(); |
2358 | if (base->fType == *fContext.fSkCaps_Type) { |
2359 | return this->getCap(fieldNode.fOffset, field); |
2360 | } |
2361 | if (base->fType == *fContext.fSkArgs_Type) { |
2362 | return this->getArg(fieldNode.fOffset, field); |
2363 | } |
2364 | if (base->fKind == Expression::kTypeReference_Kind) { |
2365 | return this->convertTypeField(base->fOffset, ((TypeReference&) *base).fValue, |
2366 | field); |
2367 | } |
2368 | if (base->fKind == Expression::kExternalValue_Kind) { |
2369 | return this->convertField(std::move(base), field); |
2370 | } |
2371 | switch (base->fType.kind()) { |
2372 | case Type::kVector_Kind: |
2373 | return this->convertSwizzle(std::move(base), field); |
2374 | case Type::kOther_Kind: |
2375 | case Type::kStruct_Kind: |
2376 | return this->convertField(std::move(base), field); |
2377 | default: |
2378 | fErrors.error(base->fOffset, "cannot swizzle value of type '" + |
2379 | base->fType.displayName() + "'" ); |
2380 | return nullptr; |
2381 | } |
2382 | } |
2383 | |
2384 | std::unique_ptr<Expression> IRGenerator::convertPostfixExpression(const ASTNode& expression) { |
2385 | std::unique_ptr<Expression> base = this->convertExpression(*expression.begin()); |
2386 | if (!base) { |
2387 | return nullptr; |
2388 | } |
2389 | if (!base->fType.isNumber()) { |
2390 | fErrors.error(expression.fOffset, |
2391 | "'" + String(Compiler::OperatorName(expression.getToken().fKind)) + |
2392 | "' cannot operate on '" + base->fType.displayName() + "'" ); |
2393 | return nullptr; |
2394 | } |
2395 | this->setRefKind(*base, VariableReference::kReadWrite_RefKind); |
2396 | return std::unique_ptr<Expression>(new PostfixExpression(std::move(base), |
2397 | expression.getToken().fKind)); |
2398 | } |
2399 | |
2400 | void IRGenerator::checkValid(const Expression& expr) { |
2401 | switch (expr.fKind) { |
2402 | case Expression::kFunctionReference_Kind: |
2403 | fErrors.error(expr.fOffset, "expected '(' to begin function call" ); |
2404 | break; |
2405 | case Expression::kTypeReference_Kind: |
2406 | fErrors.error(expr.fOffset, "expected '(' to begin constructor invocation" ); |
2407 | break; |
2408 | default: |
2409 | if (expr.fType == *fContext.fInvalid_Type) { |
2410 | fErrors.error(expr.fOffset, "invalid expression" ); |
2411 | } |
2412 | } |
2413 | } |
2414 | |
2415 | bool IRGenerator::checkSwizzleWrite(const Swizzle& swizzle) { |
2416 | int bits = 0; |
2417 | for (int idx : swizzle.fComponents) { |
2418 | if (idx < 0) { |
2419 | fErrors.error(swizzle.fOffset, "cannot write to a swizzle mask containing a constant" ); |
2420 | return false; |
2421 | } |
2422 | SkASSERT(idx <= 3); |
2423 | int bit = 1 << idx; |
2424 | if (bits & bit) { |
2425 | fErrors.error(swizzle.fOffset, |
2426 | "cannot write to the same swizzle field more than once" ); |
2427 | return false; |
2428 | } |
2429 | bits |= bit; |
2430 | } |
2431 | return true; |
2432 | } |
2433 | |
2434 | void IRGenerator::setRefKind(const Expression& expr, VariableReference::RefKind kind) { |
2435 | switch (expr.fKind) { |
2436 | case Expression::kVariableReference_Kind: { |
2437 | const Variable& var = ((VariableReference&) expr).fVariable; |
2438 | if (var.fModifiers.fFlags & |
2439 | (Modifiers::kConst_Flag | Modifiers::kUniform_Flag | Modifiers::kVarying_Flag)) { |
2440 | fErrors.error(expr.fOffset, "cannot modify immutable variable '" + var.fName + "'" ); |
2441 | } |
2442 | ((VariableReference&) expr).setRefKind(kind); |
2443 | break; |
2444 | } |
2445 | case Expression::kFieldAccess_Kind: |
2446 | this->setRefKind(*((FieldAccess&) expr).fBase, kind); |
2447 | break; |
2448 | case Expression::kSwizzle_Kind: { |
2449 | const Swizzle& swizzle = (Swizzle&) expr; |
2450 | this->checkSwizzleWrite(swizzle); |
2451 | this->setRefKind(*swizzle.fBase, kind); |
2452 | break; |
2453 | } |
2454 | case Expression::kIndex_Kind: |
2455 | this->setRefKind(*((IndexExpression&) expr).fBase, kind); |
2456 | break; |
2457 | case Expression::kTernary_Kind: { |
2458 | TernaryExpression& t = (TernaryExpression&) expr; |
2459 | this->setRefKind(*t.fIfTrue, kind); |
2460 | this->setRefKind(*t.fIfFalse, kind); |
2461 | break; |
2462 | } |
2463 | case Expression::kExternalValue_Kind: { |
2464 | const ExternalValue& v = *((ExternalValueReference&) expr).fValue; |
2465 | if (!v.canWrite()) { |
2466 | fErrors.error(expr.fOffset, |
2467 | "cannot modify immutable external value '" + v.fName + "'" ); |
2468 | } |
2469 | break; |
2470 | } |
2471 | default: |
2472 | fErrors.error(expr.fOffset, "cannot assign to this expression" ); |
2473 | break; |
2474 | } |
2475 | } |
2476 | |
2477 | void IRGenerator::convertProgram(Program::Kind kind, |
2478 | const char* text, |
2479 | size_t length, |
2480 | SymbolTable& types, |
2481 | std::vector<std::unique_ptr<ProgramElement>>* out) { |
2482 | fKind = kind; |
2483 | fProgramElements = out; |
2484 | Parser parser(text, length, types, fErrors); |
2485 | fFile = parser.file(); |
2486 | if (fErrors.errorCount()) { |
2487 | return; |
2488 | } |
2489 | SkASSERT(fFile); |
2490 | for (const auto& decl : fFile->root()) { |
2491 | switch (decl.fKind) { |
2492 | case ASTNode::Kind::kVarDeclarations: { |
2493 | std::unique_ptr<VarDeclarations> s = this->convertVarDeclarations( |
2494 | decl, |
2495 | Variable::kGlobal_Storage); |
2496 | if (s) { |
2497 | fProgramElements->push_back(std::move(s)); |
2498 | } |
2499 | break; |
2500 | } |
2501 | case ASTNode::Kind::kEnum: { |
2502 | this->convertEnum(decl); |
2503 | break; |
2504 | } |
2505 | case ASTNode::Kind::kFunction: { |
2506 | this->convertFunction(decl); |
2507 | break; |
2508 | } |
2509 | case ASTNode::Kind::kModifiers: { |
2510 | std::unique_ptr<ModifiersDeclaration> f = this->convertModifiersDeclaration(decl); |
2511 | if (f) { |
2512 | fProgramElements->push_back(std::move(f)); |
2513 | } |
2514 | break; |
2515 | } |
2516 | case ASTNode::Kind::kInterfaceBlock: { |
2517 | std::unique_ptr<InterfaceBlock> i = this->convertInterfaceBlock(decl); |
2518 | if (i) { |
2519 | fProgramElements->push_back(std::move(i)); |
2520 | } |
2521 | break; |
2522 | } |
2523 | case ASTNode::Kind::kExtension: { |
2524 | std::unique_ptr<Extension> e = this->convertExtension(decl.fOffset, |
2525 | decl.getString()); |
2526 | if (e) { |
2527 | fProgramElements->push_back(std::move(e)); |
2528 | } |
2529 | break; |
2530 | } |
2531 | case ASTNode::Kind::kSection: { |
2532 | std::unique_ptr<Section> s = this->convertSection(decl); |
2533 | if (s) { |
2534 | fProgramElements->push_back(std::move(s)); |
2535 | } |
2536 | break; |
2537 | } |
2538 | default: |
2539 | #ifdef SK_DEBUG |
2540 | ABORT("unsupported declaration: %s\n" , decl.description().c_str()); |
2541 | #endif |
2542 | break; |
2543 | } |
2544 | } |
2545 | } |
2546 | |
2547 | |
2548 | } |
2549 | |