blob: b75259e1629d78152b27a11dc83335ff23323552 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
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 */
Ethan Nicholas11d53972016-11-28 11:23:23 -05007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLIRGenerator.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
10#include "limits.h"
John Stiles44e96be2020-08-31 13:16:04 -040011#include <iterator>
John Stilesfbd050b2020-08-03 13:21:46 -040012#include <memory>
Ethan Nicholasaf197692017-02-27 13:26:45 -050013#include <unordered_set>
ethannicholasb3058bd2016-07-01 08:22:01 -070014
Ethan Nicholas6e0fa402020-08-20 14:08:23 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCompiler.h"
17#include "src/sksl/SkSLParser.h"
Brian Osman3000d6b2020-07-31 15:57:28 -040018#include "src/sksl/SkSLUtil.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/sksl/ir/SkSLBinaryExpression.h"
20#include "src/sksl/ir/SkSLBoolLiteral.h"
21#include "src/sksl/ir/SkSLBreakStatement.h"
22#include "src/sksl/ir/SkSLConstructor.h"
23#include "src/sksl/ir/SkSLContinueStatement.h"
24#include "src/sksl/ir/SkSLDiscardStatement.h"
25#include "src/sksl/ir/SkSLDoStatement.h"
26#include "src/sksl/ir/SkSLEnum.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
Ethan Nicholas9e6a3932019-05-17 16:31:21 -040028#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Ethan Nicholas91164d12019-05-15 15:29:54 -040029#include "src/sksl/ir/SkSLExternalValueReference.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050030#include "src/sksl/ir/SkSLField.h"
31#include "src/sksl/ir/SkSLFieldAccess.h"
32#include "src/sksl/ir/SkSLFloatLiteral.h"
33#include "src/sksl/ir/SkSLForStatement.h"
34#include "src/sksl/ir/SkSLFunctionCall.h"
35#include "src/sksl/ir/SkSLFunctionDeclaration.h"
36#include "src/sksl/ir/SkSLFunctionDefinition.h"
37#include "src/sksl/ir/SkSLFunctionReference.h"
38#include "src/sksl/ir/SkSLIfStatement.h"
39#include "src/sksl/ir/SkSLIndexExpression.h"
40#include "src/sksl/ir/SkSLIntLiteral.h"
41#include "src/sksl/ir/SkSLInterfaceBlock.h"
42#include "src/sksl/ir/SkSLLayout.h"
Chris Daltonb0fd4b12019-10-29 13:41:22 -060043#include "src/sksl/ir/SkSLNop.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050044#include "src/sksl/ir/SkSLNullLiteral.h"
45#include "src/sksl/ir/SkSLPostfixExpression.h"
46#include "src/sksl/ir/SkSLPrefixExpression.h"
47#include "src/sksl/ir/SkSLReturnStatement.h"
48#include "src/sksl/ir/SkSLSetting.h"
49#include "src/sksl/ir/SkSLSwitchCase.h"
50#include "src/sksl/ir/SkSLSwitchStatement.h"
51#include "src/sksl/ir/SkSLSwizzle.h"
52#include "src/sksl/ir/SkSLTernaryExpression.h"
53#include "src/sksl/ir/SkSLUnresolvedFunction.h"
54#include "src/sksl/ir/SkSLVarDeclarations.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050055#include "src/sksl/ir/SkSLVariable.h"
56#include "src/sksl/ir/SkSLVariableReference.h"
57#include "src/sksl/ir/SkSLWhileStatement.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070058
59namespace SkSL {
60
61class AutoSymbolTable {
62public:
Ethan Nicholas11d53972016-11-28 11:23:23 -050063 AutoSymbolTable(IRGenerator* ir)
ethannicholasb3058bd2016-07-01 08:22:01 -070064 : fIR(ir)
65 , fPrevious(fIR->fSymbolTable) {
66 fIR->pushSymbolTable();
67 }
68
69 ~AutoSymbolTable() {
70 fIR->popSymbolTable();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -040071 SkASSERT(fPrevious == fIR->fSymbolTable);
ethannicholasb3058bd2016-07-01 08:22:01 -070072 }
73
74 IRGenerator* fIR;
75 std::shared_ptr<SymbolTable> fPrevious;
76};
77
ethannicholas22f939e2016-10-13 13:25:34 -070078class AutoLoopLevel {
79public:
Ethan Nicholas11d53972016-11-28 11:23:23 -050080 AutoLoopLevel(IRGenerator* ir)
ethannicholas22f939e2016-10-13 13:25:34 -070081 : fIR(ir) {
82 fIR->fLoopLevel++;
83 }
84
85 ~AutoLoopLevel() {
86 fIR->fLoopLevel--;
87 }
88
89 IRGenerator* fIR;
90};
91
Ethan Nicholasaf197692017-02-27 13:26:45 -050092class AutoSwitchLevel {
93public:
94 AutoSwitchLevel(IRGenerator* ir)
95 : fIR(ir) {
96 fIR->fSwitchLevel++;
97 }
98
99 ~AutoSwitchLevel() {
100 fIR->fSwitchLevel--;
101 }
102
103 IRGenerator* fIR;
104};
105
John Stiles941fc712020-09-19 12:47:10 +0000106class AutoDisableInline {
107public:
108 AutoDisableInline(IRGenerator* ir, bool canInline = false)
109 : fIR(ir) {
110 fOldCanInline = ir->fCanInline;
111 fIR->fCanInline &= canInline;
112 }
113
114 ~AutoDisableInline() {
115 fIR->fCanInline = fOldCanInline;
116 }
117
118 IRGenerator* fIR;
119 bool fOldCanInline;
120};
121
122IRGenerator::IRGenerator(const Context* context, Inliner* inliner,
123 std::shared_ptr<SymbolTable> symbolTable, ErrorReporter& errorReporter)
John Stiles7b463002020-08-31 17:29:21 -0400124 : fContext(*context)
John Stiles941fc712020-09-19 12:47:10 +0000125 , fInliner(inliner)
John Stiles7b463002020-08-31 17:29:21 -0400126 , fCurrentFunction(nullptr)
John Stiles7b463002020-08-31 17:29:21 -0400127 , fSymbolTable(symbolTable)
128 , fLoopLevel(0)
129 , fSwitchLevel(0)
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400130 , fErrors(errorReporter)
131 , fModifiers(new ModifiersPool()) {
John Stiles941fc712020-09-19 12:47:10 +0000132 SkASSERT(fInliner);
133}
ethannicholasb3058bd2016-07-01 08:22:01 -0700134
135void IRGenerator::pushSymbolTable() {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400136 fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable)));
ethannicholasb3058bd2016-07-01 08:22:01 -0700137}
138
139void IRGenerator::popSymbolTable() {
140 fSymbolTable = fSymbolTable->fParent;
141}
142
John Stiles194b9b92020-09-15 15:37:24 -0400143static void fill_caps(const SkSL::ShaderCapsClass& caps,
Ethan Nicholas762466e2017-06-29 10:03:38 -0400144 std::unordered_map<String, Program::Settings::Value>* capsMap) {
Brian Salomon23356442018-11-30 15:33:19 -0500145#define CAP(name) \
146 capsMap->insert(std::make_pair(String(#name), Program::Settings::Value(caps.name())))
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500147 CAP(fbFetchSupport);
Brian Salomond4013302018-04-04 13:58:33 +0000148 CAP(fbFetchNeedsCustomOutput);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500149 CAP(flatInterpolationSupport);
150 CAP(noperspectiveInterpolationSupport);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500151 CAP(externalTextureSupport);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500152 CAP(mustEnableAdvBlendEqs);
153 CAP(mustEnableSpecificAdvBlendEqs);
154 CAP(mustDeclareFragmentShaderOutput);
Michael Ludwig4f94ef62018-09-12 15:22:16 -0400155 CAP(mustDoOpBetweenFloorAndAbs);
Brian Salomonf8c187c2019-12-19 14:41:57 -0500156 CAP(mustGuardDivisionEvenAfterExplicitZeroCheck);
157 CAP(inBlendModesFailRandomlyForAllZeroVec);
Michael Ludwig24d438b2018-09-12 15:22:50 -0400158 CAP(atan2ImplementedAsAtanYOverX);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500159 CAP(canUseAnyFunctionInShader);
Chris Dalton47c8ed32017-11-15 18:27:09 -0700160 CAP(floatIs32Bits);
Ethan Nicholas07990de2017-07-18 09:47:43 -0400161 CAP(integerSupport);
John Stiles6f3015a2020-10-08 14:55:36 -0400162 CAP(builtinFMASupport);
163 CAP(builtinDeterminantSupport);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500164#undef CAP
165}
166
Ethan Nicholas3c6ae622018-04-24 13:06:09 -0400167void IRGenerator::start(const Program::Settings* settings,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400168 const ParsedModule& base,
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400169 bool isBuiltinCode) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500170 fSettings = settings;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400171 fSymbolTable = base.fSymbols;
172 fIntrinsics = base.fIntrinsics.get();
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400173 fIsBuiltinCode = isBuiltinCode;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500174 fCapsMap.clear();
175 if (settings->fCaps) {
176 fill_caps(*settings->fCaps, &fCapsMap);
Ethan Nicholas00543112018-07-31 09:44:36 -0400177 } else {
178 fCapsMap.insert(std::make_pair(String("integerSupport"),
179 Program::Settings::Value(true)));
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500180 }
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500181 this->pushSymbolTable();
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400182 fInvocations = -1;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500183 fInputs.reset();
Robert Phillipsfe8da172018-01-24 14:52:02 +0000184 fSkPerVertex = nullptr;
185 fRTAdjust = nullptr;
186 fRTAdjustInterfaceBlock = nullptr;
Brian Osman00a8b5b2020-10-02 09:06:04 -0400187 if (fIntrinsics) {
188 fIntrinsics->resetAlreadyIncluded();
Brian Osmane3dcb132020-10-08 10:27:29 -0400189 if (const ProgramElement* perVertexDecl = fIntrinsics->find(Compiler::PERVERTEX_NAME)) {
190 SkASSERT(perVertexDecl->is<InterfaceBlock>());
191 fSkPerVertex = perVertexDecl->as<InterfaceBlock>().fVariable;
Brian Osmanafa18ee2020-10-07 17:47:45 -0400192 }
Brian Osman00a8b5b2020-10-02 09:06:04 -0400193 }
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500194}
195
Ethan Nicholasfc994162019-06-06 10:04:27 -0400196std::unique_ptr<Extension> IRGenerator::convertExtension(int offset, StringFragment name) {
Brian Osman16f376f2020-09-02 12:30:59 -0400197 if (fKind != Program::kFragment_Kind &&
198 fKind != Program::kVertex_Kind &&
199 fKind != Program::kGeometry_Kind) {
200 fErrors.error(offset, "extensions are not allowed here");
201 return nullptr;
202 }
203
John Stilesfbd050b2020-08-03 13:21:46 -0400204 return std::make_unique<Extension>(offset, name);
ethannicholasb3058bd2016-07-01 08:22:01 -0700205}
206
Ethan Nicholasfc994162019-06-06 10:04:27 -0400207void IRGenerator::finish() {
208 this->popSymbolTable();
209 fSettings = nullptr;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400210 // releaseModifiers should have been called before now
211 SkASSERT(fModifiers->empty());
212}
213
214std::unique_ptr<ModifiersPool> IRGenerator::releaseModifiers() {
215 std::unique_ptr<ModifiersPool> result = std::move(fModifiers);
216 fModifiers = std::make_unique<ModifiersPool>();
217 return result;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400218}
219
Ethan Nicholas70728ef2020-05-28 07:09:00 -0400220std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& statement) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700221 switch (statement.fKind) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400222 case ASTNode::Kind::kBlock:
223 return this->convertBlock(statement);
224 case ASTNode::Kind::kVarDeclarations:
225 return this->convertVarDeclarationStatement(statement);
226 case ASTNode::Kind::kIf:
227 return this->convertIf(statement);
228 case ASTNode::Kind::kFor:
229 return this->convertFor(statement);
230 case ASTNode::Kind::kWhile:
231 return this->convertWhile(statement);
232 case ASTNode::Kind::kDo:
233 return this->convertDo(statement);
234 case ASTNode::Kind::kSwitch:
235 return this->convertSwitch(statement);
236 case ASTNode::Kind::kReturn:
237 return this->convertReturn(statement);
238 case ASTNode::Kind::kBreak:
239 return this->convertBreak(statement);
240 case ASTNode::Kind::kContinue:
241 return this->convertContinue(statement);
242 case ASTNode::Kind::kDiscard:
243 return this->convertDiscard(statement);
244 default:
245 // it's an expression
246 std::unique_ptr<Statement> result = this->convertExpressionStatement(statement);
Ethan Nicholase6592142020-09-08 10:22:09 -0400247 if (fRTAdjust && fKind == Program::kGeometry_Kind) {
248 SkASSERT(result->kind() == Statement::Kind::kExpression);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -0400249 Expression& expr = *result->as<ExpressionStatement>().expression();
Ethan Nicholase6592142020-09-08 10:22:09 -0400250 if (expr.kind() == Expression::Kind::kFunctionCall) {
John Stiles403a3632020-08-20 12:11:48 -0400251 FunctionCall& fc = expr.as<FunctionCall>();
Ethan Nicholased84b732020-10-08 11:45:44 -0400252 if (fc.function().isBuiltin() && fc.function().name() == "EmitVertex") {
Robert Phillipsfe8da172018-01-24 14:52:02 +0000253 std::vector<std::unique_ptr<Statement>> statements;
254 statements.push_back(getNormalizeSkPositionCode());
255 statements.push_back(std::move(result));
John Stilesfbd050b2020-08-03 13:21:46 -0400256 return std::make_unique<Block>(statement.fOffset, std::move(statements),
257 fSymbolTable);
Robert Phillipsfe8da172018-01-24 14:52:02 +0000258 }
259 }
260 }
261 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700262 }
263}
264
Ethan Nicholas70728ef2020-05-28 07:09:00 -0400265std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) {
266 std::vector<std::unique_ptr<Statement>> oldExtraStatements = std::move(fExtraStatements);
267 std::unique_ptr<Statement> result = this->convertSingleStatement(statement);
268 if (!result) {
269 fExtraStatements = std::move(oldExtraStatements);
270 return nullptr;
271 }
272 if (fExtraStatements.size()) {
273 fExtraStatements.push_back(std::move(result));
274 std::unique_ptr<Statement> block(new Block(-1, std::move(fExtraStatements), nullptr,
275 false));
276 fExtraStatements = std::move(oldExtraStatements);
277 return block;
278 }
279 fExtraStatements = std::move(oldExtraStatements);
280 return result;
281}
282
Ethan Nicholasfc994162019-06-06 10:04:27 -0400283std::unique_ptr<Block> IRGenerator::convertBlock(const ASTNode& block) {
284 SkASSERT(block.fKind == ASTNode::Kind::kBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 AutoSymbolTable table(this);
286 std::vector<std::unique_ptr<Statement>> statements;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400287 for (const auto& child : block) {
288 std::unique_ptr<Statement> statement = this->convertStatement(child);
ethannicholasb3058bd2016-07-01 08:22:01 -0700289 if (!statement) {
290 return nullptr;
291 }
292 statements.push_back(std::move(statement));
293 }
John Stilesfbd050b2020-08-03 13:21:46 -0400294 return std::make_unique<Block>(block.fOffset, std::move(statements), fSymbolTable);
ethannicholasb3058bd2016-07-01 08:22:01 -0700295}
296
Ethan Nicholasfc994162019-06-06 10:04:27 -0400297std::unique_ptr<Statement> IRGenerator::convertVarDeclarationStatement(const ASTNode& s) {
298 SkASSERT(s.fKind == ASTNode::Kind::kVarDeclarations);
Brian Osmanc0213602020-10-06 14:43:32 -0400299 auto decls = this->convertVarDeclarations(s, Variable::kLocal_Storage);
300 if (decls.empty()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 return nullptr;
302 }
Brian Osmanc0213602020-10-06 14:43:32 -0400303 if (decls.size() == 1) {
304 return std::move(decls.front());
305 } else {
306 return std::make_unique<Block>(s.fOffset, std::move(decls), /*symbols=*/nullptr,
307 /*isScope=*/false);
308 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700309}
310
Brian Osmanc0213602020-10-06 14:43:32 -0400311std::vector<std::unique_ptr<Statement>> IRGenerator::convertVarDeclarations(
312 const ASTNode& decls, Variable::Storage storage) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400313 SkASSERT(decls.fKind == ASTNode::Kind::kVarDeclarations);
John Stilesf621e232020-08-25 13:33:02 -0400314 auto declarationsIter = decls.begin();
315 const Modifiers& modifiers = declarationsIter++->getModifiers();
316 const ASTNode& rawType = *(declarationsIter++);
Brian Osmanc0213602020-10-06 14:43:32 -0400317 std::vector<std::unique_ptr<Statement>> varDecls;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400318 const Type* baseType = this->convertType(rawType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 if (!baseType) {
Brian Osmanc0213602020-10-06 14:43:32 -0400320 return {};
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 }
Brian Osman82329002020-07-21 09:39:27 -0400322 if (baseType->nonnullable() == *fContext.fFragmentProcessor_Type &&
323 storage != Variable::kGlobal_Storage) {
324 fErrors.error(decls.fOffset,
325 "variables of type '" + baseType->displayName() + "' must be global");
326 }
Brian Osman2fe83fe2019-12-16 13:17:59 -0500327 if (fKind != Program::kFragmentProcessor_Kind) {
328 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
Ethan Nicholase6592142020-09-08 10:22:09 -0400329 baseType->typeKind() == Type::TypeKind::kMatrix) {
Brian Osman2fe83fe2019-12-16 13:17:59 -0500330 fErrors.error(decls.fOffset, "'in' variables may not have matrix type");
331 }
Brian Osman088913a2019-12-19 15:44:56 -0500332 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
333 (modifiers.fFlags & Modifiers::kUniform_Flag)) {
334 fErrors.error(decls.fOffset,
335 "'in uniform' variables only permitted within fragment processors");
336 }
Brian Osman2fe83fe2019-12-16 13:17:59 -0500337 if (modifiers.fLayout.fWhen.fLength) {
338 fErrors.error(decls.fOffset, "'when' is only permitted within fragment processors");
339 }
340 if (modifiers.fLayout.fFlags & Layout::kTracked_Flag) {
341 fErrors.error(decls.fOffset, "'tracked' is only permitted within fragment processors");
342 }
343 if (modifiers.fLayout.fCType != Layout::CType::kDefault) {
344 fErrors.error(decls.fOffset, "'ctype' is only permitted within fragment processors");
345 }
346 if (modifiers.fLayout.fKey) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400347 fErrors.error(decls.fOffset, "'key' is only permitted within fragment processors");
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400348 }
Brian Osman2fe83fe2019-12-16 13:17:59 -0500349 }
Brian Osmana4b91692020-08-10 14:26:16 -0400350 if (fKind == Program::kPipelineStage_Kind) {
351 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
352 baseType->nonnullable() != *fContext.fFragmentProcessor_Type) {
353 fErrors.error(decls.fOffset, "'in' variables not permitted in runtime effects");
354 }
355 }
Brian Osman2fe83fe2019-12-16 13:17:59 -0500356 if (modifiers.fLayout.fKey && (modifiers.fFlags & Modifiers::kUniform_Flag)) {
357 fErrors.error(decls.fOffset, "'key' is not permitted on 'uniform' variables");
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400358 }
Brian Osmanf59a9612020-04-15 14:18:13 -0400359 if (modifiers.fLayout.fMarker.fLength) {
360 if (fKind != Program::kPipelineStage_Kind) {
361 fErrors.error(decls.fOffset, "'marker' is only permitted in runtime effects");
362 }
363 if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) {
364 fErrors.error(decls.fOffset, "'marker' is only permitted on 'uniform' variables");
365 }
366 if (*baseType != *fContext.fFloat4x4_Type) {
367 fErrors.error(decls.fOffset, "'marker' is only permitted on float4x4 variables");
368 }
369 }
Brian Osmanb32d66b2020-04-30 17:12:03 -0400370 if (modifiers.fLayout.fFlags & Layout::kSRGBUnpremul_Flag) {
371 if (fKind != Program::kPipelineStage_Kind) {
372 fErrors.error(decls.fOffset, "'srgb_unpremul' is only permitted in runtime effects");
373 }
374 if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) {
375 fErrors.error(decls.fOffset,
376 "'srgb_unpremul' is only permitted on 'uniform' variables");
377 }
378 auto validColorXformType = [](const Type& t) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400379 return t.typeKind() == Type::TypeKind::kVector && t.componentType().isFloat() &&
Brian Osmanb32d66b2020-04-30 17:12:03 -0400380 (t.columns() == 3 || t.columns() == 4);
381 };
Ethan Nicholase6592142020-09-08 10:22:09 -0400382 if (!validColorXformType(*baseType) && !(baseType->typeKind() == Type::TypeKind::kArray &&
Brian Osmanb32d66b2020-04-30 17:12:03 -0400383 validColorXformType(baseType->componentType()))) {
384 fErrors.error(decls.fOffset,
385 "'srgb_unpremul' is only permitted on half3, half4, float3, or float4 "
386 "variables");
387 }
388 }
Brian Osman3c358422020-03-23 10:44:12 -0400389 if (modifiers.fFlags & Modifiers::kVarying_Flag) {
390 if (fKind != Program::kPipelineStage_Kind) {
391 fErrors.error(decls.fOffset, "'varying' is only permitted in runtime effects");
392 }
393 if (!baseType->isFloat() &&
Ethan Nicholase6592142020-09-08 10:22:09 -0400394 !(baseType->typeKind() == Type::TypeKind::kVector &&
395 baseType->componentType().isFloat())) {
Brian Osman3c358422020-03-23 10:44:12 -0400396 fErrors.error(decls.fOffset, "'varying' must be float scalar or vector");
397 }
398 }
Ethan Nicholas63d7ee32020-08-17 10:57:12 -0400399 int permitted = Modifiers::kConst_Flag;
400 if (storage == Variable::kGlobal_Storage) {
401 permitted |= Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
402 Modifiers::kFlat_Flag | Modifiers::kVarying_Flag |
403 Modifiers::kNoPerspective_Flag | Modifiers::kPLS_Flag |
404 Modifiers::kPLSIn_Flag | Modifiers::kPLSOut_Flag |
405 Modifiers::kRestrict_Flag | Modifiers::kVolatile_Flag |
406 Modifiers::kReadOnly_Flag | Modifiers::kWriteOnly_Flag |
407 Modifiers::kCoherent_Flag | Modifiers::kBuffer_Flag;
408 }
409 this->checkModifiers(decls.fOffset, modifiers, permitted);
John Stilesf621e232020-08-25 13:33:02 -0400410 for (; declarationsIter != decls.end(); ++declarationsIter) {
411 const ASTNode& varDecl = *declarationsIter;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400412 if (modifiers.fLayout.fLocation == 0 && modifiers.fLayout.fIndex == 0 &&
413 (modifiers.fFlags & Modifiers::kOut_Flag) && fKind == Program::kFragment_Kind &&
414 varDecl.getVarData().fName != "sk_FragColor") {
415 fErrors.error(varDecl.fOffset,
Ethan Nicholas6c942712018-03-16 09:45:11 -0400416 "out location=0, index=0 is reserved for sk_FragColor");
417 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400418 const ASTNode::VarData& varData = varDecl.getVarData();
ethannicholasd598f792016-07-25 10:08:54 -0700419 const Type* type = baseType;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700420 std::vector<std::unique_ptr<Expression>> sizes;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400421 auto iter = varDecl.begin();
422 for (size_t i = 0; i < varData.fSizeCount; ++i, ++iter) {
423 const ASTNode& rawSize = *iter;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700424 if (rawSize) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400425 auto size = this->coerce(this->convertExpression(rawSize), *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 if (!size) {
Brian Osmanc0213602020-10-06 14:43:32 -0400427 return {};
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 }
Ethan Nicholase2c49992020-10-05 11:49:11 -0400429 String name(type->name());
Ethan Nicholas50afc172017-02-16 14:49:57 -0500430 int64_t count;
Ethan Nicholase6592142020-09-08 10:22:09 -0400431 if (size->kind() == Expression::Kind::kIntLiteral) {
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400432 count = size->as<IntLiteral>().value();
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 if (count <= 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700434 fErrors.error(size->fOffset, "array size must be positive");
Brian Osmanc0213602020-10-06 14:43:32 -0400435 return {};
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 }
437 name += "[" + to_string(count) + "]";
438 } else {
Ethan Nicholas66d80062019-09-09 14:50:51 -0400439 fErrors.error(size->fOffset, "array size must be specified");
Brian Osmanc0213602020-10-06 14:43:32 -0400440 return {};
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 }
John Stiles3ae071e2020-08-05 15:29:29 -0400442 type = fSymbolTable->takeOwnershipOfSymbol(
Ethan Nicholase6592142020-09-08 10:22:09 -0400443 std::make_unique<Type>(name, Type::TypeKind::kArray, *type, (int)count));
ethannicholas14fe8cc2016-09-07 13:37:16 -0700444 sizes.push_back(std::move(size));
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 } else {
John Stiles3ae071e2020-08-05 15:29:29 -0400446 type = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>(
Brian Osmane8c26082020-10-01 17:22:45 -0400447 type->name() + "[]", Type::TypeKind::kArray, *type, Type::kUnsizedArray));
ethannicholas14fe8cc2016-09-07 13:37:16 -0700448 sizes.push_back(nullptr);
ethannicholasb3058bd2016-07-01 08:22:01 -0700449 }
450 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400451 auto var = std::make_unique<Variable>(varDecl.fOffset, fModifiers->handle(modifiers),
452 varData.fName, type, fIsBuiltinCode, storage);
Ethan Nicholase2c49992020-10-05 11:49:11 -0400453 if (var->name() == Compiler::RTADJUST_NAME) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400454 SkASSERT(!fRTAdjust);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400455 SkASSERT(var->type() == *fContext.fFloat4_Type);
Robert Phillipsfe8da172018-01-24 14:52:02 +0000456 fRTAdjust = var.get();
457 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700458 std::unique_ptr<Expression> value;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400459 if (iter != varDecl.end()) {
460 value = this->convertExpression(*iter);
ethannicholasb3058bd2016-07-01 08:22:01 -0700461 if (!value) {
Brian Osmanc0213602020-10-06 14:43:32 -0400462 return {};
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 }
ethannicholasd598f792016-07-25 10:08:54 -0700464 value = this->coerce(std::move(value), *type);
Ethan Nicholas68dd2c12018-03-01 15:05:17 -0500465 if (!value) {
Brian Osmanc0213602020-10-06 14:43:32 -0400466 return {};
Ethan Nicholas68dd2c12018-03-01 15:05:17 -0500467 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400468 var->setInitialValue(value.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400470 Symbol* symbol = (*fSymbolTable)[var->name()];
Ethan Nicholase2c49992020-10-05 11:49:11 -0400471 if (symbol && storage == Variable::kGlobal_Storage && var->name() == "sk_FragColor") {
John Stilesce591b72020-08-27 11:47:30 -0400472 // Already defined, ignore.
473 } else if (symbol && storage == Variable::kGlobal_Storage &&
Ethan Nicholase6592142020-09-08 10:22:09 -0400474 symbol->kind() == Symbol::Kind::kVariable &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400475 symbol->as<Variable>().modifiers().fLayout.fBuiltin >= 0) {
John Stilesce591b72020-08-27 11:47:30 -0400476 // Already defined, just update the modifiers.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400477 symbol->as<Variable>().setModifiersHandle(var->modifiersHandle());
ethannicholasf789b382016-08-03 12:43:36 -0700478 } else {
John Stilesb8cc6652020-10-08 09:12:07 -0400479 varDecls.push_back(std::make_unique<VarDeclaration>(
Brian Osmanc0213602020-10-06 14:43:32 -0400480 var.get(), baseType, std::move(sizes), std::move(value)));
John Stilesb8cc6652020-10-08 09:12:07 -0400481 fSymbolTable->add(std::move(var));
ethannicholasf789b382016-08-03 12:43:36 -0700482 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700483 }
Brian Osmanc0213602020-10-06 14:43:32 -0400484 return varDecls;
ethannicholasb3058bd2016-07-01 08:22:01 -0700485}
486
Ethan Nicholasfc994162019-06-06 10:04:27 -0400487std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(const ASTNode& m) {
Brian Osman16f376f2020-09-02 12:30:59 -0400488 if (fKind != Program::kFragment_Kind &&
489 fKind != Program::kVertex_Kind &&
490 fKind != Program::kGeometry_Kind) {
491 fErrors.error(m.fOffset, "layout qualifiers are not allowed here");
492 return nullptr;
493 }
494
Ethan Nicholasfc994162019-06-06 10:04:27 -0400495 SkASSERT(m.fKind == ASTNode::Kind::kModifiers);
496 Modifiers modifiers = m.getModifiers();
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400497 if (modifiers.fLayout.fInvocations != -1) {
Ethan Nicholasf06576b2019-04-03 15:45:25 -0400498 if (fKind != Program::kGeometry_Kind) {
499 fErrors.error(m.fOffset, "'invocations' is only legal in geometry shaders");
500 return nullptr;
501 }
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400502 fInvocations = modifiers.fLayout.fInvocations;
Chris Daltonf1b47bb2017-10-06 11:57:51 -0600503 if (fSettings->fCaps && !fSettings->fCaps->gsInvocationsSupport()) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400504 modifiers.fLayout.fInvocations = -1;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400505 Variable& invocationId = (*fSymbolTable)["sk_InvocationID"]->as<Variable>();
506 Modifiers modifiers = invocationId.modifiers();
507 modifiers.fFlags = 0;
508 modifiers.fLayout.fBuiltin = -1;
509 invocationId.setModifiersHandle(fModifiers->handle(modifiers));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400510 if (modifiers.fLayout.description() == "") {
511 return nullptr;
512 }
513 }
514 }
515 if (modifiers.fLayout.fMaxVertices != -1 && fInvocations > 0 && fSettings->fCaps &&
Chris Daltonf1b47bb2017-10-06 11:57:51 -0600516 !fSettings->fCaps->gsInvocationsSupport()) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400517 modifiers.fLayout.fMaxVertices *= fInvocations;
518 }
John Stilesfbd050b2020-08-03 13:21:46 -0400519 return std::make_unique<ModifiersDeclaration>(modifiers);
ethannicholas5961bc92016-10-12 06:39:56 -0700520}
521
John Stilesad2319f2020-09-02 15:01:47 -0400522std::unique_ptr<Statement> IRGenerator::convertIf(const ASTNode& n) {
523 SkASSERT(n.fKind == ASTNode::Kind::kIf);
524 auto iter = n.begin();
525 std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)),
526 *fContext.fBool_Type);
527 if (!test) {
528 return nullptr;
529 }
530 std::unique_ptr<Statement> ifTrue = this->convertStatement(*(iter++));
531 if (!ifTrue) {
532 return nullptr;
533 }
John Stilesad2319f2020-09-02 15:01:47 -0400534 std::unique_ptr<Statement> ifFalse;
535 if (iter != n.end()) {
536 ifFalse = this->convertStatement(*(iter++));
537 if (!ifFalse) {
538 return nullptr;
539 }
John Stilesad2319f2020-09-02 15:01:47 -0400540 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400541 if (test->kind() == Expression::Kind::kBoolLiteral) {
John Stilesad2319f2020-09-02 15:01:47 -0400542 // static boolean value, fold down to a single branch
Ethan Nicholas59d660c2020-09-28 09:18:15 -0400543 if (test->as<BoolLiteral>().value()) {
John Stilesad2319f2020-09-02 15:01:47 -0400544 return ifTrue;
545 } else if (ifFalse) {
546 return ifFalse;
547 } else {
548 // False & no else clause. Not an error, so don't return null!
John Stiles2ff97062020-09-02 15:02:01 -0400549 return std::make_unique<Nop>();
John Stilesad2319f2020-09-02 15:01:47 -0400550 }
551 }
John Stilesb61ee902020-09-21 12:26:59 -0400552 auto ifStmt = std::make_unique<IfStatement>(n.fOffset, n.getBool(), std::move(test),
553 std::move(ifTrue), std::move(ifFalse));
Ethan Nicholas8c44eca2020-10-07 16:47:09 -0400554 fInliner->ensureScopedBlocks(ifStmt->ifTrue().get(), ifStmt.get());
555 fInliner->ensureScopedBlocks(ifStmt->ifFalse().get(), ifStmt.get());
John Stilesb61ee902020-09-21 12:26:59 -0400556 return std::move(ifStmt);
John Stilesad2319f2020-09-02 15:01:47 -0400557}
558
Ethan Nicholasfc994162019-06-06 10:04:27 -0400559std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) {
560 SkASSERT(f.fKind == ASTNode::Kind::kFor);
ethannicholas22f939e2016-10-13 13:25:34 -0700561 AutoLoopLevel level(this);
ethannicholasb3058bd2016-07-01 08:22:01 -0700562 AutoSymbolTable table(this);
ethannicholas22f939e2016-10-13 13:25:34 -0700563 std::unique_ptr<Statement> initializer;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400564 auto iter = f.begin();
565 if (*iter) {
566 initializer = this->convertStatement(*iter);
ethannicholas22f939e2016-10-13 13:25:34 -0700567 if (!initializer) {
568 return nullptr;
569 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400571 ++iter;
ethannicholas22f939e2016-10-13 13:25:34 -0700572 std::unique_ptr<Expression> test;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400573 if (*iter) {
John Stiles941fc712020-09-19 12:47:10 +0000574 AutoDisableInline disableInline(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400575 test = this->coerce(this->convertExpression(*iter), *fContext.fBool_Type);
ethannicholas22f939e2016-10-13 13:25:34 -0700576 if (!test) {
577 return nullptr;
578 }
John Stiles941fc712020-09-19 12:47:10 +0000579
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400581 ++iter;
ethannicholas22f939e2016-10-13 13:25:34 -0700582 std::unique_ptr<Expression> next;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400583 if (*iter) {
John Stiles941fc712020-09-19 12:47:10 +0000584 AutoDisableInline disableInline(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400585 next = this->convertExpression(*iter);
ethannicholas22f939e2016-10-13 13:25:34 -0700586 if (!next) {
587 return nullptr;
588 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400590 ++iter;
591 std::unique_ptr<Statement> statement = this->convertStatement(*iter);
ethannicholasb3058bd2016-07-01 08:22:01 -0700592 if (!statement) {
593 return nullptr;
594 }
John Stilesb61ee902020-09-21 12:26:59 -0400595 auto forStmt = std::make_unique<ForStatement>(f.fOffset, std::move(initializer),
596 std::move(test), std::move(next),
597 std::move(statement), fSymbolTable);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -0400598 fInliner->ensureScopedBlocks(forStmt->statement().get(), forStmt.get());
John Stilesb61ee902020-09-21 12:26:59 -0400599 return std::move(forStmt);
ethannicholasb3058bd2016-07-01 08:22:01 -0700600}
601
Ethan Nicholasfc994162019-06-06 10:04:27 -0400602std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) {
603 SkASSERT(w.fKind == ASTNode::Kind::kWhile);
ethannicholas22f939e2016-10-13 13:25:34 -0700604 AutoLoopLevel level(this);
John Stiles941fc712020-09-19 12:47:10 +0000605 std::unique_ptr<Expression> test;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400606 auto iter = w.begin();
John Stiles941fc712020-09-19 12:47:10 +0000607 {
608 AutoDisableInline disableInline(this);
609 test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type);
610 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700611 if (!test) {
612 return nullptr;
613 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400614 std::unique_ptr<Statement> statement = this->convertStatement(*(iter++));
ethannicholasb3058bd2016-07-01 08:22:01 -0700615 if (!statement) {
616 return nullptr;
617 }
John Stilesb61ee902020-09-21 12:26:59 -0400618 auto whileStmt = std::make_unique<WhileStatement>(w.fOffset, std::move(test),
619 std::move(statement));
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400620 fInliner->ensureScopedBlocks(whileStmt->statement().get(), whileStmt.get());
John Stilesb61ee902020-09-21 12:26:59 -0400621 return std::move(whileStmt);
ethannicholasb3058bd2016-07-01 08:22:01 -0700622}
623
Ethan Nicholasfc994162019-06-06 10:04:27 -0400624std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) {
625 SkASSERT(d.fKind == ASTNode::Kind::kDo);
ethannicholas22f939e2016-10-13 13:25:34 -0700626 AutoLoopLevel level(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400627 auto iter = d.begin();
628 std::unique_ptr<Statement> statement = this->convertStatement(*(iter++));
629 if (!statement) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700630 return nullptr;
631 }
John Stiles941fc712020-09-19 12:47:10 +0000632 std::unique_ptr<Expression> test;
633 {
634 AutoDisableInline disableInline(this);
635 test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type);
636 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400637 if (!test) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700638 return nullptr;
639 }
John Stilesb61ee902020-09-21 12:26:59 -0400640 auto doStmt = std::make_unique<DoStatement>(d.fOffset, std::move(statement), std::move(test));
Ethan Nicholas1fd61162020-09-28 13:14:19 -0400641 fInliner->ensureScopedBlocks(doStmt->statement().get(), doStmt.get());
John Stilesb61ee902020-09-21 12:26:59 -0400642 return std::move(doStmt);
ethannicholasb3058bd2016-07-01 08:22:01 -0700643}
644
Ethan Nicholasfc994162019-06-06 10:04:27 -0400645std::unique_ptr<Statement> IRGenerator::convertSwitch(const ASTNode& s) {
646 SkASSERT(s.fKind == ASTNode::Kind::kSwitch);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500647 AutoSwitchLevel level(this);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400648 auto iter = s.begin();
649 std::unique_ptr<Expression> value = this->convertExpression(*(iter++));
Ethan Nicholasaf197692017-02-27 13:26:45 -0500650 if (!value) {
651 return nullptr;
652 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400653 if (value->type() != *fContext.fUInt_Type &&
654 value->type().typeKind() != Type::TypeKind::kEnum) {
Ethan Nicholasaf197692017-02-27 13:26:45 -0500655 value = this->coerce(std::move(value), *fContext.fInt_Type);
656 if (!value) {
657 return nullptr;
658 }
659 }
660 AutoSymbolTable table(this);
661 std::unordered_set<int> caseValues;
662 std::vector<std::unique_ptr<SwitchCase>> cases;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400663 for (; iter != s.end(); ++iter) {
664 const ASTNode& c = *iter;
665 SkASSERT(c.fKind == ASTNode::Kind::kSwitchCase);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500666 std::unique_ptr<Expression> caseValue;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400667 auto childIter = c.begin();
668 if (*childIter) {
669 caseValue = this->convertExpression(*childIter);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500670 if (!caseValue) {
671 return nullptr;
672 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400673 caseValue = this->coerce(std::move(caseValue), value->type());
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500674 if (!caseValue) {
675 return nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500676 }
Brian Osman3e3db6c2020-08-14 09:42:12 -0400677 int64_t v = 0;
678 if (!this->getConstantInt(*caseValue, &v)) {
679 fErrors.error(caseValue->fOffset, "case value must be a constant integer");
Ethan Nicholasaf197692017-02-27 13:26:45 -0500680 return nullptr;
681 }
Ethan Nicholasaf197692017-02-27 13:26:45 -0500682 if (caseValues.find(v) != caseValues.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700683 fErrors.error(caseValue->fOffset, "duplicate case value");
Ethan Nicholasaf197692017-02-27 13:26:45 -0500684 }
685 caseValues.insert(v);
686 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400687 ++childIter;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500688 std::vector<std::unique_ptr<Statement>> statements;
Ethan Nicholasfc994162019-06-06 10:04:27 -0400689 for (; childIter != c.end(); ++childIter) {
690 std::unique_ptr<Statement> converted = this->convertStatement(*childIter);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500691 if (!converted) {
692 return nullptr;
693 }
694 statements.push_back(std::move(converted));
695 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400696 cases.emplace_back(new SwitchCase(c.fOffset, std::move(caseValue),
Ethan Nicholasaf197692017-02-27 13:26:45 -0500697 std::move(statements)));
698 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400699 return std::unique_ptr<Statement>(new SwitchStatement(s.fOffset, s.getBool(),
Ethan Nicholasc432b0c2017-07-18 13:22:37 -0400700 std::move(value), std::move(cases),
701 fSymbolTable));
Ethan Nicholasaf197692017-02-27 13:26:45 -0500702}
703
Ethan Nicholasfc994162019-06-06 10:04:27 -0400704std::unique_ptr<Statement> IRGenerator::convertExpressionStatement(const ASTNode& s) {
705 std::unique_ptr<Expression> e = this->convertExpression(s);
ethannicholasb3058bd2016-07-01 08:22:01 -0700706 if (!e) {
707 return nullptr;
708 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 return std::unique_ptr<Statement>(new ExpressionStatement(std::move(e)));
710}
711
Ethan Nicholasfc994162019-06-06 10:04:27 -0400712std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTNode& r) {
713 SkASSERT(r.fKind == ASTNode::Kind::kReturn);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400714 SkASSERT(fCurrentFunction);
Robert Phillipsfe8da172018-01-24 14:52:02 +0000715 // early returns from a vertex main function will bypass the sk_Position normalization, so
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400716 // SkASSERT that we aren't doing that. It is of course possible to fix this by adding a
Robert Phillipsfe8da172018-01-24 14:52:02 +0000717 // normalization before each return, but it will probably never actually be necessary.
Ethan Nicholase2c49992020-10-05 11:49:11 -0400718 SkASSERT(Program::kVertex_Kind != fKind || !fRTAdjust || "main" != fCurrentFunction->name());
Ethan Nicholasfc994162019-06-06 10:04:27 -0400719 if (r.begin() != r.end()) {
720 std::unique_ptr<Expression> result = this->convertExpression(*r.begin());
ethannicholasb3058bd2016-07-01 08:22:01 -0700721 if (!result) {
722 return nullptr;
723 }
Ethan Nicholased84b732020-10-08 11:45:44 -0400724 if (fCurrentFunction->returnType() == *fContext.fVoid_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700725 fErrors.error(result->fOffset, "may not return a value from a void function");
Brian Osman5eea6ae2020-09-09 16:05:18 -0400726 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -0700727 } else {
Ethan Nicholased84b732020-10-08 11:45:44 -0400728 result = this->coerce(std::move(result), fCurrentFunction->returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 if (!result) {
730 return nullptr;
731 }
732 }
733 return std::unique_ptr<Statement>(new ReturnStatement(std::move(result)));
734 } else {
Ethan Nicholased84b732020-10-08 11:45:44 -0400735 if (fCurrentFunction->returnType() != *fContext.fVoid_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700736 fErrors.error(r.fOffset, "expected function to return '" +
Ethan Nicholased84b732020-10-08 11:45:44 -0400737 fCurrentFunction->returnType().displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -0700738 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700739 return std::unique_ptr<Statement>(new ReturnStatement(r.fOffset));
ethannicholasb3058bd2016-07-01 08:22:01 -0700740 }
741}
742
Ethan Nicholasfc994162019-06-06 10:04:27 -0400743std::unique_ptr<Statement> IRGenerator::convertBreak(const ASTNode& b) {
744 SkASSERT(b.fKind == ASTNode::Kind::kBreak);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500745 if (fLoopLevel > 0 || fSwitchLevel > 0) {
John Stilesb61ee902020-09-21 12:26:59 -0400746 return std::make_unique<BreakStatement>(b.fOffset);
ethannicholas22f939e2016-10-13 13:25:34 -0700747 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700748 fErrors.error(b.fOffset, "break statement must be inside a loop or switch");
ethannicholas22f939e2016-10-13 13:25:34 -0700749 return nullptr;
750 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700751}
752
Ethan Nicholasfc994162019-06-06 10:04:27 -0400753std::unique_ptr<Statement> IRGenerator::convertContinue(const ASTNode& c) {
754 SkASSERT(c.fKind == ASTNode::Kind::kContinue);
ethannicholas22f939e2016-10-13 13:25:34 -0700755 if (fLoopLevel > 0) {
John Stilesb61ee902020-09-21 12:26:59 -0400756 return std::make_unique<ContinueStatement>(c.fOffset);
ethannicholas22f939e2016-10-13 13:25:34 -0700757 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700758 fErrors.error(c.fOffset, "continue statement must be inside a loop");
ethannicholas22f939e2016-10-13 13:25:34 -0700759 return nullptr;
760 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700761}
762
Ethan Nicholasfc994162019-06-06 10:04:27 -0400763std::unique_ptr<Statement> IRGenerator::convertDiscard(const ASTNode& d) {
764 SkASSERT(d.fKind == ASTNode::Kind::kDiscard);
John Stilesb61ee902020-09-21 12:26:59 -0400765 return std::make_unique<DiscardStatement>(d.fOffset);
ethannicholasb3058bd2016-07-01 08:22:01 -0700766}
767
Ethan Nicholasaae47c82017-11-10 15:34:03 -0500768std::unique_ptr<Block> IRGenerator::applyInvocationIDWorkaround(std::unique_ptr<Block> main) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400769 Layout invokeLayout;
770 Modifiers invokeModifiers(invokeLayout, Modifiers::kHasSideEffects_Flag);
John Stilesb8cc6652020-10-08 09:12:07 -0400771 const FunctionDeclaration* invokeDecl =
Ethan Nicholased84b732020-10-08 11:45:44 -0400772 fSymbolTable->add(std::make_unique<FunctionDeclaration>(
773 /*offset=*/-1,
774 fModifiers->handle(invokeModifiers),
775 "_invoke",
776 std::vector<Variable*>(),
777 fContext.fVoid_Type.get(),
778 /*builtin=*/false));
John Stilesb9af7232020-08-20 15:57:48 -0400779 fProgramElements->push_back(std::make_unique<FunctionDefinition>(/*offset=*/-1,
780 *invokeDecl,
781 std::move(main)));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400782
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000783 std::vector<std::unique_ptr<VarDeclaration>> variables;
John Stilesb9af7232020-08-20 15:57:48 -0400784 const Variable* loopIdx = &(*fSymbolTable)["sk_InvocationID"]->as<Variable>();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700785 std::unique_ptr<Expression> test(new BinaryExpression(-1,
Brian Osman79457ef2020-09-24 15:01:27 -0400786 std::unique_ptr<Expression>(new VariableReference(-1, loopIdx)),
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400787 Token::Kind::TK_LT,
John Stilesfbd050b2020-08-03 13:21:46 -0400788 std::make_unique<IntLiteral>(fContext, -1, fInvocations),
Ethan Nicholas30d30222020-09-11 12:27:26 -0400789 fContext.fBool_Type.get()));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400790 std::unique_ptr<Expression> next(new PostfixExpression(
791 std::unique_ptr<Expression>(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700792 new VariableReference(-1,
Brian Osman79457ef2020-09-24 15:01:27 -0400793 loopIdx,
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400794 VariableReference::kReadWrite_RefKind)),
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400795 Token::Kind::TK_PLUSPLUS));
Ethan Nicholasfc994162019-06-06 10:04:27 -0400796 ASTNode endPrimitiveID(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier, "EndPrimitive");
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400797 std::unique_ptr<Expression> endPrimitive = this->convertExpression(endPrimitiveID);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400798 SkASSERT(endPrimitive);
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400799
800 std::vector<std::unique_ptr<Statement>> loopBody;
801 std::vector<std::unique_ptr<Expression>> invokeArgs;
802 loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700803 this->call(-1,
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400804 *invokeDecl,
805 std::vector<std::unique_ptr<Expression>>()))));
806 loopBody.push_back(std::unique_ptr<Statement>(new ExpressionStatement(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700807 this->call(-1,
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400808 std::move(endPrimitive),
809 std::vector<std::unique_ptr<Expression>>()))));
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700810 std::unique_ptr<Expression> assignment(new BinaryExpression(-1,
Brian Osman79457ef2020-09-24 15:01:27 -0400811 std::unique_ptr<Expression>(new VariableReference(-1, loopIdx,
Ethan Nicholas4fadce42020-07-30 13:29:30 -0400812 VariableReference::kWrite_RefKind)),
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400813 Token::Kind::TK_EQ,
John Stilesfbd050b2020-08-03 13:21:46 -0400814 std::make_unique<IntLiteral>(fContext, -1, 0),
Ethan Nicholas30d30222020-09-11 12:27:26 -0400815 fContext.fInt_Type.get()));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400816 std::unique_ptr<Statement> initializer(new ExpressionStatement(std::move(assignment)));
817 std::unique_ptr<Statement> loop = std::unique_ptr<Statement>(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700818 new ForStatement(-1,
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400819 std::move(initializer),
820 std::move(test),
821 std::move(next),
John Stilesfbd050b2020-08-03 13:21:46 -0400822 std::make_unique<Block>(-1, std::move(loopBody)),
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400823 fSymbolTable));
824 std::vector<std::unique_ptr<Statement>> children;
825 children.push_back(std::move(loop));
John Stilesfbd050b2020-08-03 13:21:46 -0400826 return std::make_unique<Block>(-1, std::move(children));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400827}
828
Robert Phillipsfe8da172018-01-24 14:52:02 +0000829std::unique_ptr<Statement> IRGenerator::getNormalizeSkPositionCode() {
Ethan Nicholasb809efb2018-04-12 14:39:21 -0400830 // sk_Position = float4(sk_Position.xy * rtAdjust.xz + sk_Position.ww * rtAdjust.yw,
Robert Phillipsfe8da172018-01-24 14:52:02 +0000831 // 0,
832 // sk_Position.w);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400833 SkASSERT(fSkPerVertex && fRTAdjust);
Robert Phillipsfe8da172018-01-24 14:52:02 +0000834 #define REF(var) std::unique_ptr<Expression>(\
Brian Osman79457ef2020-09-24 15:01:27 -0400835 new VariableReference(-1, var, VariableReference::kRead_RefKind))
Ethan Nicholas4fadce42020-07-30 13:29:30 -0400836 #define WREF(var) std::unique_ptr<Expression>(\
Brian Osman79457ef2020-09-24 15:01:27 -0400837 new VariableReference(-1, var, VariableReference::kWrite_RefKind))
Robert Phillipsfe8da172018-01-24 14:52:02 +0000838 #define FIELD(var, idx) std::unique_ptr<Expression>(\
839 new FieldAccess(REF(var), idx, FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
Ethan Nicholas4fadce42020-07-30 13:29:30 -0400840 #define POS std::unique_ptr<Expression>(new FieldAccess(WREF(fSkPerVertex), 0, \
Brian Osmanafa18ee2020-10-07 17:47:45 -0400841 FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
Robert Phillipsfe8da172018-01-24 14:52:02 +0000842 #define ADJUST (fRTAdjustInterfaceBlock ? \
843 FIELD(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex) : \
844 REF(fRTAdjust))
Ethan Nicholasb809efb2018-04-12 14:39:21 -0400845 #define SWIZZLE(expr, ...) std::unique_ptr<Expression>(new Swizzle(fContext, expr, \
846 { __VA_ARGS__ }))
847 #define OP(left, op, right) std::unique_ptr<Expression>( \
848 new BinaryExpression(-1, left, op, right, \
Ethan Nicholas30d30222020-09-11 12:27:26 -0400849 fContext.fFloat2_Type.get()))
Robert Phillipsfe8da172018-01-24 14:52:02 +0000850 std::vector<std::unique_ptr<Expression>> children;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400851 children.push_back(OP(OP(SWIZZLE(POS, 0, 1), Token::Kind::TK_STAR, SWIZZLE(ADJUST, 0, 2)),
852 Token::Kind::TK_PLUS,
853 OP(SWIZZLE(POS, 3, 3), Token::Kind::TK_STAR, SWIZZLE(ADJUST, 1, 3))));
Robert Phillipsfe8da172018-01-24 14:52:02 +0000854 children.push_back(std::unique_ptr<Expression>(new FloatLiteral(fContext, -1, 0.0)));
855 children.push_back(SWIZZLE(POS, 3));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 std::unique_ptr<Expression> result = OP(POS, Token::Kind::TK_EQ,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400857 std::unique_ptr<Expression>(new Constructor(
858 -1,
859 fContext.fFloat4_Type.get(),
860 std::move(children))));
Robert Phillipsfe8da172018-01-24 14:52:02 +0000861 return std::unique_ptr<Statement>(new ExpressionStatement(std::move(result)));
862}
863
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400864template<typename T>
865class AutoClear {
866public:
867 AutoClear(T* container)
868 : fContainer(container) {
869 SkASSERT(container->empty());
870 }
871
872 ~AutoClear() {
873 fContainer->clear();
874 }
875
876private:
877 T* fContainer;
878};
879
John Stilesb8e010c2020-08-11 18:05:39 -0400880template <typename T> AutoClear(T* c) -> AutoClear<T>;
881
Ethan Nicholas63d7ee32020-08-17 10:57:12 -0400882void IRGenerator::checkModifiers(int offset, const Modifiers& modifiers, int permitted) {
883 int flags = modifiers.fFlags;
884 #define CHECK(flag, name) \
885 if (!flags) return; \
886 if (flags & flag) { \
887 if (!(permitted & flag)) { \
888 fErrors.error(offset, "'" name "' is not permitted here"); \
889 } \
890 flags &= ~flag; \
891 }
892 CHECK(Modifiers::kConst_Flag, "const")
893 CHECK(Modifiers::kIn_Flag, "in")
894 CHECK(Modifiers::kOut_Flag, "out")
895 CHECK(Modifiers::kUniform_Flag, "uniform")
896 CHECK(Modifiers::kFlat_Flag, "flat")
897 CHECK(Modifiers::kNoPerspective_Flag, "noperspective")
898 CHECK(Modifiers::kReadOnly_Flag, "readonly")
899 CHECK(Modifiers::kWriteOnly_Flag, "writeonly")
900 CHECK(Modifiers::kCoherent_Flag, "coherent")
901 CHECK(Modifiers::kVolatile_Flag, "volatile")
902 CHECK(Modifiers::kRestrict_Flag, "restrict")
903 CHECK(Modifiers::kBuffer_Flag, "buffer")
904 CHECK(Modifiers::kHasSideEffects_Flag, "sk_has_side_effects")
905 CHECK(Modifiers::kPLS_Flag, "__pixel_localEXT")
906 CHECK(Modifiers::kPLSIn_Flag, "__pixel_local_inEXT")
907 CHECK(Modifiers::kPLSOut_Flag, "__pixel_local_outEXT")
908 CHECK(Modifiers::kVarying_Flag, "varying")
Ethan Nicholasf3c8f5d2020-08-20 13:09:14 +0000909 CHECK(Modifiers::kInline_Flag, "inline")
Ethan Nicholas63d7ee32020-08-17 10:57:12 -0400910 SkASSERT(flags == 0);
911}
912
Ethan Nicholasfc994162019-06-06 10:04:27 -0400913void IRGenerator::convertFunction(const ASTNode& f) {
John Stilesb8e010c2020-08-11 18:05:39 -0400914 AutoClear clear(&fReferencedIntrinsics);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400915 auto iter = f.begin();
Brian Osmand8070392020-09-09 15:50:02 -0400916 const Type* returnType = this->convertType(*(iter++), /*allowVoid=*/true);
John Stilesb9af7232020-08-20 15:57:48 -0400917 if (returnType == nullptr) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400918 return;
ethannicholasb3058bd2016-07-01 08:22:01 -0700919 }
Brian Osman3000d6b2020-07-31 15:57:28 -0400920 auto type_is_allowed = [&](const Type* t) {
921#if defined(SKSL_STANDALONE)
922 return true;
923#else
924 GrSLType unusedSLType;
925 return fKind != Program::kPipelineStage_Kind ||
926 type_to_grsltype(fContext, *t, &unusedSLType);
927#endif
928 };
929 if (returnType->nonnullable() == *fContext.fFragmentProcessor_Type ||
930 !type_is_allowed(returnType)) {
Brian Osman82329002020-07-21 09:39:27 -0400931 fErrors.error(f.fOffset,
932 "functions may not return type '" + returnType->displayName() + "'");
933 return;
934 }
John Stilesb9af7232020-08-20 15:57:48 -0400935 const ASTNode::FunctionData& funcData = f.getFunctionData();
936 this->checkModifiers(f.fOffset, funcData.fModifiers, Modifiers::kHasSideEffects_Flag |
937 Modifiers::kInline_Flag);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400938 std::vector<Variable*> parameters;
John Stilesb9af7232020-08-20 15:57:48 -0400939 for (size_t i = 0; i < funcData.fParameterCount; ++i) {
Ethan Nicholasfc994162019-06-06 10:04:27 -0400940 const ASTNode& param = *(iter++);
941 SkASSERT(param.fKind == ASTNode::Kind::kParameter);
942 ASTNode::ParameterData pd = param.getParameterData();
Ethan Nicholas63d7ee32020-08-17 10:57:12 -0400943 this->checkModifiers(param.fOffset, pd.fModifiers, Modifiers::kIn_Flag |
944 Modifiers::kOut_Flag);
Ethan Nicholasfc994162019-06-06 10:04:27 -0400945 auto paramIter = param.begin();
946 const Type* type = this->convertType(*(paramIter++));
ethannicholasb3058bd2016-07-01 08:22:01 -0700947 if (!type) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -0400948 return;
ethannicholasb3058bd2016-07-01 08:22:01 -0700949 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400950 for (int j = (int) pd.fSizeCount; j >= 1; j--) {
951 int size = (param.begin() + j)->getInt();
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400952 String name = type->name() + "[" + to_string(size) + "]";
John Stiles3ae071e2020-08-05 15:29:29 -0400953 type = fSymbolTable->takeOwnershipOfSymbol(
Ethan Nicholase6592142020-09-08 10:22:09 -0400954 std::make_unique<Type>(std::move(name), Type::TypeKind::kArray, *type, size));
ethannicholasb3058bd2016-07-01 08:22:01 -0700955 }
Brian Osman3000d6b2020-07-31 15:57:28 -0400956 // Only the (builtin) declarations of 'sample' are allowed to have FP parameters
957 if ((type->nonnullable() == *fContext.fFragmentProcessor_Type && !fIsBuiltinCode) ||
958 !type_is_allowed(type)) {
959 fErrors.error(param.fOffset,
960 "parameters of type '" + type->displayName() + "' not allowed");
961 return;
962 }
Ethan Nicholasfc994162019-06-06 10:04:27 -0400963 StringFragment name = pd.fName;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400964 Variable* var = fSymbolTable->takeOwnershipOfSymbol(
965 std::make_unique<Variable>(param.fOffset, fModifiers->handle(pd.fModifiers),
966 name, type, fIsBuiltinCode,
967 Variable::kParameter_Storage));
ethannicholasd598f792016-07-25 10:08:54 -0700968 parameters.push_back(var);
ethannicholasb3058bd2016-07-01 08:22:01 -0700969 }
970
Brian Osman767f4442020-08-13 16:59:48 -0400971 auto paramIsCoords = [&](int idx) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400972 return parameters[idx]->type() == *fContext.fFloat2_Type &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400973 parameters[idx]->modifiers().fFlags == 0;
Brian Osman767f4442020-08-13 16:59:48 -0400974 };
Brian Osman767f4442020-08-13 16:59:48 -0400975
John Stilesb9af7232020-08-20 15:57:48 -0400976 if (funcData.fName == "main") {
Ethan Nicholas0d997662019-04-08 09:46:01 -0400977 switch (fKind) {
978 case Program::kPipelineStage_Kind: {
Brian Osman767f4442020-08-13 16:59:48 -0400979 // half4 main() -or- half4 main(float2)
980 bool valid = (*returnType == *fContext.fHalf4_Type) &&
981 ((parameters.size() == 0) ||
982 (parameters.size() == 1 && paramIsCoords(0)));
983 if (!valid) {
984 fErrors.error(f.fOffset, "pipeline stage 'main' must be declared "
985 "half4 main() or half4 main(float2)");
986 return;
987 }
988 break;
Brian Osman44820a92020-08-26 09:27:39 -0400989 }
Michael Ludwigfc2fdf02020-06-29 17:20:13 -0400990 case Program::kFragmentProcessor_Kind: {
Brian Osman44820a92020-08-26 09:27:39 -0400991 bool valid = (parameters.size() == 0) ||
992 (parameters.size() == 1 && paramIsCoords(0));
Michael Ludwigfc2fdf02020-06-29 17:20:13 -0400993 if (!valid) {
994 fErrors.error(f.fOffset, ".fp 'main' must be declared main() or main(float2)");
995 return;
996 }
997 break;
998 }
Ethan Nicholas746035a2019-04-23 13:31:09 -0400999 case Program::kGeneric_Kind:
Ethan Nicholas0d997662019-04-08 09:46:01 -04001000 break;
Ethan Nicholas0d997662019-04-08 09:46:01 -04001001 default:
1002 if (parameters.size()) {
1003 fErrors.error(f.fOffset, "shader 'main' must have zero parameters");
1004 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001005 }
1006 }
1007
ethannicholasb3058bd2016-07-01 08:22:01 -07001008 // find existing declaration
ethannicholasd598f792016-07-25 10:08:54 -07001009 const FunctionDeclaration* decl = nullptr;
John Stilesb9af7232020-08-20 15:57:48 -04001010 const Symbol* entry = (*fSymbolTable)[funcData.fName];
ethannicholasb3058bd2016-07-01 08:22:01 -07001011 if (entry) {
ethannicholasd598f792016-07-25 10:08:54 -07001012 std::vector<const FunctionDeclaration*> functions;
Ethan Nicholase6592142020-09-08 10:22:09 -04001013 switch (entry->kind()) {
1014 case Symbol::Kind::kUnresolvedFunction:
John Stiles17c5b702020-08-18 10:40:03 -04001015 functions = entry->as<UnresolvedFunction>().fFunctions;
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001017 case Symbol::Kind::kFunctionDeclaration:
John Stiles17c5b702020-08-18 10:40:03 -04001018 functions.push_back(&entry->as<FunctionDeclaration>());
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 break;
1020 default:
John Stilesb9af7232020-08-20 15:57:48 -04001021 fErrors.error(f.fOffset, "symbol '" + funcData.fName + "' was already defined");
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04001022 return;
ethannicholasb3058bd2016-07-01 08:22:01 -07001023 }
John Stilesb9af7232020-08-20 15:57:48 -04001024 for (const FunctionDeclaration* other : functions) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04001025 SkASSERT(other->name() == funcData.fName);
Ethan Nicholased84b732020-10-08 11:45:44 -04001026 if (parameters.size() == other->parameters().size()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 bool match = true;
1028 for (size_t i = 0; i < parameters.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -04001029 if (parameters[i]->type() != other->parameters()[i]->type()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001030 match = false;
1031 break;
1032 }
1033 }
1034 if (match) {
Ethan Nicholased84b732020-10-08 11:45:44 -04001035 if (*returnType != other->returnType()) {
1036 FunctionDeclaration newDecl(f.fOffset,
1037 fModifiers->handle(funcData.fModifiers),
1038 funcData.fName,
1039 parameters,
1040 returnType,
1041 fIsBuiltinCode);
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001042 fErrors.error(f.fOffset, "functions '" + newDecl.description() +
1043 "' and '" + other->description() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001044 "' differ only in return type");
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04001045 return;
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 }
1047 decl = other;
1048 for (size_t i = 0; i < parameters.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -04001049 if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001050 fErrors.error(f.fOffset, "modifiers on parameter " +
1051 to_string((uint64_t) i + 1) +
John Stilesb9af7232020-08-20 15:57:48 -04001052 " differ between declaration and definition");
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04001053 return;
ethannicholasb3058bd2016-07-01 08:22:01 -07001054 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 }
Ethan Nicholased84b732020-10-08 11:45:44 -04001056 if (other->definition() && !other->isBuiltin()) {
John Stilesb9af7232020-08-20 15:57:48 -04001057 fErrors.error(f.fOffset, "duplicate definition of " + other->description());
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 }
1059 break;
1060 }
1061 }
1062 }
1063 }
1064 if (!decl) {
John Stilesb9af7232020-08-20 15:57:48 -04001065 // Conservatively assume all user-defined functions have side effects.
1066 Modifiers declModifiers = funcData.fModifiers;
1067 if (!fIsBuiltinCode) {
1068 declModifiers.fFlags |= Modifiers::kHasSideEffects_Flag;
1069 }
1070
1071 // Create a new declaration.
Ethan Nicholased84b732020-10-08 11:45:44 -04001072 decl = fSymbolTable->add(std::make_unique<FunctionDeclaration>(
1073 f.fOffset,
1074 fModifiers->handle(declModifiers),
1075 funcData.fName,
1076 parameters,
1077 returnType,
1078 fIsBuiltinCode));
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001080 if (iter != f.end()) {
1081 // compile body
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001082 SkASSERT(!fCurrentFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001083 fCurrentFunction = decl;
ethannicholasd598f792016-07-25 10:08:54 -07001084 std::shared_ptr<SymbolTable> old = fSymbolTable;
1085 AutoSymbolTable table(this);
Brian Osman44820a92020-08-26 09:27:39 -04001086 if (funcData.fName == "main" && (fKind == Program::kPipelineStage_Kind ||
1087 fKind == Program::kFragmentProcessor_Kind)) {
Brian Osman767f4442020-08-13 16:59:48 -04001088 if (parameters.size() == 1) {
1089 SkASSERT(paramIsCoords(0));
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001090 Modifiers m = parameters[0]->modifiers();
1091 m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
1092 parameters[0]->setModifiersHandle(fModifiers->handle(m));
Brian Osman767f4442020-08-13 16:59:48 -04001093 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001094 }
Ethan Nicholased84b732020-10-08 11:45:44 -04001095 const std::vector<Variable*>& declParameters = decl->parameters();
ethannicholasd598f792016-07-25 10:08:54 -07001096 for (size_t i = 0; i < parameters.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -04001097 fSymbolTable->addWithoutOwnership(declParameters[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 }
John Stilesb9af7232020-08-20 15:57:48 -04001099 bool needInvocationIDWorkaround = fInvocations != -1 && funcData.fName == "main" &&
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001100 fSettings->fCaps &&
1101 !fSettings->fCaps->gsInvocationsSupport();
Ethan Nicholasfc994162019-06-06 10:04:27 -04001102 std::unique_ptr<Block> body = this->convertBlock(*iter);
ethannicholasd598f792016-07-25 10:08:54 -07001103 fCurrentFunction = nullptr;
1104 if (!body) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04001105 return;
1106 }
1107 if (needInvocationIDWorkaround) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001108 body = this->applyInvocationIDWorkaround(std::move(body));
ethannicholasd598f792016-07-25 10:08:54 -07001109 }
John Stilesb9af7232020-08-20 15:57:48 -04001110 if (Program::kVertex_Kind == fKind && funcData.fName == "main" && fRTAdjust) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001111 body->children().push_back(this->getNormalizeSkPositionCode());
Robert Phillipsfe8da172018-01-24 14:52:02 +00001112 }
John Stilesb8e010c2020-08-11 18:05:39 -04001113 auto result = std::make_unique<FunctionDefinition>(f.fOffset, *decl, std::move(body),
1114 std::move(fReferencedIntrinsics));
Ethan Nicholased84b732020-10-08 11:45:44 -04001115 decl->setDefinition(result.get());
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001116 result->fSource = &f;
1117 fProgramElements->push_back(std::move(result));
ethannicholasb3058bd2016-07-01 08:22:01 -07001118 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001119}
1120
Ethan Nicholasfc994162019-06-06 10:04:27 -04001121std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTNode& intf) {
Brian Osman16f376f2020-09-02 12:30:59 -04001122 if (fKind != Program::kFragment_Kind &&
1123 fKind != Program::kVertex_Kind &&
1124 fKind != Program::kGeometry_Kind) {
1125 fErrors.error(intf.fOffset, "interface block is not allowed here");
1126 return nullptr;
1127 }
1128
Ethan Nicholasfc994162019-06-06 10:04:27 -04001129 SkASSERT(intf.fKind == ASTNode::Kind::kInterfaceBlock);
1130 ASTNode::InterfaceBlockData id = intf.getInterfaceBlockData();
ethannicholasb3058bd2016-07-01 08:22:01 -07001131 std::shared_ptr<SymbolTable> old = fSymbolTable;
Ethan Nicholas68dd2c12018-03-01 15:05:17 -05001132 this->pushSymbolTable();
1133 std::shared_ptr<SymbolTable> symbols = fSymbolTable;
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 std::vector<Type::Field> fields;
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04001135 bool haveRuntimeArray = false;
Robert Phillipsfe8da172018-01-24 14:52:02 +00001136 bool foundRTAdjust = false;
Ethan Nicholasfc994162019-06-06 10:04:27 -04001137 auto iter = intf.begin();
1138 for (size_t i = 0; i < id.fDeclarationCount; ++i) {
Brian Osmanc0213602020-10-06 14:43:32 -04001139 std::vector<std::unique_ptr<Statement>> decls =
1140 this->convertVarDeclarations(*(iter++), Variable::kInterfaceBlock_Storage);
1141 if (decls.empty()) {
ethannicholas7effa7a2016-10-14 09:56:33 -07001142 return nullptr;
1143 }
Brian Osmanc0213602020-10-06 14:43:32 -04001144 for (const auto& decl : decls) {
1145 const VarDeclaration& vd = decl->as<VarDeclaration>();
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04001146 if (haveRuntimeArray) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001147 fErrors.error(decl->fOffset,
Brian Osmanc0213602020-10-06 14:43:32 -04001148 "only the last entry in an interface block may be a runtime-sized "
1149 "array");
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04001150 }
Robert Phillipsfe8da172018-01-24 14:52:02 +00001151 if (vd.fVar == fRTAdjust) {
1152 foundRTAdjust = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001153 SkASSERT(vd.fVar->type() == *fContext.fFloat4_Type);
Robert Phillipsfe8da172018-01-24 14:52:02 +00001154 fRTAdjustFieldIndex = fields.size();
1155 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001156 fields.push_back(Type::Field(vd.fVar->modifiers(), vd.fVar->name(),
Brian Osmanc0213602020-10-06 14:43:32 -04001157 &vd.fVar->type()));
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001158 if (vd.fValue) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001159 fErrors.error(decl->fOffset,
Brian Osmanc0213602020-10-06 14:43:32 -04001160 "initializers are not permitted on interface block fields");
ethannicholasb3058bd2016-07-01 08:22:01 -07001161 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001162 if (vd.fVar->type().typeKind() == Type::TypeKind::kArray &&
Brian Osmane8c26082020-10-01 17:22:45 -04001163 vd.fVar->type().columns() == Type::kUnsizedArray) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04001164 haveRuntimeArray = true;
1165 }
Ethan Nicholas11d53972016-11-28 11:23:23 -05001166 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001167 }
Ethan Nicholas68dd2c12018-03-01 15:05:17 -05001168 this->popSymbolTable();
John Stiles3ae071e2020-08-05 15:29:29 -04001169 const Type* type =
1170 old->takeOwnershipOfSymbol(std::make_unique<Type>(intf.fOffset, id.fTypeName, fields));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001171 std::vector<std::unique_ptr<Expression>> sizes;
Ethan Nicholasfc994162019-06-06 10:04:27 -04001172 for (size_t i = 0; i < id.fSizeCount; ++i) {
1173 const ASTNode& size = *(iter++);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001174 if (size) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001175 std::unique_ptr<Expression> converted = this->convertExpression(size);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001176 if (!converted) {
1177 return nullptr;
1178 }
Ethan Nicholase2c49992020-10-05 11:49:11 -04001179 String name = type->name();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001180 int64_t count;
Ethan Nicholase6592142020-09-08 10:22:09 -04001181 if (converted->kind() == Expression::Kind::kIntLiteral) {
Ethan Nicholase96cdd12020-09-28 16:27:18 -04001182 count = converted->as<IntLiteral>().value();
Ethan Nicholas50afc172017-02-16 14:49:57 -05001183 if (count <= 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001184 fErrors.error(converted->fOffset, "array size must be positive");
Ethan Nicholas66d80062019-09-09 14:50:51 -04001185 return nullptr;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001186 }
1187 name += "[" + to_string(count) + "]";
1188 } else {
Ethan Nicholas66d80062019-09-09 14:50:51 -04001189 fErrors.error(intf.fOffset, "array size must be specified");
1190 return nullptr;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001191 }
John Stiles3ae071e2020-08-05 15:29:29 -04001192 type = symbols->takeOwnershipOfSymbol(
Ethan Nicholase6592142020-09-08 10:22:09 -04001193 std::make_unique<Type>(name, Type::TypeKind::kArray, *type, (int)count));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001194 sizes.push_back(std::move(converted));
1195 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04001196 String name = String(type->name()) + "[]";
Brian Osmane8c26082020-10-01 17:22:45 -04001197 type = symbols->takeOwnershipOfSymbol(std::make_unique<Type>(
1198 name, Type::TypeKind::kArray, *type, Type::kUnsizedArray));
1199 sizes.push_back(nullptr);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001200 }
1201 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001202 Variable* var = old->takeOwnershipOfSymbol(
John Stiles3ae071e2020-08-05 15:29:29 -04001203 std::make_unique<Variable>(intf.fOffset,
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001204 fModifiers->handle(id.fModifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001205 id.fInstanceName.fLength ? id.fInstanceName : id.fTypeName,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001206 type,
Brian Osman3887a012020-09-30 13:22:27 -04001207 fIsBuiltinCode,
John Stiles3ae071e2020-08-05 15:29:29 -04001208 Variable::kGlobal_Storage));
Robert Phillipsfe8da172018-01-24 14:52:02 +00001209 if (foundRTAdjust) {
1210 fRTAdjustInterfaceBlock = var;
1211 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001212 if (id.fInstanceName.fLength) {
John Stilesb8cc6652020-10-08 09:12:07 -04001213 old->addWithoutOwnership(var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 } else {
1215 for (size_t i = 0; i < fields.size(); i++) {
John Stilesb8cc6652020-10-08 09:12:07 -04001216 old->add(std::make_unique<Field>(intf.fOffset, var, (int)i));
ethannicholasb3058bd2016-07-01 08:22:01 -07001217 }
1218 }
John Stilesfbd050b2020-08-03 13:21:46 -04001219 return std::make_unique<InterfaceBlock>(intf.fOffset,
1220 var,
1221 id.fTypeName,
1222 id.fInstanceName,
1223 std::move(sizes),
1224 symbols);
ethannicholasb3058bd2016-07-01 08:22:01 -07001225}
1226
Brian Osman3e3db6c2020-08-14 09:42:12 -04001227bool IRGenerator::getConstantInt(const Expression& value, int64_t* out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001228 switch (value.kind()) {
1229 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -04001230 *out = value.as<IntLiteral>().value();
Brian Osman3e3db6c2020-08-14 09:42:12 -04001231 return true;
Ethan Nicholase6592142020-09-08 10:22:09 -04001232 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001233 const Variable& var = *value.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001234 return (var.modifiers().fFlags & Modifiers::kConst_Flag) &&
1235 var.initialValue() && this->getConstantInt(*var.initialValue(), out);
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001236 }
1237 default:
Brian Osman3e3db6c2020-08-14 09:42:12 -04001238 return false;
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001239 }
1240}
1241
Ethan Nicholasfc994162019-06-06 10:04:27 -04001242void IRGenerator::convertEnum(const ASTNode& e) {
Brian Osman16f376f2020-09-02 12:30:59 -04001243 if (fKind == Program::kPipelineStage_Kind) {
1244 fErrors.error(e.fOffset, "enum is not allowed here");
1245 return;
1246 }
1247
Ethan Nicholasfc994162019-06-06 10:04:27 -04001248 SkASSERT(e.fKind == ASTNode::Kind::kEnum);
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001249 int64_t currentValue = 0;
1250 Layout layout;
Ethan Nicholasfc994162019-06-06 10:04:27 -04001251 ASTNode enumType(e.fNodes, e.fOffset, ASTNode::Kind::kType,
1252 ASTNode::TypeData(e.getString(), false, false));
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001253 const Type* type = this->convertType(enumType);
1254 Modifiers modifiers(layout, Modifiers::kConst_Flag);
Brian Osman1313d1a2020-09-08 10:34:30 -04001255 std::shared_ptr<SymbolTable> oldTable = fSymbolTable;
1256 fSymbolTable = std::make_shared<SymbolTable>(fSymbolTable);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001257 for (auto iter = e.begin(); iter != e.end(); ++iter) {
1258 const ASTNode& child = *iter;
1259 SkASSERT(child.fKind == ASTNode::Kind::kEnumCase);
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001260 std::unique_ptr<Expression> value;
Ethan Nicholasfc994162019-06-06 10:04:27 -04001261 if (child.begin() != child.end()) {
1262 value = this->convertExpression(*child.begin());
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001263 if (!value) {
Brian Osman1313d1a2020-09-08 10:34:30 -04001264 fSymbolTable = oldTable;
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001265 return;
1266 }
Brian Osman3e3db6c2020-08-14 09:42:12 -04001267 if (!this->getConstantInt(*value, &currentValue)) {
1268 fErrors.error(value->fOffset, "enum value must be a constant integer");
Brian Osman1313d1a2020-09-08 10:34:30 -04001269 fSymbolTable = oldTable;
Brian Osman3e3db6c2020-08-14 09:42:12 -04001270 return;
1271 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001272 }
1273 value = std::unique_ptr<Expression>(new IntLiteral(fContext, e.fOffset, currentValue));
1274 ++currentValue;
John Stilesb8cc6652020-10-08 09:12:07 -04001275 fSymbolTable->add(std::make_unique<Variable>(e.fOffset, fModifiers->handle(modifiers),
1276 child.getString(), type, fIsBuiltinCode,
1277 Variable::kGlobal_Storage, value.get()));
Brian Osman3e3db6c2020-08-14 09:42:12 -04001278 fSymbolTable->takeOwnershipOfIRNode(std::move(value));
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001279 }
Brian Osman1313d1a2020-09-08 10:34:30 -04001280 // Now we orphanize the Enum's symbol table, so that future lookups in it are strict
1281 fSymbolTable->fParent = nullptr;
Brian Osman3e3db6c2020-08-14 09:42:12 -04001282 fProgramElements->push_back(std::unique_ptr<ProgramElement>(
1283 new Enum(e.fOffset, e.getString(), fSymbolTable, fIsBuiltinCode)));
Brian Osman1313d1a2020-09-08 10:34:30 -04001284 fSymbolTable = oldTable;
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001285}
1286
Brian Osmand8070392020-09-09 15:50:02 -04001287const Type* IRGenerator::convertType(const ASTNode& type, bool allowVoid) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001288 ASTNode::TypeData td = type.getTypeData();
1289 const Symbol* result = (*fSymbolTable)[td.fName];
Brian Osmand8070392020-09-09 15:50:02 -04001290 if (result && result->is<Type>()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001291 if (td.fIsNullable) {
John Stiles17c5b702020-08-18 10:40:03 -04001292 if (result->as<Type>() == *fContext.fFragmentProcessor_Type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001293 if (type.begin() != type.end()) {
1294 fErrors.error(type.fOffset, "type '" + td.fName + "' may not be used in "
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001295 "an array");
1296 }
John Stiles3ae071e2020-08-05 15:29:29 -04001297 result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>(
Ethan Nicholase2c49992020-10-05 11:49:11 -04001298 String(result->name()) + "?", Type::TypeKind::kNullable,
1299 result->as<Type>()));
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001300 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001301 fErrors.error(type.fOffset, "type '" + td.fName + "' may not be nullable");
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001302 }
1303 }
Brian Osmand8070392020-09-09 15:50:02 -04001304 if (result->as<Type>() == *fContext.fVoid_Type) {
1305 if (!allowVoid) {
1306 fErrors.error(type.fOffset, "type '" + td.fName + "' not allowed in this context");
1307 return nullptr;
1308 }
1309 if (type.begin() != type.end()) {
1310 fErrors.error(type.fOffset, "type '" + td.fName + "' may not be used in an array");
1311 return nullptr;
1312 }
1313 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001314 for (const auto& size : type) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04001315 String name(result->name());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001316 name += "[";
Ethan Nicholasfc994162019-06-06 10:04:27 -04001317 if (size) {
1318 name += to_string(size.getInt());
Ethan Nicholas50afc172017-02-16 14:49:57 -05001319 }
1320 name += "]";
Brian Osmane8c26082020-10-01 17:22:45 -04001321 result = fSymbolTable->takeOwnershipOfSymbol(
1322 std::make_unique<Type>(name, Type::TypeKind::kArray, result->as<Type>(),
1323 size ? size.getInt() : Type::kUnsizedArray));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001324 }
John Stiles17c5b702020-08-18 10:40:03 -04001325 return &result->as<Type>();
ethannicholasb3058bd2016-07-01 08:22:01 -07001326 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001327 fErrors.error(type.fOffset, "unknown type '" + td.fName + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001328 return nullptr;
1329}
1330
Ethan Nicholasfc994162019-06-06 10:04:27 -04001331std::unique_ptr<Expression> IRGenerator::convertExpression(const ASTNode& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 switch (expr.fKind) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001333 case ASTNode::Kind::kBinary:
1334 return this->convertBinaryExpression(expr);
1335 case ASTNode::Kind::kBool:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001336 return std::unique_ptr<Expression>(new BoolLiteral(fContext, expr.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04001337 expr.getBool()));
1338 case ASTNode::Kind::kCall:
1339 return this->convertCallExpression(expr);
1340 case ASTNode::Kind::kField:
1341 return this->convertFieldExpression(expr);
1342 case ASTNode::Kind::kFloat:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001343 return std::unique_ptr<Expression>(new FloatLiteral(fContext, expr.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04001344 expr.getFloat()));
1345 case ASTNode::Kind::kIdentifier:
1346 return this->convertIdentifier(expr);
1347 case ASTNode::Kind::kIndex:
1348 return this->convertIndexExpression(expr);
1349 case ASTNode::Kind::kInt:
1350 return std::unique_ptr<Expression>(new IntLiteral(fContext, expr.fOffset,
1351 expr.getInt()));
1352 case ASTNode::Kind::kNull:
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001353 return std::unique_ptr<Expression>(new NullLiteral(fContext, expr.fOffset));
Ethan Nicholasfc994162019-06-06 10:04:27 -04001354 case ASTNode::Kind::kPostfix:
1355 return this->convertPostfixExpression(expr);
1356 case ASTNode::Kind::kPrefix:
1357 return this->convertPrefixExpression(expr);
Brian Osman6518d772020-09-10 16:50:06 -04001358 case ASTNode::Kind::kScope:
1359 return this->convertScopeExpression(expr);
Ethan Nicholasfc994162019-06-06 10:04:27 -04001360 case ASTNode::Kind::kTernary:
1361 return this->convertTernaryExpression(expr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001363#ifdef SK_DEBUG
Ethan Nicholasfc994162019-06-06 10:04:27 -04001364 ABORT("unsupported expression: %s\n", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001365#endif
1366 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001367 }
1368}
1369
Ethan Nicholasfc994162019-06-06 10:04:27 -04001370std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identifier) {
1371 SkASSERT(identifier.fKind == ASTNode::Kind::kIdentifier);
1372 const Symbol* result = (*fSymbolTable)[identifier.getString()];
ethannicholasb3058bd2016-07-01 08:22:01 -07001373 if (!result) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001374 fErrors.error(identifier.fOffset, "unknown identifier '" + identifier.getString() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001375 return nullptr;
1376 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001377 switch (result->kind()) {
1378 case Symbol::Kind::kFunctionDeclaration: {
ethannicholasd598f792016-07-25 10:08:54 -07001379 std::vector<const FunctionDeclaration*> f = {
John Stiles17c5b702020-08-18 10:40:03 -04001380 &result->as<FunctionDeclaration>()
ethannicholasb3058bd2016-07-01 08:22:01 -07001381 };
John Stilesfbd050b2020-08-03 13:21:46 -04001382 return std::make_unique<FunctionReference>(fContext, identifier.fOffset, f);
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001384 case Symbol::Kind::kUnresolvedFunction: {
John Stiles17c5b702020-08-18 10:40:03 -04001385 const UnresolvedFunction* f = &result->as<UnresolvedFunction>();
John Stilesfbd050b2020-08-03 13:21:46 -04001386 return std::make_unique<FunctionReference>(fContext, identifier.fOffset, f->fFunctions);
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001388 case Symbol::Kind::kVariable: {
John Stiles17c5b702020-08-18 10:40:03 -04001389 const Variable* var = &result->as<Variable>();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001390 const Modifiers& modifiers = var->modifiers();
1391 switch (modifiers.fLayout.fBuiltin) {
Ethan Nicholascd700e92018-08-24 16:43:57 -04001392 case SK_WIDTH_BUILTIN:
1393 fInputs.fRTWidth = true;
1394 break;
1395 case SK_HEIGHT_BUILTIN:
Greg Daniele6ab9982018-08-22 13:56:32 +00001396 fInputs.fRTHeight = true;
Ethan Nicholascd700e92018-08-24 16:43:57 -04001397 break;
1398#ifndef SKSL_STANDALONE
1399 case SK_FRAGCOORD_BUILTIN:
Brian Osman9f313b62019-10-02 12:03:11 -04001400 fInputs.fFlipY = true;
1401 if (fSettings->fFlipY &&
1402 (!fSettings->fCaps ||
1403 !fSettings->fCaps->fragCoordConventionsExtensionString())) {
1404 fInputs.fRTHeight = true;
Ethan Nicholascd700e92018-08-24 16:43:57 -04001405 }
Greg Daniele6ab9982018-08-22 13:56:32 +00001406#endif
Ethan Nicholascd700e92018-08-24 16:43:57 -04001407 }
Ethan Nicholas33c59ed2019-08-13 10:21:38 -04001408 if (fKind == Program::kFragmentProcessor_Kind &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001409 (modifiers.fFlags & Modifiers::kIn_Flag) &&
1410 !(modifiers.fFlags & Modifiers::kUniform_Flag) &&
1411 !modifiers.fLayout.fKey &&
1412 modifiers.fLayout.fBuiltin == -1 &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001413 var->type().nonnullable() != *fContext.fFragmentProcessor_Type &&
1414 var->type().typeKind() != Type::TypeKind::kSampler) {
Ethan Nicholas33c59ed2019-08-13 10:21:38 -04001415 bool valid = false;
1416 for (const auto& decl : fFile->root()) {
1417 if (decl.fKind == ASTNode::Kind::kSection) {
1418 ASTNode::SectionData section = decl.getSectionData();
1419 if (section.fName == "setData") {
1420 valid = true;
1421 break;
1422 }
1423 }
1424 }
1425 if (!valid) {
1426 fErrors.error(identifier.fOffset, "'in' variable must be either 'uniform' or "
1427 "'layout(key)', or there must be a custom "
1428 "@setData function");
1429 }
1430 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001431 // default to kRead_RefKind; this will be corrected later if the variable is written to
John Stilesfbd050b2020-08-03 13:21:46 -04001432 return std::make_unique<VariableReference>(identifier.fOffset,
Brian Osman79457ef2020-09-24 15:01:27 -04001433 var,
John Stilesfbd050b2020-08-03 13:21:46 -04001434 VariableReference::kRead_RefKind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001435 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001436 case Symbol::Kind::kField: {
John Stiles17c5b702020-08-18 10:40:03 -04001437 const Field* field = &result->as<Field>();
Brian Osman6a204db2020-10-08 09:29:02 -04001438 auto base = std::make_unique<VariableReference>(identifier.fOffset, &field->owner(),
Ethan Nicholas86a43402017-01-19 13:32:00 -05001439 VariableReference::kRead_RefKind);
Brian Osman6a204db2020-10-08 09:29:02 -04001440 return std::make_unique<FieldAccess>(std::move(base),
1441 field->fieldIndex(),
1442 FieldAccess::kAnonymousInterfaceBlock_OwnerKind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001443 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001444 case Symbol::Kind::kType: {
John Stiles17c5b702020-08-18 10:40:03 -04001445 const Type* t = &result->as<Type>();
Ethan Nicholase6592142020-09-08 10:22:09 -04001446 return std::make_unique<TypeReference>(fContext, identifier.fOffset, t);
ethannicholasb3058bd2016-07-01 08:22:01 -07001447 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001448 case Symbol::Kind::kExternal: {
John Stiles17c5b702020-08-18 10:40:03 -04001449 const ExternalValue* r = &result->as<ExternalValue>();
John Stilesfbd050b2020-08-03 13:21:46 -04001450 return std::make_unique<ExternalValueReference>(identifier.fOffset, r);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001451 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 default:
Ethan Nicholase6592142020-09-08 10:22:09 -04001453 ABORT("unsupported symbol type %d\n", (int) result->kind());
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 }
Ethan Nicholasc0709392017-06-27 11:20:22 -04001455}
1456
Ethan Nicholasfc994162019-06-06 10:04:27 -04001457std::unique_ptr<Section> IRGenerator::convertSection(const ASTNode& s) {
Brian Osman16f376f2020-09-02 12:30:59 -04001458 if (fKind != Program::kFragmentProcessor_Kind) {
1459 fErrors.error(s.fOffset, "syntax error");
1460 return nullptr;
1461 }
1462
Ethan Nicholasfc994162019-06-06 10:04:27 -04001463 ASTNode::SectionData section = s.getSectionData();
John Stilesfbd050b2020-08-03 13:21:46 -04001464 return std::make_unique<Section>(s.fOffset, section.fName, section.fArgument,
1465 section.fText);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001466}
1467
Ethan Nicholas11d53972016-11-28 11:23:23 -05001468std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr,
ethannicholasd598f792016-07-25 10:08:54 -07001469 const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001470 if (!expr) {
1471 return nullptr;
1472 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001473 if (expr->type() == type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001474 return expr;
1475 }
1476 this->checkValid(*expr);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001477 if (expr->type() == *fContext.fInvalid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 return nullptr;
1479 }
Brian Osman0acb5b52020-09-02 13:45:47 -04001480 if (!expr->coercionCost(type).isPossible(fSettings->fAllowNarrowingConversions)) {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001481 fErrors.error(expr->fOffset, "expected '" + type.displayName() + "', but found '" +
Ethan Nicholas30d30222020-09-11 12:27:26 -04001482 expr->type().displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001483 return nullptr;
1484 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001485 if (type.typeKind() == Type::TypeKind::kScalar) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 std::vector<std::unique_ptr<Expression>> args;
1487 args.push_back(std::move(expr));
Ethan Nicholase1f55022019-02-05 17:17:40 -05001488 std::unique_ptr<Expression> ctor;
1489 if (type == *fContext.fFloatLiteral_Type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001490 ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier,
1491 "float"));
Ethan Nicholase1f55022019-02-05 17:17:40 -05001492 } else if (type == *fContext.fIntLiteral_Type) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001493 ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier,
1494 "int"));
Ethan Nicholase1f55022019-02-05 17:17:40 -05001495 } else {
Ethan Nicholasfc994162019-06-06 10:04:27 -04001496 ctor = this->convertIdentifier(ASTNode(&fFile->fNodes, -1, ASTNode::Kind::kIdentifier,
Ethan Nicholase2c49992020-10-05 11:49:11 -04001497 type.name()));
Ethan Nicholase1f55022019-02-05 17:17:40 -05001498 }
1499 if (!ctor) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04001500 printf("error, null identifier: %s\n", String(type.name()).c_str());
Ethan Nicholase1f55022019-02-05 17:17:40 -05001501 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001502 SkASSERT(ctor);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001503 return this->call(-1, std::move(ctor), std::move(args));
ethannicholasb3058bd2016-07-01 08:22:01 -07001504 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001505 if (expr->kind() == Expression::Kind::kNullLiteral) {
1506 SkASSERT(type.typeKind() == Type::TypeKind::kNullable);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001507 return std::unique_ptr<Expression>(new NullLiteral(expr->fOffset, &type));
Ethan Nicholasee1c8a72019-02-22 10:50:47 -05001508 }
ethannicholas5961bc92016-10-12 06:39:56 -07001509 std::vector<std::unique_ptr<Expression>> args;
1510 args.push_back(std::move(expr));
Ethan Nicholas30d30222020-09-11 12:27:26 -04001511 return std::unique_ptr<Expression>(new Constructor(-1, &type, std::move(args)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001512}
1513
ethannicholasf789b382016-08-03 12:43:36 -07001514static bool is_matrix_multiply(const Type& left, const Type& right) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001515 if (left.typeKind() == Type::TypeKind::kMatrix) {
1516 return right.typeKind() == Type::TypeKind::kMatrix ||
1517 right.typeKind() == Type::TypeKind::kVector;
ethannicholasf789b382016-08-03 12:43:36 -07001518 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001519 return left.typeKind() == Type::TypeKind::kVector &&
1520 right.typeKind() == Type::TypeKind::kMatrix;
ethannicholasf789b382016-08-03 12:43:36 -07001521}
ethannicholasea4567c2016-10-17 11:24:37 -07001522
ethannicholasb3058bd2016-07-01 08:22:01 -07001523/**
1524 * Determines the operand and result types of a binary expression. Returns true if the expression is
1525 * legal, false otherwise. If false, the values of the out parameters are undefined.
1526 */
Ethan Nicholas11d53972016-11-28 11:23:23 -05001527static bool determine_binary_type(const Context& context,
Brian Osman0acb5b52020-09-02 13:45:47 -04001528 bool allowNarrowing,
Ethan Nicholas11d53972016-11-28 11:23:23 -05001529 Token::Kind op,
1530 const Type& left,
1531 const Type& right,
ethannicholasd598f792016-07-25 10:08:54 -07001532 const Type** outLeftType,
1533 const Type** outRightType,
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001534 const Type** outResultType) {
1535 bool isLogical = false;
Brian Osmanbf2163f2020-09-16 16:21:40 -04001536 bool isBitwise = false;
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001537 bool validMatrixOrVectorOp = false;
1538 bool isAssignment = Compiler::IsAssignment(op);
1539
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001541 case Token::Kind::TK_EQ:
ethannicholasea4567c2016-10-17 11:24:37 -07001542 *outLeftType = &left;
1543 *outRightType = &left;
1544 *outResultType = &left;
Brian Osman0acb5b52020-09-02 13:45:47 -04001545 return right.canCoerceTo(left, allowNarrowing);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001546 case Token::Kind::TK_EQEQ: // fall through
Brian Osman0acb5b52020-09-02 13:45:47 -04001547 case Token::Kind::TK_NEQ: {
1548 CoercionCost rightToLeft = right.coercionCost(left),
1549 leftToRight = left.coercionCost(right);
1550 if (rightToLeft < leftToRight) {
1551 if (rightToLeft.isPossible(allowNarrowing)) {
1552 *outLeftType = &left;
1553 *outRightType = &left;
1554 *outResultType = context.fBool_Type.get();
1555 return true;
1556 }
1557 } else {
1558 if (leftToRight.isPossible(allowNarrowing)) {
1559 *outLeftType = &right;
1560 *outRightType = &right;
1561 *outResultType = context.fBool_Type.get();
1562 return true;
1563 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001564 }
Ethan Nicholas23463002018-03-28 15:16:15 -04001565 return false;
Brian Osman0acb5b52020-09-02 13:45:47 -04001566 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001567 case Token::Kind::TK_LT: // fall through
1568 case Token::Kind::TK_GT: // fall through
1569 case Token::Kind::TK_LTEQ: // fall through
1570 case Token::Kind::TK_GTEQ:
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 isLogical = true;
1572 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001573 case Token::Kind::TK_LOGICALOR: // fall through
1574 case Token::Kind::TK_LOGICALAND: // fall through
1575 case Token::Kind::TK_LOGICALXOR: // fall through
1576 case Token::Kind::TK_LOGICALOREQ: // fall through
1577 case Token::Kind::TK_LOGICALANDEQ: // fall through
1578 case Token::Kind::TK_LOGICALXOREQ:
ethannicholasd598f792016-07-25 10:08:54 -07001579 *outLeftType = context.fBool_Type.get();
1580 *outRightType = context.fBool_Type.get();
1581 *outResultType = context.fBool_Type.get();
Brian Osman0acb5b52020-09-02 13:45:47 -04001582 return left.canCoerceTo(*context.fBool_Type, allowNarrowing) &&
1583 right.canCoerceTo(*context.fBool_Type, allowNarrowing);
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001584 case Token::Kind::TK_STAREQ: // fall through
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001585 case Token::Kind::TK_STAR:
ethannicholasf789b382016-08-03 12:43:36 -07001586 if (is_matrix_multiply(left, right)) {
1587 // determine final component type
Brian Osman3ed22a92020-09-17 15:10:25 -04001588 if (determine_binary_type(context, allowNarrowing, op,
Brian Osman0acb5b52020-09-02 13:45:47 -04001589 left.componentType(), right.componentType(),
1590 outLeftType, outRightType, outResultType)) {
Ethan Nicholas11d53972016-11-28 11:23:23 -05001591 *outLeftType = &(*outResultType)->toCompound(context, left.columns(),
Brian Salomon23356442018-11-30 15:33:19 -05001592 left.rows());
Ethan Nicholas11d53972016-11-28 11:23:23 -05001593 *outRightType = &(*outResultType)->toCompound(context, right.columns(),
Brian Salomon23356442018-11-30 15:33:19 -05001594 right.rows());
ethannicholasf789b382016-08-03 12:43:36 -07001595 int leftColumns = left.columns();
1596 int leftRows = left.rows();
1597 int rightColumns;
1598 int rightRows;
Ethan Nicholase6592142020-09-08 10:22:09 -04001599 if (right.typeKind() == Type::TypeKind::kVector) {
ethannicholasf789b382016-08-03 12:43:36 -07001600 // matrix * vector treats the vector as a column vector, so we need to
1601 // transpose it
1602 rightColumns = right.rows();
1603 rightRows = right.columns();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001604 SkASSERT(rightColumns == 1);
ethannicholasf789b382016-08-03 12:43:36 -07001605 } else {
1606 rightColumns = right.columns();
1607 rightRows = right.rows();
1608 }
1609 if (rightColumns > 1) {
1610 *outResultType = &(*outResultType)->toCompound(context, rightColumns,
1611 leftRows);
1612 } else {
1613 // result was a column vector, transpose it back to a row
1614 *outResultType = &(*outResultType)->toCompound(context, leftRows,
1615 rightColumns);
1616 }
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001617 if (isAssignment && ((*outResultType)->columns() != leftColumns ||
1618 (*outResultType)->rows() != leftRows)) {
1619 return false;
1620 }
ethannicholasf789b382016-08-03 12:43:36 -07001621 return leftColumns == rightRows;
1622 } else {
1623 return false;
1624 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001625 }
ethannicholasea4567c2016-10-17 11:24:37 -07001626 validMatrixOrVectorOp = true;
1627 break;
Brian Osmanbf2163f2020-09-16 16:21:40 -04001628 case Token::Kind::TK_SHLEQ:
1629 case Token::Kind::TK_SHREQ:
1630 case Token::Kind::TK_BITWISEANDEQ:
1631 case Token::Kind::TK_BITWISEOREQ:
1632 case Token::Kind::TK_BITWISEXOREQ:
1633 case Token::Kind::TK_SHL:
1634 case Token::Kind::TK_SHR:
1635 case Token::Kind::TK_BITWISEAND:
1636 case Token::Kind::TK_BITWISEOR:
1637 case Token::Kind::TK_BITWISEXOR:
1638 isBitwise = true;
1639 validMatrixOrVectorOp = true;
1640 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001641 case Token::Kind::TK_PLUSEQ:
1642 case Token::Kind::TK_MINUSEQ:
1643 case Token::Kind::TK_SLASHEQ:
1644 case Token::Kind::TK_PERCENTEQ:
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001645 case Token::Kind::TK_PLUS:
1646 case Token::Kind::TK_MINUS:
1647 case Token::Kind::TK_SLASH:
1648 case Token::Kind::TK_PERCENT:
ethannicholasea4567c2016-10-17 11:24:37 -07001649 validMatrixOrVectorOp = true;
1650 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001651 case Token::Kind::TK_COMMA:
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001652 *outLeftType = &left;
1653 *outRightType = &right;
1654 *outResultType = &right;
1655 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001656 default:
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001657 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 }
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001659
1660 bool leftIsVectorOrMatrix = left.typeKind() == Type::TypeKind::kVector ||
1661 left.typeKind() == Type::TypeKind::kMatrix,
1662 rightIsVectorOrMatrix = right.typeKind() == Type::TypeKind::kVector ||
1663 right.typeKind() == Type::TypeKind::kMatrix;
1664
1665 if (leftIsVectorOrMatrix && validMatrixOrVectorOp &&
1666 right.typeKind() == Type::TypeKind::kScalar) {
Brian Osman0acb5b52020-09-02 13:45:47 -04001667 if (determine_binary_type(context, allowNarrowing, op, left.componentType(), right,
1668 outLeftType, outRightType, outResultType)) {
ethannicholasd598f792016-07-25 10:08:54 -07001669 *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows());
ethannicholasb3058bd2016-07-01 08:22:01 -07001670 if (!isLogical) {
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001671 *outResultType =
1672 &(*outResultType)->toCompound(context, left.columns(), left.rows());
ethannicholasb3058bd2016-07-01 08:22:01 -07001673 }
1674 return true;
1675 }
1676 return false;
1677 }
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001678
1679 if (!isAssignment && rightIsVectorOrMatrix && validMatrixOrVectorOp &&
1680 left.typeKind() == Type::TypeKind::kScalar) {
Brian Osman0acb5b52020-09-02 13:45:47 -04001681 if (determine_binary_type(context, allowNarrowing, op, left, right.componentType(),
1682 outLeftType, outRightType, outResultType)) {
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001683 *outRightType = &(*outRightType)->toCompound(context, right.columns(), right.rows());
1684 if (!isLogical) {
1685 *outResultType =
1686 &(*outResultType)->toCompound(context, right.columns(), right.rows());
1687 }
1688 return true;
1689 }
1690 return false;
1691 }
1692
Brian Osman0acb5b52020-09-02 13:45:47 -04001693 CoercionCost rightToLeftCost = right.coercionCost(left);
1694 CoercionCost leftToRightCost = isAssignment ? CoercionCost::Impossible()
1695 : left.coercionCost(right);
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001696
1697 if ((left.typeKind() == Type::TypeKind::kScalar &&
1698 right.typeKind() == Type::TypeKind::kScalar) ||
1699 (leftIsVectorOrMatrix && validMatrixOrVectorOp)) {
Brian Osmanbf2163f2020-09-16 16:21:40 -04001700 if (isBitwise) {
1701 const Type& leftNumberType(leftIsVectorOrMatrix ? left.componentType() : left);
1702 const Type& rightNumberType(rightIsVectorOrMatrix ? right.componentType() : right);
1703 if (!leftNumberType.isInteger() || !rightNumberType.isInteger()) {
1704 return false;
1705 }
1706 }
Brian Osman0acb5b52020-09-02 13:45:47 -04001707 if (rightToLeftCost.isPossible(allowNarrowing) && rightToLeftCost < leftToRightCost) {
1708 // Right-to-Left conversion is possible and cheaper
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001709 *outLeftType = &left;
1710 *outRightType = &left;
1711 *outResultType = &left;
Brian Osman0acb5b52020-09-02 13:45:47 -04001712 } else if (leftToRightCost.isPossible(allowNarrowing)) {
Brian Osmanc4cb3a62020-09-03 16:52:28 -04001713 // Left-to-Right conversion is possible (and at least as cheap as Right-to-Left)
1714 *outLeftType = &right;
1715 *outRightType = &right;
1716 *outResultType = &right;
1717 } else {
1718 return false;
1719 }
1720 if (isLogical) {
1721 *outResultType = context.fBool_Type.get();
1722 }
1723 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001724 }
1725 return false;
1726}
1727
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001728static std::unique_ptr<Expression> short_circuit_boolean(const Context& context,
1729 const Expression& left,
1730 Token::Kind op,
1731 const Expression& right) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001732 SkASSERT(left.kind() == Expression::Kind::kBoolLiteral);
Ethan Nicholas59d660c2020-09-28 09:18:15 -04001733 bool leftVal = left.as<BoolLiteral>().value();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001734 if (op == Token::Kind::TK_LOGICALAND) {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001735 // (true && expr) -> (expr) and (false && expr) -> (false)
1736 return leftVal ? right.clone()
1737 : std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, false));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001738 } else if (op == Token::Kind::TK_LOGICALOR) {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001739 // (true || expr) -> (true) and (false || expr) -> (expr)
1740 return leftVal ? std::unique_ptr<Expression>(new BoolLiteral(context, left.fOffset, true))
1741 : right.clone();
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001742 } else if (op == Token::Kind::TK_LOGICALXOR) {
Noah Lavine334d0ba2019-12-18 23:03:49 -05001743 // (true ^^ expr) -> !(expr) and (false ^^ expr) -> (expr)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001744 return leftVal ? std::unique_ptr<Expression>(new PrefixExpression(
1745 Token::Kind::TK_LOGICALNOT,
1746 right.clone()))
Noah Lavine334d0ba2019-12-18 23:03:49 -05001747 : right.clone();
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001748 } else {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001749 return nullptr;
1750 }
1751}
1752
ethannicholas08a92112016-11-09 13:26:45 -08001753std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
1754 Token::Kind op,
Ethan Nicholas86a43402017-01-19 13:32:00 -05001755 const Expression& right) const {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001756 // If the left side is a constant boolean literal, the right side does not need to be constant
1757 // for short circuit optimizations to allow the constant to be folded.
Ethan Nicholase6592142020-09-08 10:22:09 -04001758 if (left.kind() == Expression::Kind::kBoolLiteral && !right.isCompileTimeConstant()) {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001759 return short_circuit_boolean(fContext, left, op, right);
Ethan Nicholase6592142020-09-08 10:22:09 -04001760 } else if (right.kind() == Expression::Kind::kBoolLiteral && !left.isCompileTimeConstant()) {
Michael Ludwig7b429ae2018-09-06 17:01:38 -04001761 // There aren't side effects in SKSL within expressions, so (left OP right) is equivalent to
1762 // (right OP left) for short-circuit optimizations
1763 return short_circuit_boolean(fContext, right, op, left);
1764 }
1765
1766 // Other than the short-circuit cases above, constant folding requires both sides to be constant
Brian Osmanb6b95732020-06-30 11:44:27 -04001767 if (!left.isCompileTimeConstant() || !right.isCompileTimeConstant()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001768 return nullptr;
1769 }
ethannicholas08a92112016-11-09 13:26:45 -08001770 // Note that we expressly do not worry about precision and overflow here -- we use the maximum
1771 // precision to calculate the results and hope the result makes sense. The plan is to move the
1772 // Skia caps into SkSL, so we have access to all of them including the precisions of the various
1773 // types, which will let us be more intelligent about this.
Ethan Nicholase6592142020-09-08 10:22:09 -04001774 if (left.kind() == Expression::Kind::kBoolLiteral &&
1775 right.kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04001776 bool leftVal = left.as<BoolLiteral>().value();
1777 bool rightVal = right.as<BoolLiteral>().value();
ethannicholas08a92112016-11-09 13:26:45 -08001778 bool result;
1779 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001780 case Token::Kind::TK_LOGICALAND: result = leftVal && rightVal; break;
1781 case Token::Kind::TK_LOGICALOR: result = leftVal || rightVal; break;
1782 case Token::Kind::TK_LOGICALXOR: result = leftVal ^ rightVal; break;
ethannicholas08a92112016-11-09 13:26:45 -08001783 default: return nullptr;
1784 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001785 return std::unique_ptr<Expression>(new BoolLiteral(fContext, left.fOffset, result));
ethannicholas08a92112016-11-09 13:26:45 -08001786 }
John Stilesfbd050b2020-08-03 13:21:46 -04001787 #define RESULT(t, op) std::make_unique<t ## Literal>(fContext, left.fOffset, \
1788 leftVal op rightVal)
1789 #define URESULT(t, op) std::make_unique<t ## Literal>(fContext, left.fOffset, \
1790 (uint32_t) leftVal op \
1791 (uint32_t) rightVal)
Ethan Nicholase6592142020-09-08 10:22:09 -04001792 if (left.kind() == Expression::Kind::kIntLiteral &&
1793 right.kind() == Expression::Kind::kIntLiteral) {
Ethan Nicholase96cdd12020-09-28 16:27:18 -04001794 int64_t leftVal = left.as<IntLiteral>().value();
1795 int64_t rightVal = right.as<IntLiteral>().value();
ethannicholas08a92112016-11-09 13:26:45 -08001796 switch (op) {
Ethan Nicholas66869e92020-04-30 09:27:54 -04001797 case Token::Kind::TK_PLUS: return URESULT(Int, +);
1798 case Token::Kind::TK_MINUS: return URESULT(Int, -);
1799 case Token::Kind::TK_STAR: return URESULT(Int, *);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001800 case Token::Kind::TK_SLASH:
Ethan Nicholas66869e92020-04-30 09:27:54 -04001801 if (leftVal == std::numeric_limits<int64_t>::min() && rightVal == -1) {
1802 fErrors.error(right.fOffset, "arithmetic overflow");
1803 return nullptr;
Ethan Nicholas9a5610e2017-01-03 15:16:29 -05001804 }
Ethan Nicholas66869e92020-04-30 09:27:54 -04001805 if (!rightVal) {
1806 fErrors.error(right.fOffset, "division by zero");
1807 return nullptr;
1808 }
1809 return RESULT(Int, /);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001810 case Token::Kind::TK_PERCENT:
Ethan Nicholas66869e92020-04-30 09:27:54 -04001811 if (leftVal == std::numeric_limits<int64_t>::min() && rightVal == -1) {
1812 fErrors.error(right.fOffset, "arithmetic overflow");
1813 return nullptr;
Ethan Nicholas2503ab62017-01-05 10:44:25 -05001814 }
Ethan Nicholas66869e92020-04-30 09:27:54 -04001815 if (!rightVal) {
1816 fErrors.error(right.fOffset, "division by zero");
1817 return nullptr;
1818 }
1819 return RESULT(Int, %);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001820 case Token::Kind::TK_BITWISEAND: return RESULT(Int, &);
1821 case Token::Kind::TK_BITWISEOR: return RESULT(Int, |);
1822 case Token::Kind::TK_BITWISEXOR: return RESULT(Int, ^);
1823 case Token::Kind::TK_EQEQ: return RESULT(Bool, ==);
1824 case Token::Kind::TK_NEQ: return RESULT(Bool, !=);
1825 case Token::Kind::TK_GT: return RESULT(Bool, >);
1826 case Token::Kind::TK_GTEQ: return RESULT(Bool, >=);
1827 case Token::Kind::TK_LT: return RESULT(Bool, <);
1828 case Token::Kind::TK_LTEQ: return RESULT(Bool, <=);
1829 case Token::Kind::TK_SHL:
Ethan Nicholasfeba68a2019-06-10 09:56:29 -04001830 if (rightVal >= 0 && rightVal <= 31) {
Ethan Nicholase4489002020-04-29 14:00:14 -04001831 return URESULT(Int, <<);
Ethan Nicholasfeba68a2019-06-10 09:56:29 -04001832 }
1833 fErrors.error(right.fOffset, "shift value out of range");
1834 return nullptr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001835 case Token::Kind::TK_SHR:
Ethan Nicholasfeba68a2019-06-10 09:56:29 -04001836 if (rightVal >= 0 && rightVal <= 31) {
Ethan Nicholase4489002020-04-29 14:00:14 -04001837 return URESULT(Int, >>);
Ethan Nicholasfeba68a2019-06-10 09:56:29 -04001838 }
1839 fErrors.error(right.fOffset, "shift value out of range");
1840 return nullptr;
1841
1842 default:
1843 return nullptr;
ethannicholas08a92112016-11-09 13:26:45 -08001844 }
1845 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001846 if (left.kind() == Expression::Kind::kFloatLiteral &&
1847 right.kind() == Expression::Kind::kFloatLiteral) {
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04001848 SKSL_FLOAT leftVal = left.as<FloatLiteral>().value();
1849 SKSL_FLOAT rightVal = right.as<FloatLiteral>().value();
ethannicholas08a92112016-11-09 13:26:45 -08001850 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001851 case Token::Kind::TK_PLUS: return RESULT(Float, +);
1852 case Token::Kind::TK_MINUS: return RESULT(Float, -);
1853 case Token::Kind::TK_STAR: return RESULT(Float, *);
1854 case Token::Kind::TK_SLASH:
Ethan Nicholas9a5610e2017-01-03 15:16:29 -05001855 if (rightVal) {
1856 return RESULT(Float, /);
1857 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001858 fErrors.error(right.fOffset, "division by zero");
Ethan Nicholas9a5610e2017-01-03 15:16:29 -05001859 return nullptr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001860 case Token::Kind::TK_EQEQ: return RESULT(Bool, ==);
1861 case Token::Kind::TK_NEQ: return RESULT(Bool, !=);
1862 case Token::Kind::TK_GT: return RESULT(Bool, >);
1863 case Token::Kind::TK_GTEQ: return RESULT(Bool, >=);
1864 case Token::Kind::TK_LT: return RESULT(Bool, <);
1865 case Token::Kind::TK_LTEQ: return RESULT(Bool, <=);
1866 default: return nullptr;
ethannicholas08a92112016-11-09 13:26:45 -08001867 }
1868 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001869 const Type& leftType = left.type();
1870 const Type& rightType = right.type();
1871 if (leftType.typeKind() == Type::TypeKind::kVector && leftType.componentType().isFloat() &&
1872 leftType == rightType) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001873 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas4cf5fd92019-06-10 16:15:56 -04001874 #define RETURN_VEC_COMPONENTWISE_RESULT(op) \
Ethan Nicholas30d30222020-09-11 12:27:26 -04001875 for (int i = 0; i < leftType.columns(); i++) { \
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04001876 SKSL_FLOAT value = left.getFVecComponent(i) op \
1877 right.getFVecComponent(i); \
Ethan Nicholas4cf5fd92019-06-10 16:15:56 -04001878 args.emplace_back(new FloatLiteral(fContext, -1, value)); \
1879 } \
Ethan Nicholas30d30222020-09-11 12:27:26 -04001880 return std::unique_ptr<Expression>(new Constructor(-1, &leftType, \
Brian Salomon23356442018-11-30 15:33:19 -05001881 std::move(args)))
Ethan Nicholascb670962017-04-20 19:31:52 -04001882 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001883 case Token::Kind::TK_EQEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001884 return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1,
Ethan Nicholas3deaeb22017-04-25 14:42:11 -04001885 left.compareConstant(fContext, right)));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001886 case Token::Kind::TK_NEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001887 return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1,
Ethan Nicholas3deaeb22017-04-25 14:42:11 -04001888 !left.compareConstant(fContext, right)));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001889 case Token::Kind::TK_PLUS: RETURN_VEC_COMPONENTWISE_RESULT(+);
1890 case Token::Kind::TK_MINUS: RETURN_VEC_COMPONENTWISE_RESULT(-);
1891 case Token::Kind::TK_STAR: RETURN_VEC_COMPONENTWISE_RESULT(*);
1892 case Token::Kind::TK_SLASH:
Ethan Nicholas30d30222020-09-11 12:27:26 -04001893 for (int i = 0; i < leftType.columns(); i++) {
Ethan Nicholas4cf5fd92019-06-10 16:15:56 -04001894 SKSL_FLOAT rvalue = right.getFVecComponent(i);
1895 if (rvalue == 0.0) {
1896 fErrors.error(right.fOffset, "division by zero");
1897 return nullptr;
1898 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04001899 SKSL_FLOAT value = left.getFVecComponent(i) / rvalue;
Ethan Nicholas4cf5fd92019-06-10 16:15:56 -04001900 args.emplace_back(new FloatLiteral(fContext, -1, value));
1901 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001902 return std::unique_ptr<Expression>(new Constructor(-1, &leftType,
Ethan Nicholas4cf5fd92019-06-10 16:15:56 -04001903 std::move(args)));
Ethan Nicholase6592142020-09-08 10:22:09 -04001904 default:
1905 return nullptr;
Ethan Nicholascb670962017-04-20 19:31:52 -04001906 }
1907 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001908 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
1909 rightType.typeKind() == Type::TypeKind::kMatrix &&
Ethan Nicholase6592142020-09-08 10:22:09 -04001910 left.kind() == right.kind()) {
Ethan Nicholas3deaeb22017-04-25 14:42:11 -04001911 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001912 case Token::Kind::TK_EQEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001913 return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1,
Ethan Nicholas3deaeb22017-04-25 14:42:11 -04001914 left.compareConstant(fContext, right)));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001915 case Token::Kind::TK_NEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001916 return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1,
Ethan Nicholas3deaeb22017-04-25 14:42:11 -04001917 !left.compareConstant(fContext, right)));
1918 default:
1919 return nullptr;
1920 }
1921 }
ethannicholas08a92112016-11-09 13:26:45 -08001922 #undef RESULT
1923 return nullptr;
1924}
1925
Ethan Nicholasfc994162019-06-06 10:04:27 -04001926std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode& expression) {
1927 SkASSERT(expression.fKind == ASTNode::Kind::kBinary);
1928 auto iter = expression.begin();
1929 std::unique_ptr<Expression> left = this->convertExpression(*(iter++));
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 if (!left) {
1931 return nullptr;
1932 }
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001933 Token::Kind op = expression.getToken().fKind;
John Stiles941fc712020-09-19 12:47:10 +00001934 std::unique_ptr<Expression> right;
1935 {
1936 // Can't inline the right side of a short-circuiting boolean, because our inlining
1937 // approach runs things out of order.
1938 AutoDisableInline disableInline(this, /*canInline=*/(op != Token::Kind::TK_LOGICALAND &&
1939 op != Token::Kind::TK_LOGICALOR));
1940 right = this->convertExpression(*(iter++));
1941 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001942 if (!right) {
1943 return nullptr;
1944 }
ethannicholasd598f792016-07-25 10:08:54 -07001945 const Type* leftType;
1946 const Type* rightType;
1947 const Type* resultType;
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001948 const Type* rawLeftType;
John Stilesd0e48402020-09-22 14:00:40 -04001949 if (left->is<IntLiteral>() && right->type().isInteger()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001950 rawLeftType = &right->type();
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001951 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001952 rawLeftType = &left->type();
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001953 }
1954 const Type* rawRightType;
John Stilesd0e48402020-09-22 14:00:40 -04001955 if (right->is<IntLiteral>() && left->type().isInteger()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001956 rawRightType = &left->type();
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001957 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001958 rawRightType = &right->type();
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001959 }
Brian Osman0acb5b52020-09-02 13:45:47 -04001960 if (!determine_binary_type(fContext, fSettings->fAllowNarrowingConversions, op,
1961 *rawLeftType, *rawRightType, &leftType, &rightType, &resultType)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001962 fErrors.error(expression.fOffset, String("type mismatch: '") +
Ethan Nicholasfc994162019-06-06 10:04:27 -04001963 Compiler::OperatorName(expression.getToken().fKind) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04001964 "' cannot operate on '" + left->type().displayName() +
1965 "', '" + right->type().displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07001966 return nullptr;
1967 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04001968 if (Compiler::IsAssignment(op)) {
Ethan Nicholas4fadce42020-07-30 13:29:30 -04001969 if (!this->setRefKind(*left, op != Token::Kind::TK_EQ
1970 ? VariableReference::kReadWrite_RefKind
1971 : VariableReference::kWrite_RefKind)) {
1972 return nullptr;
1973 }
ethannicholasea4567c2016-10-17 11:24:37 -07001974 }
1975 left = this->coerce(std::move(left), *leftType);
1976 right = this->coerce(std::move(right), *rightType);
1977 if (!left || !right) {
1978 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07001979 }
John Stilesa008b0f2020-08-16 08:48:02 -04001980 std::unique_ptr<Expression> result = this->constantFold(*left, op, *right);
ethannicholas08a92112016-11-09 13:26:45 -08001981 if (!result) {
John Stilesd1c4dac2020-08-11 18:50:50 -04001982 result = std::make_unique<BinaryExpression>(expression.fOffset, std::move(left), op,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001983 std::move(right), resultType);
ethannicholas08a92112016-11-09 13:26:45 -08001984 }
1985 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001986}
1987
Ethan Nicholasfc994162019-06-06 10:04:27 -04001988std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(const ASTNode& node) {
1989 SkASSERT(node.fKind == ASTNode::Kind::kTernary);
1990 auto iter = node.begin();
1991 std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)),
ethannicholasd598f792016-07-25 10:08:54 -07001992 *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 if (!test) {
1994 return nullptr;
1995 }
John Stiles941fc712020-09-19 12:47:10 +00001996 std::unique_ptr<Expression> ifTrue;
1997 std::unique_ptr<Expression> ifFalse;
1998 {
1999 AutoDisableInline disableInline(this);
2000 ifTrue = this->convertExpression(*(iter++));
2001 if (!ifTrue) {
2002 return nullptr;
2003 }
2004 ifFalse = this->convertExpression(*(iter++));
2005 if (!ifFalse) {
2006 return nullptr;
2007 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 }
ethannicholasd598f792016-07-25 10:08:54 -07002009 const Type* trueType;
2010 const Type* falseType;
2011 const Type* resultType;
Brian Osman0acb5b52020-09-02 13:45:47 -04002012 if (!determine_binary_type(fContext, fSettings->fAllowNarrowingConversions,
2013 Token::Kind::TK_EQEQ, ifTrue->type(), ifFalse->type(),
2014 &trueType, &falseType, &resultType) ||
2015 trueType != falseType) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002016 fErrors.error(node.fOffset, "ternary operator result mismatch: '" +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002017 ifTrue->type().displayName() + "', '" +
2018 ifFalse->type().displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 return nullptr;
2020 }
Brian Osman82329002020-07-21 09:39:27 -04002021 if (trueType->nonnullable() == *fContext.fFragmentProcessor_Type) {
2022 fErrors.error(node.fOffset,
2023 "ternary expression of type '" + trueType->displayName() + "' not allowed");
2024 return nullptr;
2025 }
ethannicholasd598f792016-07-25 10:08:54 -07002026 ifTrue = this->coerce(std::move(ifTrue), *trueType);
Ethan Nicholas2be687a2017-01-03 16:44:39 -05002027 if (!ifTrue) {
2028 return nullptr;
2029 }
ethannicholasd598f792016-07-25 10:08:54 -07002030 ifFalse = this->coerce(std::move(ifFalse), *falseType);
Ethan Nicholas2be687a2017-01-03 16:44:39 -05002031 if (!ifFalse) {
2032 return nullptr;
2033 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002034 if (test->kind() == Expression::Kind::kBoolLiteral) {
ethannicholas08a92112016-11-09 13:26:45 -08002035 // static boolean test, just return one of the branches
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002036 if (test->as<BoolLiteral>().value()) {
ethannicholas08a92112016-11-09 13:26:45 -08002037 return ifTrue;
2038 } else {
2039 return ifFalse;
2040 }
2041 }
John Stiles8fa3b4e2020-09-02 11:27:23 -04002042 return std::make_unique<TernaryExpression>(node.fOffset,
2043 std::move(test),
2044 std::move(ifTrue),
2045 std::move(ifFalse));
ethannicholasb3058bd2016-07-01 08:22:01 -07002046}
2047
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002048void IRGenerator::copyIntrinsicIfNeeded(const FunctionDeclaration& function) {
Brian Osman00a8b5b2020-10-02 09:06:04 -04002049 if (const ProgramElement* found = fIntrinsics->findAndInclude(function.description())) {
Brian Osman2b469eb2020-09-21 11:32:10 -04002050 const FunctionDefinition& original = found->as<FunctionDefinition>();
John Stiles9878d9e2020-09-22 15:40:16 -04002051
2052 // Sort the referenced intrinsics into a consistent order; otherwise our output will become
2053 // non-deterministic.
2054 std::vector<const FunctionDeclaration*> intrinsics(original.fReferencedIntrinsics.begin(),
2055 original.fReferencedIntrinsics.end());
2056 std::sort(intrinsics.begin(), intrinsics.end(),
2057 [](const FunctionDeclaration* a, const FunctionDeclaration* b) {
Ethan Nicholased84b732020-10-08 11:45:44 -04002058 if (a->isBuiltin() != b->isBuiltin()) {
2059 return a->isBuiltin() < b->isBuiltin();
John Stiles9878d9e2020-09-22 15:40:16 -04002060 }
2061 if (a->fOffset != b->fOffset) {
2062 return a->fOffset < b->fOffset;
2063 }
Ethan Nicholase2c49992020-10-05 11:49:11 -04002064 if (a->name() != b->name()) {
2065 return a->name() < b->name();
John Stiles9878d9e2020-09-22 15:40:16 -04002066 }
2067 return a->description() < b->description();
2068 });
2069 for (const FunctionDeclaration* f : intrinsics) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002070 this->copyIntrinsicIfNeeded(*f);
2071 }
2072 fProgramElements->push_back(original.clone());
2073 }
2074}
2075
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002076std::unique_ptr<Expression> IRGenerator::call(int offset,
Ethan Nicholas11d53972016-11-28 11:23:23 -05002077 const FunctionDeclaration& function,
ethannicholasd598f792016-07-25 10:08:54 -07002078 std::vector<std::unique_ptr<Expression>> arguments) {
Ethan Nicholased84b732020-10-08 11:45:44 -04002079 if (function.isBuiltin()) {
2080 if (function.definition()) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002081 fReferencedIntrinsics.insert(&function);
2082 }
Brian Osman00a8b5b2020-10-02 09:06:04 -04002083 if (!fIsBuiltinCode && fIntrinsics) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002084 this->copyIntrinsicIfNeeded(function);
Ethan Nicholasdb80f692019-11-22 14:06:12 -05002085 }
2086 }
Ethan Nicholased84b732020-10-08 11:45:44 -04002087 if (function.parameters().size() != arguments.size()) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002088 String msg = "call to '" + function.name() + "' expected " +
Ethan Nicholased84b732020-10-08 11:45:44 -04002089 to_string((uint64_t) function.parameters().size()) +
ethannicholasb3058bd2016-07-01 08:22:01 -07002090 " argument";
Ethan Nicholased84b732020-10-08 11:45:44 -04002091 if (function.parameters().size() != 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002092 msg += "s";
2093 }
ethannicholas5961bc92016-10-12 06:39:56 -07002094 msg += ", but found " + to_string((uint64_t) arguments.size());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002095 fErrors.error(offset, msg);
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 return nullptr;
2097 }
Ethan Nicholased84b732020-10-08 11:45:44 -04002098 if (fKind == Program::kPipelineStage_Kind && !function.definition() && !function.isBuiltin()) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002099 String msg = "call to undefined function '" + function.name() + "'";
Brian Osman5f6b41e2020-03-09 11:53:24 -04002100 fErrors.error(offset, msg);
2101 return nullptr;
2102 }
ethannicholas471e8942016-10-28 09:02:46 -07002103 std::vector<const Type*> types;
2104 const Type* returnType;
2105 if (!function.determineFinalTypes(arguments, &types, &returnType)) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002106 String msg = "no match for " + function.name() + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002107 String separator;
ethannicholas471e8942016-10-28 09:02:46 -07002108 for (size_t i = 0; i < arguments.size(); i++) {
2109 msg += separator;
2110 separator = ", ";
Ethan Nicholas30d30222020-09-11 12:27:26 -04002111 msg += arguments[i]->type().displayName();
ethannicholas471e8942016-10-28 09:02:46 -07002112 }
2113 msg += ")";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002114 fErrors.error(offset, msg);
ethannicholas471e8942016-10-28 09:02:46 -07002115 return nullptr;
2116 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholas471e8942016-10-28 09:02:46 -07002118 arguments[i] = this->coerce(std::move(arguments[i]), *types[i]);
ethannicholasea4567c2016-10-17 11:24:37 -07002119 if (!arguments[i]) {
2120 return nullptr;
2121 }
Ethan Nicholased84b732020-10-08 11:45:44 -04002122 const Modifiers& paramModifiers = function.parameters()[i]->modifiers();
John Stiles978674a2020-09-23 15:24:51 -04002123 if (paramModifiers.fFlags & Modifiers::kOut_Flag) {
2124 if (!this->setRefKind(*arguments[i], paramModifiers.fFlags & Modifiers::kIn_Flag
2125 ? VariableReference::kReadWrite_RefKind
2126 : VariableReference::kPointer_RefKind)) {
2127 return nullptr;
2128 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 }
2130 }
John Stilesea9ab822020-08-31 09:55:04 -04002131
Ethan Nicholas0dec9922020-10-05 15:51:52 -04002132 auto funcCall = std::make_unique<FunctionCall>(offset, returnType, &function,
John Stiles941fc712020-09-19 12:47:10 +00002133 std::move(arguments));
John Stiles2d7973a2020-10-02 15:01:03 -04002134 if (fCanInline &&
Ethan Nicholased84b732020-10-08 11:45:44 -04002135 fInliner->isSafeToInline(funcCall->function().definition()) &&
2136 !fInliner->isLargeFunction(funcCall->function().definition())) {
John Stiles2d7973a2020-10-02 15:01:03 -04002137 Inliner::InlinedCall inlinedCall = fInliner->inlineCall(funcCall.get(), fSymbolTable.get(),
2138 fCurrentFunction);
John Stiles941fc712020-09-19 12:47:10 +00002139 if (inlinedCall.fInlinedBody) {
2140 fExtraStatements.push_back(std::move(inlinedCall.fInlinedBody));
2141 }
2142 return std::move(inlinedCall.fReplacementExpr);
2143 }
2144
2145 return std::move(funcCall);
ethannicholasb3058bd2016-07-01 08:22:01 -07002146}
2147
2148/**
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04002149 * Determines the cost of coercing the arguments of a function to the required types. Cost has no
Brian Osman0acb5b52020-09-02 13:45:47 -04002150 * particular meaning other than "lower costs are preferred". Returns CoercionCost::Impossible() if
2151 * the call is not valid.
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 */
Brian Osman0acb5b52020-09-02 13:45:47 -04002153CoercionCost IRGenerator::callCost(const FunctionDeclaration& function,
2154 const std::vector<std::unique_ptr<Expression>>& arguments) {
Ethan Nicholased84b732020-10-08 11:45:44 -04002155 if (function.parameters().size() != arguments.size()) {
Brian Osman0acb5b52020-09-02 13:45:47 -04002156 return CoercionCost::Impossible();
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 }
ethannicholas471e8942016-10-28 09:02:46 -07002158 std::vector<const Type*> types;
2159 const Type* ignored;
2160 if (!function.determineFinalTypes(arguments, &types, &ignored)) {
Brian Osman0acb5b52020-09-02 13:45:47 -04002161 return CoercionCost::Impossible();
ethannicholas471e8942016-10-28 09:02:46 -07002162 }
Brian Osman0acb5b52020-09-02 13:45:47 -04002163 CoercionCost total = CoercionCost::Free();
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 for (size_t i = 0; i < arguments.size(); i++) {
Brian Osman0acb5b52020-09-02 13:45:47 -04002165 total = total + arguments[i]->coercionCost(*types[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07002166 }
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04002167 return total;
ethannicholasb3058bd2016-07-01 08:22:01 -07002168}
2169
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002170std::unique_ptr<Expression> IRGenerator::call(int offset,
Ethan Nicholas11d53972016-11-28 11:23:23 -05002171 std::unique_ptr<Expression> functionValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 std::vector<std::unique_ptr<Expression>> arguments) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002173 switch (functionValue->kind()) {
2174 case Expression::Kind::kTypeReference:
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002175 return this->convertConstructor(offset,
John Stiles403a3632020-08-20 12:11:48 -04002176 functionValue->as<TypeReference>().fValue,
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002177 std::move(arguments));
Ethan Nicholase6592142020-09-08 10:22:09 -04002178 case Expression::Kind::kExternalValue: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002179 const ExternalValue& v = functionValue->as<ExternalValueReference>().value();
2180 if (!v.canCall()) {
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002181 fErrors.error(offset, "this external value is not a function");
2182 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002184 int count = v.callParameterCount();
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002185 if (count != (int) arguments.size()) {
2186 fErrors.error(offset, "external function expected " + to_string(count) +
2187 " arguments, but found " + to_string((int) arguments.size()));
2188 return nullptr;
2189 }
2190 static constexpr int PARAMETER_MAX = 16;
2191 SkASSERT(count < PARAMETER_MAX);
2192 const Type* types[PARAMETER_MAX];
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002193 v.getCallParameterTypes(types);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002194 for (int i = 0; i < count; ++i) {
2195 arguments[i] = this->coerce(std::move(arguments[i]), *types[i]);
2196 if (!arguments[i]) {
2197 return nullptr;
2198 }
2199 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002200 return std::make_unique<ExternalFunctionCall>(offset, &v, std::move(arguments));
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002202 case Expression::Kind::kFunctionReference: {
John Stilesce591b72020-08-27 11:47:30 -04002203 const FunctionReference& ref = functionValue->as<FunctionReference>();
Brian Osman0acb5b52020-09-02 13:45:47 -04002204 CoercionCost bestCost = CoercionCost::Impossible();
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002205 const FunctionDeclaration* best = nullptr;
John Stilesce591b72020-08-27 11:47:30 -04002206 if (ref.fFunctions.size() > 1) {
2207 for (const auto& f : ref.fFunctions) {
Brian Osman0acb5b52020-09-02 13:45:47 -04002208 CoercionCost cost = this->callCost(*f, arguments);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002209 if (cost < bestCost) {
2210 bestCost = cost;
2211 best = f;
2212 }
2213 }
2214 if (best) {
2215 return this->call(offset, *best, std::move(arguments));
2216 }
Ethan Nicholase2c49992020-10-05 11:49:11 -04002217 String msg = "no match for " + ref.fFunctions[0]->name() + "(";
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002218 String separator;
2219 for (size_t i = 0; i < arguments.size(); i++) {
2220 msg += separator;
2221 separator = ", ";
Ethan Nicholas30d30222020-09-11 12:27:26 -04002222 msg += arguments[i]->type().displayName();
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002223 }
2224 msg += ")";
2225 fErrors.error(offset, msg);
2226 return nullptr;
2227 }
John Stilesce591b72020-08-27 11:47:30 -04002228 return this->call(offset, *ref.fFunctions[0], std::move(arguments));
ethannicholasb3058bd2016-07-01 08:22:01 -07002229 }
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002230 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002231 fErrors.error(offset, "not a function");
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04002232 return nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002233 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002234}
2235
Ethan Nicholas84645e32017-02-09 13:57:14 -05002236std::unique_ptr<Expression> IRGenerator::convertNumberConstructor(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002237 int offset,
Ethan Nicholas11d53972016-11-28 11:23:23 -05002238 const Type& type,
ethannicholasb3058bd2016-07-01 08:22:01 -07002239 std::vector<std::unique_ptr<Expression>> args) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002240 SkASSERT(type.isNumber());
Ethan Nicholas84645e32017-02-09 13:57:14 -05002241 if (args.size() != 1) {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002242 fErrors.error(offset, "invalid arguments to '" + type.displayName() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002243 "' constructor, (expected exactly 1 argument, but found " +
2244 to_string((uint64_t) args.size()) + ")");
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 return nullptr;
2246 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002247 const Type& argType = args[0]->type();
2248 if (type == argType) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04002249 return std::move(args[0]);
2250 }
John Stilesd0e48402020-09-22 14:00:40 -04002251 if (type.isFloat() && args.size() == 1 && args[0]->is<FloatLiteral>()) {
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002252 SKSL_FLOAT value = args[0]->as<FloatLiteral>().value();
John Stilesd0e48402020-09-22 14:00:40 -04002253 return std::make_unique<FloatLiteral>(offset, value, &type);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04002254 }
John Stilesd0e48402020-09-22 14:00:40 -04002255 if (type.isFloat() && args.size() == 1 && args[0]->is<IntLiteral>()) {
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002256 int64_t value = args[0]->as<IntLiteral>().value();
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002257 return std::make_unique<FloatLiteral>(offset, (float)value, &type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002258 }
John Stilesd0e48402020-09-22 14:00:40 -04002259 if (args[0]->is<IntLiteral>() && (type == *fContext.fInt_Type ||
2260 type == *fContext.fUInt_Type)) {
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002261 return std::make_unique<IntLiteral>(offset, args[0]->as<IntLiteral>().value(), &type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002262 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002263 if (argType == *fContext.fBool_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002264 std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, offset, 0));
2265 std::unique_ptr<IntLiteral> one(new IntLiteral(fContext, offset, 1));
John Stilesd0e48402020-09-22 14:00:40 -04002266 return std::make_unique<TernaryExpression>(offset, std::move(args[0]),
2267 this->coerce(std::move(one), type),
2268 this->coerce(std::move(zero), type));
Ethan Nicholas84645e32017-02-09 13:57:14 -05002269 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002270 if (!argType.isNumber()) {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002271 fErrors.error(offset, "invalid argument to '" + type.displayName() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002272 "' constructor (expected a number or bool, but found '" +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002273 argType.displayName() + "')");
Ethan Nicholas84645e32017-02-09 13:57:14 -05002274 return nullptr;
2275 }
John Stilesd0e48402020-09-22 14:00:40 -04002276 return std::make_unique<Constructor>(offset, &type, std::move(args));
Ethan Nicholas84645e32017-02-09 13:57:14 -05002277}
2278
John Stiles36374402020-08-13 12:16:44 -04002279static int component_count(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002280 switch (type.typeKind()) {
2281 case Type::TypeKind::kVector:
Ethan Nicholas84645e32017-02-09 13:57:14 -05002282 return type.columns();
Ethan Nicholase6592142020-09-08 10:22:09 -04002283 case Type::TypeKind::kMatrix:
Ethan Nicholas84645e32017-02-09 13:57:14 -05002284 return type.columns() * type.rows();
2285 default:
2286 return 1;
2287 }
2288}
2289
2290std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002291 int offset,
Ethan Nicholas84645e32017-02-09 13:57:14 -05002292 const Type& type,
2293 std::vector<std::unique_ptr<Expression>> args) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002294 SkASSERT(type.typeKind() == Type::TypeKind::kVector ||
2295 type.typeKind() == Type::TypeKind::kMatrix);
2296 if (type.typeKind() == Type::TypeKind::kMatrix && args.size() == 1 &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04002297 args[0]->type().typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas84645e32017-02-09 13:57:14 -05002298 // matrix from matrix is always legal
Ethan Nicholas30d30222020-09-11 12:27:26 -04002299 return std::unique_ptr<Expression>(new Constructor(offset, &type, std::move(args)));
Ethan Nicholas84645e32017-02-09 13:57:14 -05002300 }
2301 int actual = 0;
2302 int expected = type.rows() * type.columns();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002303 if (args.size() != 1 || expected != component_count(args[0]->type()) ||
2304 type.componentType().isNumber() != args[0]->type().componentType().isNumber()) {
ethannicholas5961bc92016-10-12 06:39:56 -07002305 for (size_t i = 0; i < args.size(); i++) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002306 const Type& argType = args[i]->type();
2307 if (argType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002308 if (type.componentType().isNumber() !=
Ethan Nicholas30d30222020-09-11 12:27:26 -04002309 argType.componentType().isNumber()) {
2310 fErrors.error(offset, "'" + argType.displayName() + "' is not a valid "
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002311 "parameter to '" + type.displayName() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002312 "' constructor");
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002313 return nullptr;
2314 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002315 actual += argType.columns();
2316 } else if (argType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002317 actual += 1;
Ethan Nicholase6592142020-09-08 10:22:09 -04002318 if (type.typeKind() != Type::TypeKind::kScalar) {
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002319 args[i] = this->coerce(std::move(args[i]), type.componentType());
2320 if (!args[i]) {
2321 return nullptr;
2322 }
2323 }
2324 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002325 fErrors.error(offset, "'" + argType.displayName() + "' is not a valid "
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002326 "parameter to '" + type.displayName() + "' constructor");
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002327 return nullptr;
2328 }
2329 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05002330 if (actual != 1 && actual != expected) {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002331 fErrors.error(offset, "invalid arguments to '" + type.displayName() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002332 "' constructor (expected " + to_string(expected) +
2333 " scalars, but found " + to_string(actual) + ")");
Ethan Nicholas49a36ba2017-02-09 17:04:23 +00002334 return nullptr;
2335 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002336 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002337 return std::unique_ptr<Expression>(new Constructor(offset, &type, std::move(args)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002338}
2339
Ethan Nicholas84645e32017-02-09 13:57:14 -05002340std::unique_ptr<Expression> IRGenerator::convertConstructor(
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002341 int offset,
Ethan Nicholas84645e32017-02-09 13:57:14 -05002342 const Type& type,
2343 std::vector<std::unique_ptr<Expression>> args) {
2344 // FIXME: add support for structs
Ethan Nicholas30d30222020-09-11 12:27:26 -04002345 if (args.size() == 1 && args[0]->type() == type &&
Brian Osman82329002020-07-21 09:39:27 -04002346 type.nonnullable() != *fContext.fFragmentProcessor_Type) {
Ethan Nicholas84645e32017-02-09 13:57:14 -05002347 // argument is already the right type, just return it
2348 return std::move(args[0]);
2349 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002350 Type::TypeKind kind = type.typeKind();
Ethan Nicholas84645e32017-02-09 13:57:14 -05002351 if (type.isNumber()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002352 return this->convertNumberConstructor(offset, type, std::move(args));
Ethan Nicholase6592142020-09-08 10:22:09 -04002353 } else if (kind == Type::TypeKind::kArray) {
Ethan Nicholas84645e32017-02-09 13:57:14 -05002354 const Type& base = type.componentType();
2355 for (size_t i = 0; i < args.size(); i++) {
2356 args[i] = this->coerce(std::move(args[i]), base);
2357 if (!args[i]) {
2358 return nullptr;
2359 }
2360 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002361 return std::make_unique<Constructor>(offset, &type, std::move(args));
Ethan Nicholase6592142020-09-08 10:22:09 -04002362 } else if (kind == Type::TypeKind::kVector || kind == Type::TypeKind::kMatrix) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002363 return this->convertCompoundConstructor(offset, type, std::move(args));
Ethan Nicholas84645e32017-02-09 13:57:14 -05002364 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002365 fErrors.error(offset, "cannot construct '" + type.displayName() + "'");
Ethan Nicholas84645e32017-02-09 13:57:14 -05002366 return nullptr;
2367 }
2368}
2369
Ethan Nicholasfc994162019-06-06 10:04:27 -04002370std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(const ASTNode& expression) {
2371 SkASSERT(expression.fKind == ASTNode::Kind::kPrefix);
2372 std::unique_ptr<Expression> base = this->convertExpression(*expression.begin());
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 if (!base) {
2374 return nullptr;
2375 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002376 const Type& baseType = base->type();
Ethan Nicholasfc994162019-06-06 10:04:27 -04002377 switch (expression.getToken().fKind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002378 case Token::Kind::TK_PLUS:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002379 if (!baseType.isNumber() && baseType.typeKind() != Type::TypeKind::kVector &&
2380 baseType != *fContext.fFloatLiteral_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002381 fErrors.error(expression.fOffset,
Ethan Nicholas30d30222020-09-11 12:27:26 -04002382 "'+' cannot operate on '" + baseType.displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 return nullptr;
2384 }
2385 return base;
John Stiles978674a2020-09-23 15:24:51 -04002386
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002387 case Token::Kind::TK_MINUS:
John Stiles978674a2020-09-23 15:24:51 -04002388 if (base->is<IntLiteral>()) {
2389 return std::make_unique<IntLiteral>(fContext, base->fOffset,
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002390 -base->as<IntLiteral>().value());
ethannicholasb3058bd2016-07-01 08:22:01 -07002391 }
John Stiles978674a2020-09-23 15:24:51 -04002392 if (base->is<FloatLiteral>()) {
2393 return std::make_unique<FloatLiteral>(fContext, base->fOffset,
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002394 -base->as<FloatLiteral>().value());
ethannicholasb3058bd2016-07-01 08:22:01 -07002395 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002396 if (!baseType.isNumber() && baseType.typeKind() != Type::TypeKind::kVector) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002397 fErrors.error(expression.fOffset,
Ethan Nicholas30d30222020-09-11 12:27:26 -04002398 "'-' cannot operate on '" + baseType.displayName() + "'");
Ethan Nicholase1f55022019-02-05 17:17:40 -05002399 return nullptr;
2400 }
John Stiles978674a2020-09-23 15:24:51 -04002401 return std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS, std::move(base));
2402
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002403 case Token::Kind::TK_PLUSPLUS:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002404 if (!baseType.isNumber()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002405 fErrors.error(expression.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04002406 String("'") + Compiler::OperatorName(expression.getToken().fKind) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002407 "' cannot operate on '" + baseType.displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002408 return nullptr;
2409 }
John Stiles978674a2020-09-23 15:24:51 -04002410 if (!this->setRefKind(*base, VariableReference::kReadWrite_RefKind)) {
2411 return nullptr;
2412 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002414 case Token::Kind::TK_MINUSMINUS:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002415 if (!baseType.isNumber()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002416 fErrors.error(expression.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04002417 String("'") + Compiler::OperatorName(expression.getToken().fKind) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002418 "' cannot operate on '" + baseType.displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 return nullptr;
2420 }
John Stiles978674a2020-09-23 15:24:51 -04002421 if (!this->setRefKind(*base, VariableReference::kReadWrite_RefKind)) {
2422 return nullptr;
2423 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002425 case Token::Kind::TK_LOGICALNOT:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002426 if (baseType != *fContext.fBool_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002427 fErrors.error(expression.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04002428 String("'") + Compiler::OperatorName(expression.getToken().fKind) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002429 "' cannot operate on '" + baseType.displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002430 return nullptr;
2431 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002432 if (base->kind() == Expression::Kind::kBoolLiteral) {
John Stiles978674a2020-09-23 15:24:51 -04002433 return std::make_unique<BoolLiteral>(fContext, base->fOffset,
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002434 !base->as<BoolLiteral>().value());
ethannicholas08a92112016-11-09 13:26:45 -08002435 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002437 case Token::Kind::TK_BITWISENOT:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002438 if (baseType != *fContext.fInt_Type && baseType != *fContext.fUInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002439 fErrors.error(expression.fOffset,
Ethan Nicholasfc994162019-06-06 10:04:27 -04002440 String("'") + Compiler::OperatorName(expression.getToken().fKind) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002441 "' cannot operate on '" + baseType.displayName() + "'");
ethannicholas5961bc92016-10-12 06:39:56 -07002442 return nullptr;
2443 }
2444 break;
Ethan Nicholas11d53972016-11-28 11:23:23 -05002445 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 ABORT("unsupported prefix operator\n");
2447 }
John Stiles978674a2020-09-23 15:24:51 -04002448 return std::make_unique<PrefixExpression>(expression.getToken().fKind, std::move(base));
ethannicholasb3058bd2016-07-01 08:22:01 -07002449}
2450
2451std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression> base,
Ethan Nicholasfc994162019-06-06 10:04:27 -04002452 const ASTNode& index) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002453 if (base->kind() == Expression::Kind::kTypeReference) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002454 if (index.fKind == ASTNode::Kind::kInt) {
John Stiles403a3632020-08-20 12:11:48 -04002455 const Type& oldType = base->as<TypeReference>().fValue;
Ethan Nicholasfc994162019-06-06 10:04:27 -04002456 SKSL_INT size = index.getInt();
John Stiles3ae071e2020-08-05 15:29:29 -04002457 const Type* newType = fSymbolTable->takeOwnershipOfSymbol(
2458 std::make_unique<Type>(oldType.name() + "[" + to_string(size) + "]",
Ethan Nicholase6592142020-09-08 10:22:09 -04002459 Type::TypeKind::kArray, oldType, size));
2460 return std::make_unique<TypeReference>(fContext, base->fOffset, newType);
Ethan Nicholas50afc172017-02-16 14:49:57 -05002461
2462 } else {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002463 fErrors.error(base->fOffset, "array size must be a constant");
Ethan Nicholas50afc172017-02-16 14:49:57 -05002464 return nullptr;
2465 }
2466 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002467 const Type& baseType = base->type();
2468 if (baseType.typeKind() != Type::TypeKind::kArray &&
2469 baseType.typeKind() != Type::TypeKind::kMatrix &&
2470 baseType.typeKind() != Type::TypeKind::kVector) {
2471 fErrors.error(base->fOffset, "expected array, but found '" + baseType.displayName() +
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002472 "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002473 return nullptr;
2474 }
2475 std::unique_ptr<Expression> converted = this->convertExpression(index);
2476 if (!converted) {
2477 return nullptr;
2478 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002479 if (converted->type() != *fContext.fUInt_Type) {
ethannicholas5961bc92016-10-12 06:39:56 -07002480 converted = this->coerce(std::move(converted), *fContext.fInt_Type);
2481 if (!converted) {
2482 return nullptr;
2483 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002484 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002485 return std::make_unique<IndexExpression>(fContext, std::move(base), std::move(converted));
ethannicholasb3058bd2016-07-01 08:22:01 -07002486}
2487
2488std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002489 StringFragment field) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002490 if (base->kind() == Expression::Kind::kExternalValue) {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002491 const ExternalValue& ev = base->as<ExternalValueReference>().value();
Ethan Nicholas91164d12019-05-15 15:29:54 -04002492 ExternalValue* result = ev.getChild(String(field).c_str());
2493 if (!result) {
2494 fErrors.error(base->fOffset, "external value does not have a child named '" + field +
2495 "'");
2496 return nullptr;
2497 }
2498 return std::unique_ptr<Expression>(new ExternalValueReference(base->fOffset, result));
2499 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002500 const Type& baseType = base->type();
2501 auto fields = baseType.fields();
ethannicholasb3058bd2016-07-01 08:22:01 -07002502 for (size_t i = 0; i < fields.size(); i++) {
2503 if (fields[i].fName == field) {
2504 return std::unique_ptr<Expression>(new FieldAccess(std::move(base), (int) i));
2505 }
2506 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002507 fErrors.error(base->fOffset, "type '" + baseType.displayName() + "' does not have a field "
John Stiles68861e32020-09-25 16:02:07 -04002508 "named '" + field + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002509 return nullptr;
2510}
2511
Brian Osman25647672020-09-15 15:16:56 -04002512// Swizzles are complicated due to constant components. The most difficult case is a mask like
John Stiles6e49a372020-09-16 13:40:54 -04002513// '.x1w0'. A naive approach might turn that into 'float4(base.x, 1, base.w, 0)', but that evaluates
2514// 'base' twice. We instead group the swizzle mask ('xw') and constants ('1, 0') together and use a
Brian Osman25647672020-09-15 15:16:56 -04002515// secondary swizzle to put them back into the right order, so in this case we end up with
John Stiles6e49a372020-09-16 13:40:54 -04002516// 'float4(base.xw, 1, 0).xzyw'.
ethannicholasb3058bd2016-07-01 08:22:01 -07002517std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002518 StringFragment fields) {
Brian Osman25647672020-09-15 15:16:56 -04002519 const int offset = base->fOffset;
Ethan Nicholas30d30222020-09-11 12:27:26 -04002520 const Type& baseType = base->type();
2521 if (baseType.typeKind() != Type::TypeKind::kVector && !baseType.isNumber()) {
Brian Osman25647672020-09-15 15:16:56 -04002522 fErrors.error(offset, "cannot swizzle value of type '" + baseType.displayName() + "'");
ethannicholasb3058bd2016-07-01 08:22:01 -07002523 return nullptr;
2524 }
Brian Osman25647672020-09-15 15:16:56 -04002525
2526 if (fields.fLength > 4) {
2527 fErrors.error(offset, "too many components in swizzle mask '" + fields + "'");
2528 return nullptr;
2529 }
2530
2531 std::vector<int> maskComponents;
John Stiles6e49a372020-09-16 13:40:54 -04002532 maskComponents.reserve(fields.fLength);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002533 for (size_t i = 0; i < fields.fLength; i++) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002534 switch (fields[i]) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05002535 case '0':
Ethan Nicholasac285b12019-02-12 16:05:18 -05002536 case '1':
John Stiles6e49a372020-09-16 13:40:54 -04002537 // Skip over constant fields for now.
Ethan Nicholasac285b12019-02-12 16:05:18 -05002538 break;
Ethan Nicholase455f652019-09-13 12:52:55 -04002539 case 'x':
2540 case 'r':
Ethan Nicholas11d53972016-11-28 11:23:23 -05002541 case 's':
Ethan Nicholase455f652019-09-13 12:52:55 -04002542 case 'L':
Brian Osman25647672020-09-15 15:16:56 -04002543 maskComponents.push_back(0);
ethannicholasb3058bd2016-07-01 08:22:01 -07002544 break;
Ethan Nicholase455f652019-09-13 12:52:55 -04002545 case 'y':
2546 case 'g':
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 case 't':
Ethan Nicholase455f652019-09-13 12:52:55 -04002548 case 'T':
Ethan Nicholas30d30222020-09-11 12:27:26 -04002549 if (baseType.columns() >= 2) {
Brian Osman25647672020-09-15 15:16:56 -04002550 maskComponents.push_back(1);
ethannicholasb3058bd2016-07-01 08:22:01 -07002551 break;
2552 }
John Stiles30212b72020-06-11 17:55:07 -04002553 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04002554 case 'z':
2555 case 'b':
Ethan Nicholas11d53972016-11-28 11:23:23 -05002556 case 'p':
Ethan Nicholase455f652019-09-13 12:52:55 -04002557 case 'R':
Ethan Nicholas30d30222020-09-11 12:27:26 -04002558 if (baseType.columns() >= 3) {
Brian Osman25647672020-09-15 15:16:56 -04002559 maskComponents.push_back(2);
ethannicholasb3058bd2016-07-01 08:22:01 -07002560 break;
2561 }
John Stiles30212b72020-06-11 17:55:07 -04002562 [[fallthrough]];
Ethan Nicholase455f652019-09-13 12:52:55 -04002563 case 'w':
2564 case 'a':
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 case 'q':
Ethan Nicholase455f652019-09-13 12:52:55 -04002566 case 'B':
Ethan Nicholas30d30222020-09-11 12:27:26 -04002567 if (baseType.columns() >= 4) {
Brian Osman25647672020-09-15 15:16:56 -04002568 maskComponents.push_back(3);
ethannicholasb3058bd2016-07-01 08:22:01 -07002569 break;
2570 }
John Stiles30212b72020-06-11 17:55:07 -04002571 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 default:
Brian Osman25647672020-09-15 15:16:56 -04002573 fErrors.error(offset, String::printf("invalid swizzle component '%c'", fields[i]));
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 return nullptr;
2575 }
2576 }
Brian Osman25647672020-09-15 15:16:56 -04002577 if (maskComponents.empty()) {
2578 fErrors.error(offset, "swizzle must refer to base expression");
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 return nullptr;
2580 }
Brian Osman25647672020-09-15 15:16:56 -04002581
2582 // First, we need a vector expression that is the non-constant portion of the swizzle, packed:
2583 // scalar.xxx -> type3(scalar)
2584 // scalar.x0x0 -> type2(scalar)
2585 // vector.zyx -> vector.zyx
2586 // vector.x0y0 -> vector.xy
2587 std::unique_ptr<Expression> expr;
Ethan Nicholas30d30222020-09-11 12:27:26 -04002588 if (baseType.isNumber()) {
Brian Osman25647672020-09-15 15:16:56 -04002589 std::vector<std::unique_ptr<Expression>> scalarConstructorArgs;
2590 scalarConstructorArgs.push_back(std::move(base));
2591 expr = std::make_unique<Constructor>(
2592 offset, &baseType.toCompound(fContext, maskComponents.size(), 1),
2593 std::move(scalarConstructorArgs));
2594 } else {
2595 expr = std::make_unique<Swizzle>(fContext, std::move(base), maskComponents);
Ethan Nicholas7b9da252020-08-03 13:43:50 -04002596 }
Brian Osman25647672020-09-15 15:16:56 -04002597
John Stiles6e49a372020-09-16 13:40:54 -04002598 // If we have processed the entire swizzle, we're done.
2599 if (maskComponents.size() == fields.fLength) {
Brian Osman25647672020-09-15 15:16:56 -04002600 return expr;
2601 }
2602
2603 // Now we create a constructor that has the correct number of elements for the final swizzle,
John Stiles6e49a372020-09-16 13:40:54 -04002604 // with all fields at the start. It's not finished yet; constants we need will be added below.
2605 // scalar.x0x0 -> type4(type2(x), ...)
2606 // vector.y111 -> type4(vector.y, ...)
2607 // vector.z10x -> type4(vector.zx, ...)
Brian Osman25647672020-09-15 15:16:56 -04002608 //
John Stiles6e49a372020-09-16 13:40:54 -04002609 // We could create simpler IR in some cases by reordering here, if all fields are packed
Brian Osman25647672020-09-15 15:16:56 -04002610 // contiguously. The benefits are minor, so skip the optimization to keep the algorithm simple.
John Stiles6e49a372020-09-16 13:40:54 -04002611 // The constructor will have at most three arguments: { base value, constant 0, constant 1 }
Brian Osman25647672020-09-15 15:16:56 -04002612 std::vector<std::unique_ptr<Expression>> constructorArgs;
John Stiles6e49a372020-09-16 13:40:54 -04002613 constructorArgs.reserve(3);
Brian Osman25647672020-09-15 15:16:56 -04002614 constructorArgs.push_back(std::move(expr));
John Stiles6e49a372020-09-16 13:40:54 -04002615
2616 // Apply another swizzle to shuffle the constants into the correct place. Any constant values we
2617 // need are also tacked on to the end of the constructor.
2618 // scalar.x0x0 -> type4(type2(x), 0).xyxy
2619 // vector.y111 -> type4(vector.y, 1).xyyy
2620 // vector.z10x -> type4(vector.zx, 1, 0).xzwy
Brian Osman25647672020-09-15 15:16:56 -04002621 const Type* numberType = baseType.isNumber() ? &baseType : &baseType.componentType();
John Stiles6e49a372020-09-16 13:40:54 -04002622 std::vector<int> swizzleComponents;
2623 swizzleComponents.reserve(fields.fLength);
2624 int maskFieldIdx = 0;
2625 int constantFieldIdx = maskComponents.size();
2626 int constantZeroIdx = -1, constantOneIdx = -1;
Brian Osman25647672020-09-15 15:16:56 -04002627
Brian Osman25647672020-09-15 15:16:56 -04002628 for (size_t i = 0; i < fields.fLength; i++) {
John Stiles6e49a372020-09-16 13:40:54 -04002629 switch (fields[i]) {
2630 case '0':
2631 if (constantZeroIdx == -1) {
John Stilesd0e48402020-09-22 14:00:40 -04002632 // Synthesize a 'type(0)' argument at the end of the constructor.
2633 auto zero = std::make_unique<Constructor>(
2634 offset, numberType, std::vector<std::unique_ptr<Expression>>{});
Ethan Nicholasf70f0442020-09-29 12:41:35 -04002635 zero->arguments().push_back(std::make_unique<IntLiteral>(fContext, offset,
2636 /*fValue=*/0));
John Stilesd0e48402020-09-22 14:00:40 -04002637 constructorArgs.push_back(std::move(zero));
John Stiles6e49a372020-09-16 13:40:54 -04002638 constantZeroIdx = constantFieldIdx++;
2639 }
2640 swizzleComponents.push_back(constantZeroIdx);
2641 break;
2642 case '1':
2643 if (constantOneIdx == -1) {
John Stilesd0e48402020-09-22 14:00:40 -04002644 // Synthesize a 'type(1)' argument at the end of the constructor.
2645 auto one = std::make_unique<Constructor>(
2646 offset, numberType, std::vector<std::unique_ptr<Expression>>{});
Ethan Nicholasf70f0442020-09-29 12:41:35 -04002647 one->arguments().push_back(std::make_unique<IntLiteral>(fContext, offset,
2648 /*fValue=*/1));
John Stilesd0e48402020-09-22 14:00:40 -04002649 constructorArgs.push_back(std::move(one));
John Stiles6e49a372020-09-16 13:40:54 -04002650 constantOneIdx = constantFieldIdx++;
2651 }
2652 swizzleComponents.push_back(constantOneIdx);
2653 break;
2654 default:
2655 // The non-constant fields are already in the expected order.
2656 swizzleComponents.push_back(maskFieldIdx++);
2657 break;
Brian Osman25647672020-09-15 15:16:56 -04002658 }
2659 }
2660
John Stiles6e49a372020-09-16 13:40:54 -04002661 expr = std::make_unique<Constructor>(offset,
2662 &numberType->toCompound(fContext, constantFieldIdx, 1),
2663 std::move(constructorArgs));
2664
John Stilesb23ea382020-09-16 13:41:14 -04002665 // For some of our most common use cases ('.xyz0', '.xyz1'), we will now have an identity
2666 // swizzle; in those cases we can just return the constructor without the swizzle attached.
2667 for (size_t i = 0; i < swizzleComponents.size(); ++i) {
2668 if (swizzleComponents[i] != int(i)) {
2669 // The swizzle has an effect, so apply it.
2670 return std::make_unique<Swizzle>(fContext, std::move(expr),
2671 std::move(swizzleComponents));
2672 }
2673 }
2674
2675 // The swizzle was a no-op; return the constructor expression directly.
2676 return expr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002677}
2678
Ethan Nicholas01ec7e82020-10-08 12:10:12 -04002679const Type* IRGenerator::typeForSetting(int offset, String name) const {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002680 auto found = fCapsMap.find(name);
2681 if (found == fCapsMap.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002682 fErrors.error(offset, "unknown capability flag '" + name + "'");
Ethan Nicholas3605ace2016-11-21 15:59:48 -05002683 return nullptr;
2684 }
Ethan Nicholas01ec7e82020-10-08 12:10:12 -04002685 switch (found->second.fKind) {
2686 case Program::Settings::Value::kBool_Kind: return fContext.fBool_Type.get();
2687 case Program::Settings::Value::kFloat_Kind: return fContext.fFloat_Type.get();
2688 case Program::Settings::Value::kInt_Kind: return fContext.fInt_Type.get();
2689 }
2690 SkUNREACHABLE;
2691 return nullptr;
2692}
2693
2694std::unique_ptr<Expression> IRGenerator::valueForSetting(int offset, String name) const {
2695 auto found = fCapsMap.find(name);
2696 if (found == fCapsMap.end()) {
2697 fErrors.error(offset, "unknown capability flag '" + name + "'");
2698 return nullptr;
2699 }
2700 return found->second.literal(fContext, offset);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002701}
2702
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002703std::unique_ptr<Expression> IRGenerator::convertTypeField(int offset, const Type& type,
2704 StringFragment field) {
Brian Osman1313d1a2020-09-08 10:34:30 -04002705 // Find the Enum element that this type refers to (if any)
Brian Osman2b469eb2020-09-21 11:32:10 -04002706 const ProgramElement* enumElement = nullptr;
2707 for (const auto& e : *fProgramElements) {
Ethan Nicholasd83ded82020-09-29 17:05:54 -04002708 if (e->is<Enum>() && type.name() == e->as<Enum>().typeName()) {
Brian Osman2b469eb2020-09-21 11:32:10 -04002709 enumElement = e.get();
2710 break;
Brian Osman1313d1a2020-09-08 10:34:30 -04002711 }
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002712 }
Brian Osman1313d1a2020-09-08 10:34:30 -04002713
2714 if (enumElement) {
2715 // We found the Enum element. Look for 'field' as a member.
2716 std::shared_ptr<SymbolTable> old = fSymbolTable;
Ethan Nicholasd83ded82020-09-29 17:05:54 -04002717 fSymbolTable = enumElement->as<Enum>().symbols();
Brian Osman1313d1a2020-09-08 10:34:30 -04002718 std::unique_ptr<Expression> result = convertIdentifier(
2719 ASTNode(&fFile->fNodes, offset, ASTNode::Kind::kIdentifier, field));
2720 if (result) {
Ethan Nicholas78686922020-10-08 06:46:27 -04002721 const Variable& v = *result->as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002722 SkASSERT(v.initialValue());
Brian Osman1313d1a2020-09-08 10:34:30 -04002723 result = std::make_unique<IntLiteral>(
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002724 offset, v.initialValue()->as<IntLiteral>().value(), &type);
Brian Osman1313d1a2020-09-08 10:34:30 -04002725 } else {
2726 fErrors.error(offset,
Ethan Nicholase2c49992020-10-05 11:49:11 -04002727 "type '" + type.name() + "' does not have a member named '" + field +
2728 "'");
Brian Osman1313d1a2020-09-08 10:34:30 -04002729 }
2730 fSymbolTable = old;
2731 return result;
2732 } else {
2733 // No Enum element? Check the intrinsics, clone it into the program, try again.
Brian Osman00a8b5b2020-10-02 09:06:04 -04002734 if (!fIsBuiltinCode && fIntrinsics) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002735 if (const ProgramElement* found = fIntrinsics->findAndInclude(type.name())) {
Brian Osman00a8b5b2020-10-02 09:06:04 -04002736 fProgramElements->push_back(found->clone());
2737 return this->convertTypeField(offset, type, field);
2738 }
Ethan Nicholasdb80f692019-11-22 14:06:12 -05002739 }
Brian Osman1313d1a2020-09-08 10:34:30 -04002740 fErrors.error(offset,
Ethan Nicholase2c49992020-10-05 11:49:11 -04002741 "type '" + type.displayName() + "' does not have a member named '" + field +
2742 "'");
Brian Osman1313d1a2020-09-08 10:34:30 -04002743 return nullptr;
Ethan Nicholasaae47c82017-11-10 15:34:03 -05002744 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05002745}
2746
Ethan Nicholasfc994162019-06-06 10:04:27 -04002747std::unique_ptr<Expression> IRGenerator::convertIndexExpression(const ASTNode& index) {
2748 SkASSERT(index.fKind == ASTNode::Kind::kIndex);
2749 auto iter = index.begin();
2750 std::unique_ptr<Expression> base = this->convertExpression(*(iter++));
ethannicholasb3058bd2016-07-01 08:22:01 -07002751 if (!base) {
2752 return nullptr;
2753 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002754 if (iter != index.end()) {
2755 return this->convertIndex(std::move(base), *(iter++));
Ethan Nicholase6592142020-09-08 10:22:09 -04002756 } else if (base->kind() == Expression::Kind::kTypeReference) {
John Stiles403a3632020-08-20 12:11:48 -04002757 const Type& oldType = base->as<TypeReference>().fValue;
John Stiles3ae071e2020-08-05 15:29:29 -04002758 const Type* newType = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>(
Brian Osmane8c26082020-10-01 17:22:45 -04002759 oldType.name() + "[]", Type::TypeKind::kArray, oldType, Type::kUnsizedArray));
Ethan Nicholase6592142020-09-08 10:22:09 -04002760 return std::make_unique<TypeReference>(fContext, base->fOffset, newType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002761 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002762 fErrors.error(index.fOffset, "'[]' must follow a type name");
2763 return nullptr;
2764}
2765
2766std::unique_ptr<Expression> IRGenerator::convertCallExpression(const ASTNode& callNode) {
2767 SkASSERT(callNode.fKind == ASTNode::Kind::kCall);
2768 auto iter = callNode.begin();
2769 std::unique_ptr<Expression> base = this->convertExpression(*(iter++));
2770 if (!base) {
2771 return nullptr;
2772 }
2773 std::vector<std::unique_ptr<Expression>> arguments;
2774 for (; iter != callNode.end(); ++iter) {
2775 std::unique_ptr<Expression> converted = this->convertExpression(*iter);
2776 if (!converted) {
2777 return nullptr;
2778 }
2779 arguments.push_back(std::move(converted));
2780 }
2781 return this->call(callNode.fOffset, std::move(base), std::move(arguments));
2782}
2783
2784std::unique_ptr<Expression> IRGenerator::convertFieldExpression(const ASTNode& fieldNode) {
2785 std::unique_ptr<Expression> base = this->convertExpression(*fieldNode.begin());
2786 if (!base) {
2787 return nullptr;
2788 }
2789 StringFragment field = fieldNode.getString();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002790 const Type& baseType = base->type();
2791 if (baseType == *fContext.fSkCaps_Type) {
Ethan Nicholas01ec7e82020-10-08 12:10:12 -04002792 const Type* type = this->typeForSetting(fieldNode.fOffset, field);
2793 if (!type) {
2794 return nullptr;
2795 }
2796 return std::make_unique<Setting>(fieldNode.fOffset, field, type);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002797 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002798 if (base->kind() == Expression::Kind::kExternalValue) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002799 return this->convertField(std::move(base), field);
2800 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002801 switch (baseType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002802 case Type::TypeKind::kOther:
2803 case Type::TypeKind::kStruct:
Ethan Nicholasfc994162019-06-06 10:04:27 -04002804 return this->convertField(std::move(base), field);
2805 default:
Ethan Nicholas7b9da252020-08-03 13:43:50 -04002806 return this->convertSwizzle(std::move(base), field);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002807 }
2808}
2809
Brian Osman6518d772020-09-10 16:50:06 -04002810std::unique_ptr<Expression> IRGenerator::convertScopeExpression(const ASTNode& scopeNode) {
2811 std::unique_ptr<Expression> base = this->convertExpression(*scopeNode.begin());
2812 if (!base) {
2813 return nullptr;
2814 }
2815 if (!base->is<TypeReference>()) {
2816 fErrors.error(scopeNode.fOffset, "'::' must follow a type name");
2817 return nullptr;
2818 }
2819 StringFragment member = scopeNode.getString();
2820 return this->convertTypeField(base->fOffset, base->as<TypeReference>().fValue, member);
2821}
2822
Ethan Nicholasfc994162019-06-06 10:04:27 -04002823std::unique_ptr<Expression> IRGenerator::convertPostfixExpression(const ASTNode& expression) {
2824 std::unique_ptr<Expression> base = this->convertExpression(*expression.begin());
2825 if (!base) {
2826 return nullptr;
2827 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002828 const Type& baseType = base->type();
2829 if (!baseType.isNumber()) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002830 fErrors.error(expression.fOffset,
2831 "'" + String(Compiler::OperatorName(expression.getToken().fKind)) +
Ethan Nicholas30d30222020-09-11 12:27:26 -04002832 "' cannot operate on '" + baseType.displayName() + "'");
Ethan Nicholasfc994162019-06-06 10:04:27 -04002833 return nullptr;
2834 }
John Stiles978674a2020-09-23 15:24:51 -04002835 if (!this->setRefKind(*base, VariableReference::kReadWrite_RefKind)) {
2836 return nullptr;
2837 }
2838 return std::make_unique<PostfixExpression>(std::move(base), expression.getToken().fKind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002839}
2840
2841void IRGenerator::checkValid(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002842 switch (expr.kind()) {
2843 case Expression::Kind::kFunctionReference:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002844 fErrors.error(expr.fOffset, "expected '(' to begin function call");
ethannicholasb3058bd2016-07-01 08:22:01 -07002845 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002846 case Expression::Kind::kTypeReference:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002847 fErrors.error(expr.fOffset, "expected '(' to begin constructor invocation");
ethannicholasb3058bd2016-07-01 08:22:01 -07002848 break;
2849 default:
Ethan Nicholas30d30222020-09-11 12:27:26 -04002850 if (expr.type() == *fContext.fInvalid_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002851 fErrors.error(expr.fOffset, "invalid expression");
ethannicholasea4567c2016-10-17 11:24:37 -07002852 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002853 }
2854}
2855
John Stilesdce4d3e2020-09-25 14:35:13 -04002856bool IRGenerator::setRefKind(Expression& expr, VariableReference::RefKind kind) {
John Stilesa976da72020-09-25 23:06:26 -04002857 VariableReference* assignableVar = nullptr;
2858 if (!Analysis::IsAssignable(expr, &assignableVar, &fErrors)) {
John Stilesdce4d3e2020-09-25 14:35:13 -04002859 return false;
2860 }
John Stilesa976da72020-09-25 23:06:26 -04002861 if (assignableVar) {
2862 assignableVar->setRefKind(kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002863 }
Ethan Nicholascb0f4092019-04-19 11:26:50 -04002864 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07002865}
2866
Brian Osman8e2ef022020-09-30 13:26:43 -04002867void IRGenerator::cloneBuiltinVariables() {
2868 class BuiltinVariableRemapper : public ProgramWriter {
2869 public:
2870 BuiltinVariableRemapper(IRGenerator* generator) : fGenerator(generator) {}
2871
Brian Osman00a8b5b2020-10-02 09:06:04 -04002872 void cloneVariable(const String& name) {
2873 // If this is the *first* time we've seen this builtin, findAndInclude will return
2874 // the corresponding ProgramElement.
Brian Osmanafa18ee2020-10-07 17:47:45 -04002875 if (const ProgramElement* sharedDecl = fGenerator->fIntrinsics->findAndInclude(name)) {
2876 SkASSERT(sharedDecl->is<GlobalVarDeclaration>() ||
2877 sharedDecl->is<InterfaceBlock>());
Brian Osman00a8b5b2020-10-02 09:06:04 -04002878
Brian Osmanafa18ee2020-10-07 17:47:45 -04002879 // Clone the ProgramElement that declares this variable
2880 std::unique_ptr<ProgramElement> clonedDecl = sharedDecl->clone();
2881 const Variable* sharedVar = nullptr;
2882 const Expression* initialValue = nullptr;
2883
2884 if (clonedDecl->is<GlobalVarDeclaration>()) {
2885 sharedVar = clonedDecl->as<GlobalVarDeclaration>().fDecl->fVar;
2886 initialValue = clonedDecl->as<GlobalVarDeclaration>().fDecl->fValue.get();
2887 } else {
2888 SkASSERT(clonedDecl->is<InterfaceBlock>());
2889 sharedVar = clonedDecl->as<InterfaceBlock>().fVariable;
2890 }
Brian Osman00a8b5b2020-10-02 09:06:04 -04002891
2892 // Now clone the Variable, and add the clone to the Program's symbol table.
Brian Osmanc0213602020-10-06 14:43:32 -04002893 // Any initial value expression was cloned as part of the GlobalVarDeclaration,
Brian Osman00a8b5b2020-10-02 09:06:04 -04002894 // so we're pointing at a Program-owned expression.
2895 const Variable* clonedVar =
2896 fGenerator->fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002897 sharedVar->fOffset, sharedVar->modifiersHandle(), sharedVar->name(),
2898 &sharedVar->type(), /*builtin=*/false, sharedVar->storage(),
Brian Osmanafa18ee2020-10-07 17:47:45 -04002899 initialValue));
Brian Osman00a8b5b2020-10-02 09:06:04 -04002900
Brian Osmanafa18ee2020-10-07 17:47:45 -04002901 // Go back and update the declaring element to point at the cloned Variable.
2902 if (clonedDecl->is<GlobalVarDeclaration>()) {
2903 clonedDecl->as<GlobalVarDeclaration>().fDecl->fVar = clonedVar;
2904 } else {
2905 clonedDecl->as<InterfaceBlock>().fVariable = clonedVar;
2906 }
Brian Osman00a8b5b2020-10-02 09:06:04 -04002907
2908 // Remember this new re-mapping...
2909 fRemap.insert({sharedVar, clonedVar});
2910
Brian Osmanafa18ee2020-10-07 17:47:45 -04002911 // Add the declaring element to this Program
2912 fNewElements.push_back(std::move(clonedDecl));
Brian Osman00a8b5b2020-10-02 09:06:04 -04002913 }
2914 }
2915
Brian Osman8e2ef022020-09-30 13:26:43 -04002916 bool visitExpression(Expression& e) override {
2917 // Look for references to builtin variables.
Ethan Nicholas78686922020-10-08 06:46:27 -04002918 if (e.is<VariableReference>() && e.as<VariableReference>().variable()->isBuiltin()) {
2919 const Variable* sharedVar = e.as<VariableReference>().variable();
Brian Osman8e2ef022020-09-30 13:26:43 -04002920
Ethan Nicholase2c49992020-10-05 11:49:11 -04002921 this->cloneVariable(sharedVar->name());
Brian Osman8e2ef022020-09-30 13:26:43 -04002922
2923 // TODO: SkASSERT(found), once all pre-includes are converted?
2924 auto found = fRemap.find(sharedVar);
2925 if (found != fRemap.end()) {
2926 e.as<VariableReference>().setVariable(found->second);
2927 }
2928 }
2929
2930 return INHERITED::visitExpression(e);
2931 }
2932
2933 IRGenerator* fGenerator;
2934 std::unordered_map<const Variable*, const Variable*> fRemap;
2935 std::vector<std::unique_ptr<ProgramElement>> fNewElements;
2936
2937 using INHERITED = ProgramWriter;
2938 using INHERITED::visitProgramElement;
2939 };
2940
Brian Osman00a8b5b2020-10-02 09:06:04 -04002941 BuiltinVariableRemapper remapper(this);
2942 for (auto& e : *fProgramElements) {
2943 remapper.visitProgramElement(*e);
Brian Osman8e2ef022020-09-30 13:26:43 -04002944 }
Brian Osman00a8b5b2020-10-02 09:06:04 -04002945
2946 // Vulkan requires certain builtin variables be present, even if they're unused. At one time,
2947 // validation errors would result if they were missing. Now, it's just (Adreno) driver bugs
2948 // that drop or corrupt draws if they're missing.
2949 switch (fKind) {
2950 case Program::kFragment_Kind:
2951 remapper.cloneVariable("sk_Clockwise");
2952 break;
2953 default:
2954 break;
2955 }
2956
2957 fProgramElements->insert(fProgramElements->begin(),
Brian Osmanafa18ee2020-10-07 17:47:45 -04002958 std::make_move_iterator(remapper.fNewElements.begin()),
2959 std::make_move_iterator(remapper.fNewElements.end()));
Brian Osman8e2ef022020-09-30 13:26:43 -04002960}
2961
Robert Phillipsfe8da172018-01-24 14:52:02 +00002962void IRGenerator::convertProgram(Program::Kind kind,
2963 const char* text,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002964 size_t length,
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002965 std::vector<std::unique_ptr<ProgramElement>>* out) {
Robert Phillipsfe8da172018-01-24 14:52:02 +00002966 fKind = kind;
Ethan Nicholasaae47c82017-11-10 15:34:03 -05002967 fProgramElements = out;
Ethan Nicholasc18bb512020-07-28 14:46:53 -04002968 Parser parser(text, length, *fSymbolTable, fErrors);
Ethan Nicholasfc994162019-06-06 10:04:27 -04002969 fFile = parser.file();
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002970 if (fErrors.errorCount()) {
2971 return;
2972 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002973 SkASSERT(fFile);
2974 for (const auto& decl : fFile->root()) {
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002975 switch (decl.fKind) {
Ethan Nicholasfc994162019-06-06 10:04:27 -04002976 case ASTNode::Kind::kVarDeclarations: {
Brian Osmanc0213602020-10-06 14:43:32 -04002977 std::vector<std::unique_ptr<Statement>> decls =
2978 this->convertVarDeclarations(decl, Variable::kGlobal_Storage);
2979 for (auto& varDecl : decls) {
2980 fProgramElements->push_back(std::make_unique<GlobalVarDeclaration>(
2981 decl.fOffset, std::move(varDecl)));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002982 }
2983 break;
2984 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002985 case ASTNode::Kind::kEnum: {
2986 this->convertEnum(decl);
Ethan Nicholasaae47c82017-11-10 15:34:03 -05002987 break;
2988 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002989 case ASTNode::Kind::kFunction: {
2990 this->convertFunction(decl);
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002991 break;
2992 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04002993 case ASTNode::Kind::kModifiers: {
2994 std::unique_ptr<ModifiersDeclaration> f = this->convertModifiersDeclaration(decl);
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002995 if (f) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05002996 fProgramElements->push_back(std::move(f));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04002997 }
2998 break;
2999 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04003000 case ASTNode::Kind::kInterfaceBlock: {
3001 std::unique_ptr<InterfaceBlock> i = this->convertInterfaceBlock(decl);
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003002 if (i) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05003003 fProgramElements->push_back(std::move(i));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003004 }
3005 break;
3006 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04003007 case ASTNode::Kind::kExtension: {
3008 std::unique_ptr<Extension> e = this->convertExtension(decl.fOffset,
3009 decl.getString());
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003010 if (e) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05003011 fProgramElements->push_back(std::move(e));
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003012 }
3013 break;
3014 }
Ethan Nicholasfc994162019-06-06 10:04:27 -04003015 case ASTNode::Kind::kSection: {
3016 std::unique_ptr<Section> s = this->convertSection(decl);
Ethan Nicholas762466e2017-06-29 10:03:38 -04003017 if (s) {
Ethan Nicholasaae47c82017-11-10 15:34:03 -05003018 fProgramElements->push_back(std::move(s));
Ethan Nicholas762466e2017-06-29 10:03:38 -04003019 }
3020 break;
3021 }
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003022 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05003023#ifdef SK_DEBUG
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003024 ABORT("unsupported declaration: %s\n", decl.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05003025#endif
3026 break;
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003027 }
3028 }
Brian Osmanc95d3a12020-09-09 10:56:27 -04003029
Brian Osman8e2ef022020-09-30 13:26:43 -04003030 // Any variables defined in the pre-includes need to be cloned into the Program
Brian Osman00a8b5b2020-10-02 09:06:04 -04003031 if (!fIsBuiltinCode && fIntrinsics) {
3032 this->cloneBuiltinVariables();
3033 }
Brian Osman8e2ef022020-09-30 13:26:43 -04003034
Brian Osmanc95d3a12020-09-09 10:56:27 -04003035 // Do a final pass looking for dangling FunctionReference or TypeReference expressions
3036 class FindIllegalExpressions : public ProgramVisitor {
3037 public:
3038 FindIllegalExpressions(IRGenerator* generator) : fGenerator(generator) {}
3039
3040 bool visitExpression(const Expression& e) override {
3041 fGenerator->checkValid(e);
3042 return INHERITED::visitExpression(e);
3043 }
3044
3045 IRGenerator* fGenerator;
3046 using INHERITED = ProgramVisitor;
3047 using INHERITED::visitProgramElement;
3048 };
3049 for (const auto& pe : *fProgramElements) {
3050 FindIllegalExpressions{this}.visitProgramElement(*pe);
3051 }
Ethan Nicholas7da6dfa2017-06-21 11:25:18 -04003052}
3053
3054
John Stilesa6841be2020-08-06 14:11:56 -04003055} // namespace SkSL