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