LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/sksl - SkSLIRGenerator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1053 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkSLIRGenerator.h"
       9             : 
      10             : #include "limits.h"
      11             : #include <unordered_set>
      12             : 
      13             : #include "SkSLCompiler.h"
      14             : #include "ast/SkSLASTBoolLiteral.h"
      15             : #include "ast/SkSLASTFieldSuffix.h"
      16             : #include "ast/SkSLASTFloatLiteral.h"
      17             : #include "ast/SkSLASTIndexSuffix.h"
      18             : #include "ast/SkSLASTIntLiteral.h"
      19             : #include "ir/SkSLBinaryExpression.h"
      20             : #include "ir/SkSLBoolLiteral.h"
      21             : #include "ir/SkSLBreakStatement.h"
      22             : #include "ir/SkSLConstructor.h"
      23             : #include "ir/SkSLContinueStatement.h"
      24             : #include "ir/SkSLDiscardStatement.h"
      25             : #include "ir/SkSLDoStatement.h"
      26             : #include "ir/SkSLExpressionStatement.h"
      27             : #include "ir/SkSLField.h"
      28             : #include "ir/SkSLFieldAccess.h"
      29             : #include "ir/SkSLFloatLiteral.h"
      30             : #include "ir/SkSLForStatement.h"
      31             : #include "ir/SkSLFunctionCall.h"
      32             : #include "ir/SkSLFunctionDeclaration.h"
      33             : #include "ir/SkSLFunctionDefinition.h"
      34             : #include "ir/SkSLFunctionReference.h"
      35             : #include "ir/SkSLIfStatement.h"
      36             : #include "ir/SkSLIndexExpression.h"
      37             : #include "ir/SkSLInterfaceBlock.h"
      38             : #include "ir/SkSLIntLiteral.h"
      39             : #include "ir/SkSLLayout.h"
      40             : #include "ir/SkSLPostfixExpression.h"
      41             : #include "ir/SkSLPrefixExpression.h"
      42             : #include "ir/SkSLReturnStatement.h"
      43             : #include "ir/SkSLSwitchCase.h"
      44             : #include "ir/SkSLSwitchStatement.h"
      45             : #include "ir/SkSLSwizzle.h"
      46             : #include "ir/SkSLTernaryExpression.h"
      47             : #include "ir/SkSLUnresolvedFunction.h"
      48             : #include "ir/SkSLVariable.h"
      49             : #include "ir/SkSLVarDeclarations.h"
      50             : #include "ir/SkSLVarDeclarationsStatement.h"
      51             : #include "ir/SkSLVariableReference.h"
      52             : #include "ir/SkSLWhileStatement.h"
      53             : 
      54             : namespace SkSL {
      55             : 
      56             : class AutoSymbolTable {
      57             : public:
      58           0 :     AutoSymbolTable(IRGenerator* ir)
      59           0 :     : fIR(ir)
      60           0 :     , fPrevious(fIR->fSymbolTable) {
      61           0 :         fIR->pushSymbolTable();
      62           0 :     }
      63             : 
      64           0 :     ~AutoSymbolTable() {
      65           0 :         fIR->popSymbolTable();
      66           0 :         ASSERT(fPrevious == fIR->fSymbolTable);
      67           0 :     }
      68             : 
      69             :     IRGenerator* fIR;
      70             :     std::shared_ptr<SymbolTable> fPrevious;
      71             : };
      72             : 
      73             : class AutoLoopLevel {
      74             : public:
      75           0 :     AutoLoopLevel(IRGenerator* ir)
      76           0 :     : fIR(ir) {
      77           0 :         fIR->fLoopLevel++;
      78           0 :     }
      79             : 
      80           0 :     ~AutoLoopLevel() {
      81           0 :         fIR->fLoopLevel--;
      82           0 :     }
      83             : 
      84             :     IRGenerator* fIR;
      85             : };
      86             : 
      87             : class AutoSwitchLevel {
      88             : public:
      89           0 :     AutoSwitchLevel(IRGenerator* ir)
      90           0 :     : fIR(ir) {
      91           0 :         fIR->fSwitchLevel++;
      92           0 :     }
      93             : 
      94           0 :     ~AutoSwitchLevel() {
      95           0 :         fIR->fSwitchLevel--;
      96           0 :     }
      97             : 
      98             :     IRGenerator* fIR;
      99             : };
     100             : 
     101           0 : IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> symbolTable,
     102           0 :                          ErrorReporter& errorReporter)
     103             : : fContext(*context)
     104             : , fCurrentFunction(nullptr)
     105           0 : , fSymbolTable(std::move(symbolTable))
     106             : , fLoopLevel(0)
     107             : , fSwitchLevel(0)
     108           0 : , fErrors(errorReporter) {}
     109             : 
     110           0 : void IRGenerator::pushSymbolTable() {
     111           0 :     fSymbolTable.reset(new SymbolTable(std::move(fSymbolTable), &fErrors));
     112           0 : }
     113             : 
     114           0 : void IRGenerator::popSymbolTable() {
     115           0 :     fSymbolTable = fSymbolTable->fParent;
     116           0 : }
     117             : 
     118           0 : static void fill_caps(const SKSL_CAPS_CLASS& caps, std::unordered_map<String, CapValue>* capsMap) {
     119             : #define CAP(name) capsMap->insert(std::make_pair(String(#name), CapValue(caps.name())));
     120           0 :     CAP(fbFetchSupport);
     121           0 :     CAP(fbFetchNeedsCustomOutput);
     122           0 :     CAP(bindlessTextureSupport);
     123           0 :     CAP(dropsTileOnZeroDivide);
     124           0 :     CAP(flatInterpolationSupport);
     125           0 :     CAP(noperspectiveInterpolationSupport);
     126           0 :     CAP(multisampleInterpolationSupport);
     127           0 :     CAP(sampleVariablesSupport);
     128           0 :     CAP(sampleMaskOverrideCoverageSupport);
     129           0 :     CAP(externalTextureSupport);
     130           0 :     CAP(texelFetchSupport);
     131           0 :     CAP(imageLoadStoreSupport);
     132           0 :     CAP(mustEnableAdvBlendEqs);
     133           0 :     CAP(mustEnableSpecificAdvBlendEqs);
     134           0 :     CAP(mustDeclareFragmentShaderOutput);
     135           0 :     CAP(canUseAnyFunctionInShader);
     136             : #undef CAP
     137           0 : }
     138             : 
     139           0 : void IRGenerator::start(const Program::Settings* settings) {
     140           0 :     fSettings = settings;
     141           0 :     fCapsMap.clear();
     142           0 :     if (settings->fCaps) {
     143           0 :         fill_caps(*settings->fCaps, &fCapsMap);
     144             :     }
     145           0 :     this->pushSymbolTable();
     146           0 :     fInputs.reset();
     147           0 : }
     148             : 
     149           0 : void IRGenerator::finish() {
     150           0 :     this->popSymbolTable();
     151           0 :     fSettings = nullptr;
     152           0 : }
     153             : 
     154           0 : std::unique_ptr<Extension> IRGenerator::convertExtension(const ASTExtension& extension) {
     155           0 :     return std::unique_ptr<Extension>(new Extension(extension.fPosition, extension.fName));
     156             : }
     157             : 
     158           0 : std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTStatement& statement) {
     159           0 :     switch (statement.fKind) {
     160             :         case ASTStatement::kBlock_Kind:
     161           0 :             return this->convertBlock((ASTBlock&) statement);
     162             :         case ASTStatement::kVarDeclaration_Kind:
     163           0 :             return this->convertVarDeclarationStatement((ASTVarDeclarationStatement&) statement);
     164             :         case ASTStatement::kExpression_Kind:
     165           0 :             return this->convertExpressionStatement((ASTExpressionStatement&) statement);
     166             :         case ASTStatement::kIf_Kind:
     167           0 :             return this->convertIf((ASTIfStatement&) statement);
     168             :         case ASTStatement::kFor_Kind:
     169           0 :             return this->convertFor((ASTForStatement&) statement);
     170             :         case ASTStatement::kWhile_Kind:
     171           0 :             return this->convertWhile((ASTWhileStatement&) statement);
     172             :         case ASTStatement::kDo_Kind:
     173           0 :             return this->convertDo((ASTDoStatement&) statement);
     174             :         case ASTStatement::kSwitch_Kind:
     175           0 :             return this->convertSwitch((ASTSwitchStatement&) statement);
     176             :         case ASTStatement::kReturn_Kind:
     177           0 :             return this->convertReturn((ASTReturnStatement&) statement);
     178             :         case ASTStatement::kBreak_Kind:
     179           0 :             return this->convertBreak((ASTBreakStatement&) statement);
     180             :         case ASTStatement::kContinue_Kind:
     181           0 :             return this->convertContinue((ASTContinueStatement&) statement);
     182             :         case ASTStatement::kDiscard_Kind:
     183           0 :             return this->convertDiscard((ASTDiscardStatement&) statement);
     184             :         default:
     185           0 :             ABORT("unsupported statement type: %d\n", statement.fKind);
     186             :     }
     187             : }
     188             : 
     189           0 : std::unique_ptr<Block> IRGenerator::convertBlock(const ASTBlock& block) {
     190           0 :     AutoSymbolTable table(this);
     191           0 :     std::vector<std::unique_ptr<Statement>> statements;
     192           0 :     for (size_t i = 0; i < block.fStatements.size(); i++) {
     193           0 :         std::unique_ptr<Statement> statement = this->convertStatement(*block.fStatements[i]);
     194           0 :         if (!statement) {
     195           0 :             return nullptr;
     196             :         }
     197           0 :         statements.push_back(std::move(statement));
     198             :     }
     199           0 :     return std::unique_ptr<Block>(new Block(block.fPosition, std::move(statements), fSymbolTable));
     200             : }
     201             : 
     202           0 : std::unique_ptr<Statement> IRGenerator::convertVarDeclarationStatement(
     203             :                                                               const ASTVarDeclarationStatement& s) {
     204           0 :     auto decl = this->convertVarDeclarations(*s.fDeclarations, Variable::kLocal_Storage);
     205           0 :     if (!decl) {
     206           0 :         return nullptr;
     207             :     }
     208           0 :     return std::unique_ptr<Statement>(new VarDeclarationsStatement(std::move(decl)));
     209             : }
     210             : 
     211           0 : std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTVarDeclarations& decl,
     212             :                                                                      Variable::Storage storage) {
     213           0 :     std::vector<VarDeclaration> variables;
     214           0 :     const Type* baseType = this->convertType(*decl.fType);
     215           0 :     if (!baseType) {
     216           0 :         return nullptr;
     217             :     }
     218           0 :     for (const auto& varDecl : decl.fVars) {
     219           0 :         const Type* type = baseType;
     220           0 :         std::vector<std::unique_ptr<Expression>> sizes;
     221           0 :         for (const auto& rawSize : varDecl.fSizes) {
     222           0 :             if (rawSize) {
     223           0 :                 auto size = this->coerce(this->convertExpression(*rawSize), *fContext.fInt_Type);
     224           0 :                 if (!size) {
     225           0 :                     return nullptr;
     226             :                 }
     227           0 :                 String name = type->fName;
     228             :                 int64_t count;
     229           0 :                 if (size->fKind == Expression::kIntLiteral_Kind) {
     230           0 :                     count = ((IntLiteral&) *size).fValue;
     231           0 :                     if (count <= 0) {
     232           0 :                         fErrors.error(size->fPosition, "array size must be positive");
     233             :                     }
     234           0 :                     name += "[" + to_string(count) + "]";
     235             :                 } else {
     236           0 :                     count = -1;
     237           0 :                     name += "[]";
     238             :                 }
     239           0 :                 type = new Type(name, Type::kArray_Kind, *type, (int) count);
     240           0 :                 fSymbolTable->takeOwnership((Type*) type);
     241           0 :                 sizes.push_back(std::move(size));
     242             :             } else {
     243           0 :                 type = new Type(type->fName + "[]", Type::kArray_Kind, *type, -1);
     244           0 :                 fSymbolTable->takeOwnership((Type*) type);
     245           0 :                 sizes.push_back(nullptr);
     246             :             }
     247             :         }
     248           0 :         auto var = std::unique_ptr<Variable>(new Variable(decl.fPosition, decl.fModifiers,
     249           0 :                                                           varDecl.fName, *type, storage));
     250           0 :         std::unique_ptr<Expression> value;
     251           0 :         if (varDecl.fValue) {
     252           0 :             value = this->convertExpression(*varDecl.fValue);
     253           0 :             if (!value) {
     254           0 :                 return nullptr;
     255             :             }
     256           0 :             value = this->coerce(std::move(value), *type);
     257             :         }
     258           0 :         if (storage == Variable::kGlobal_Storage && varDecl.fName == String("sk_FragColor") &&
     259           0 :             (*fSymbolTable)[varDecl.fName]) {
     260             :             // already defined, ignore
     261           0 :         } else if (storage == Variable::kGlobal_Storage && (*fSymbolTable)[varDecl.fName] &&
     262           0 :                    (*fSymbolTable)[varDecl.fName]->fKind == Symbol::kVariable_Kind &&
     263           0 :                    ((Variable*) (*fSymbolTable)[varDecl.fName])->fModifiers.fLayout.fBuiltin >= 0) {
     264             :             // already defined, just update the modifiers
     265           0 :             Variable* old = (Variable*) (*fSymbolTable)[varDecl.fName];
     266           0 :             old->fModifiers = var->fModifiers;
     267             :         } else {
     268           0 :             variables.emplace_back(var.get(), std::move(sizes), std::move(value));
     269           0 :             fSymbolTable->add(varDecl.fName, std::move(var));
     270             :         }
     271             :     }
     272           0 :     return std::unique_ptr<VarDeclarations>(new VarDeclarations(decl.fPosition,
     273             :                                                                 baseType,
     274           0 :                                                                 std::move(variables)));
     275             : }
     276             : 
     277           0 : std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(
     278             :                                                                  const ASTModifiersDeclaration& m) {
     279           0 :     return std::unique_ptr<ModifiersDeclaration>(new ModifiersDeclaration(m.fModifiers));
     280             : }
     281             : 
     282           0 : std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
     283           0 :     std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*s.fTest),
     284           0 :                                                     *fContext.fBool_Type);
     285           0 :     if (!test) {
     286           0 :         return nullptr;
     287             :     }
     288           0 :     std::unique_ptr<Statement> ifTrue = this->convertStatement(*s.fIfTrue);
     289           0 :     if (!ifTrue) {
     290           0 :         return nullptr;
     291             :     }
     292           0 :     std::unique_ptr<Statement> ifFalse;
     293           0 :     if (s.fIfFalse) {
     294           0 :         ifFalse = this->convertStatement(*s.fIfFalse);
     295           0 :         if (!ifFalse) {
     296           0 :             return nullptr;
     297             :         }
     298             :     }
     299           0 :     if (test->fKind == Expression::kBoolLiteral_Kind) {
     300             :         // static boolean value, fold down to a single branch
     301           0 :         if (((BoolLiteral&) *test).fValue) {
     302           0 :             return ifTrue;
     303           0 :         } else if (s.fIfFalse) {
     304           0 :             return ifFalse;
     305             :         } else {
     306             :             // False & no else clause. Not an error, so don't return null!
     307           0 :             std::vector<std::unique_ptr<Statement>> empty;
     308           0 :             return std::unique_ptr<Statement>(new Block(s.fPosition, std::move(empty),
     309           0 :                                                         fSymbolTable));
     310             :         }
     311             :     }
     312           0 :     return std::unique_ptr<Statement>(new IfStatement(s.fPosition, std::move(test),
     313           0 :                                                       std::move(ifTrue), std::move(ifFalse)));
     314             : }
     315             : 
     316           0 : std::unique_ptr<Statement> IRGenerator::convertFor(const ASTForStatement& f) {
     317           0 :     AutoLoopLevel level(this);
     318           0 :     AutoSymbolTable table(this);
     319           0 :     std::unique_ptr<Statement> initializer;
     320           0 :     if (f.fInitializer) {
     321           0 :         initializer = this->convertStatement(*f.fInitializer);
     322           0 :         if (!initializer) {
     323           0 :             return nullptr;
     324             :         }
     325             :     }
     326           0 :     std::unique_ptr<Expression> test;
     327           0 :     if (f.fTest) {
     328           0 :         test = this->coerce(this->convertExpression(*f.fTest), *fContext.fBool_Type);
     329           0 :         if (!test) {
     330           0 :             return nullptr;
     331             :         }
     332             :     }
     333           0 :     std::unique_ptr<Expression> next;
     334           0 :     if (f.fNext) {
     335           0 :         next = this->convertExpression(*f.fNext);
     336           0 :         if (!next) {
     337           0 :             return nullptr;
     338             :         }
     339           0 :         this->checkValid(*next);
     340             :     }
     341           0 :     std::unique_ptr<Statement> statement = this->convertStatement(*f.fStatement);
     342           0 :     if (!statement) {
     343           0 :         return nullptr;
     344             :     }
     345           0 :     return std::unique_ptr<Statement>(new ForStatement(f.fPosition, std::move(initializer),
     346           0 :                                                        std::move(test), std::move(next),
     347           0 :                                                        std::move(statement), fSymbolTable));
     348             : }
     349             : 
     350           0 : std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTWhileStatement& w) {
     351           0 :     AutoLoopLevel level(this);
     352           0 :     std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*w.fTest),
     353           0 :                                                     *fContext.fBool_Type);
     354           0 :     if (!test) {
     355           0 :         return nullptr;
     356             :     }
     357           0 :     std::unique_ptr<Statement> statement = this->convertStatement(*w.fStatement);
     358           0 :     if (!statement) {
     359           0 :         return nullptr;
     360             :     }
     361           0 :     return std::unique_ptr<Statement>(new WhileStatement(w.fPosition, std::move(test),
     362           0 :                                                          std::move(statement)));
     363             : }
     364             : 
     365           0 : std::unique_ptr<Statement> IRGenerator::convertDo(const ASTDoStatement& d) {
     366           0 :     AutoLoopLevel level(this);
     367           0 :     std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*d.fTest),
     368           0 :                                                     *fContext.fBool_Type);
     369           0 :     if (!test) {
     370           0 :         return nullptr;
     371             :     }
     372           0 :     std::unique_ptr<Statement> statement = this->convertStatement(*d.fStatement);
     373           0 :     if (!statement) {
     374           0 :         return nullptr;
     375             :     }
     376           0 :     return std::unique_ptr<Statement>(new DoStatement(d.fPosition, std::move(statement),
     377           0 :                                                       std::move(test)));
     378             : }
     379             : 
     380           0 : std::unique_ptr<Statement> IRGenerator::convertSwitch(const ASTSwitchStatement& s) {
     381           0 :     AutoSwitchLevel level(this);
     382           0 :     std::unique_ptr<Expression> value = this->convertExpression(*s.fValue);
     383           0 :     if (!value) {
     384           0 :         return nullptr;
     385             :     }
     386           0 :     if (value->fType != *fContext.fUInt_Type) {
     387           0 :         value = this->coerce(std::move(value), *fContext.fInt_Type);
     388           0 :         if (!value) {
     389           0 :             return nullptr;
     390             :         }
     391             :     }
     392           0 :     AutoSymbolTable table(this);
     393           0 :     std::unordered_set<int> caseValues;
     394           0 :     std::vector<std::unique_ptr<SwitchCase>> cases;
     395           0 :     for (const auto& c : s.fCases) {
     396           0 :         std::unique_ptr<Expression> caseValue;
     397           0 :         if (c->fValue) {
     398           0 :             caseValue = this->convertExpression(*c->fValue);
     399           0 :             if (!caseValue) {
     400           0 :                 return nullptr;
     401             :             }
     402           0 :             if (caseValue->fType != *fContext.fUInt_Type) {
     403           0 :                 caseValue = this->coerce(std::move(caseValue), *fContext.fInt_Type);
     404           0 :                 if (!caseValue) {
     405           0 :                     return nullptr;
     406             :                 }
     407             :             }
     408           0 :             if (!caseValue->isConstant()) {
     409           0 :                 fErrors.error(caseValue->fPosition, "case value must be a constant");
     410           0 :                 return nullptr;
     411             :             }
     412           0 :             ASSERT(caseValue->fKind == Expression::kIntLiteral_Kind);
     413           0 :             int64_t v = ((IntLiteral&) *caseValue).fValue;
     414           0 :             if (caseValues.find(v) != caseValues.end()) {
     415           0 :                 fErrors.error(caseValue->fPosition, "duplicate case value");
     416             :             }
     417           0 :             caseValues.insert(v);
     418             :         }
     419           0 :         std::vector<std::unique_ptr<Statement>> statements;
     420           0 :         for (const auto& s : c->fStatements) {
     421           0 :             std::unique_ptr<Statement> converted = this->convertStatement(*s);
     422           0 :             if (!converted) {
     423           0 :                 return nullptr;
     424             :             }
     425           0 :             statements.push_back(std::move(converted));
     426             :         }
     427           0 :         cases.emplace_back(new SwitchCase(c->fPosition, std::move(caseValue),
     428           0 :                                           std::move(statements)));
     429             :     }
     430           0 :     return std::unique_ptr<Statement>(new SwitchStatement(s.fPosition, std::move(value),
     431           0 :                                                           std::move(cases)));
     432             : }
     433             : 
     434           0 : std::unique_ptr<Statement> IRGenerator::convertExpressionStatement(
     435             :                                                                   const ASTExpressionStatement& s) {
     436           0 :     std::unique_ptr<Expression> e = this->convertExpression(*s.fExpression);
     437           0 :     if (!e) {
     438           0 :         return nullptr;
     439             :     }
     440           0 :     this->checkValid(*e);
     441           0 :     return std::unique_ptr<Statement>(new ExpressionStatement(std::move(e)));
     442             : }
     443             : 
     444           0 : std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTReturnStatement& r) {
     445           0 :     ASSERT(fCurrentFunction);
     446           0 :     if (r.fExpression) {
     447           0 :         std::unique_ptr<Expression> result = this->convertExpression(*r.fExpression);
     448           0 :         if (!result) {
     449           0 :             return nullptr;
     450             :         }
     451           0 :         if (fCurrentFunction->fReturnType == *fContext.fVoid_Type) {
     452           0 :             fErrors.error(result->fPosition, "may not return a value from a void function");
     453             :         } else {
     454           0 :             result = this->coerce(std::move(result), fCurrentFunction->fReturnType);
     455           0 :             if (!result) {
     456           0 :                 return nullptr;
     457             :             }
     458             :         }
     459           0 :         return std::unique_ptr<Statement>(new ReturnStatement(std::move(result)));
     460             :     } else {
     461           0 :         if (fCurrentFunction->fReturnType != *fContext.fVoid_Type) {
     462           0 :             fErrors.error(r.fPosition, "expected function to return '" +
     463           0 :                                        fCurrentFunction->fReturnType.description() + "'");
     464             :         }
     465           0 :         return std::unique_ptr<Statement>(new ReturnStatement(r.fPosition));
     466             :     }
     467             : }
     468             : 
     469           0 : std::unique_ptr<Statement> IRGenerator::convertBreak(const ASTBreakStatement& b) {
     470           0 :     if (fLoopLevel > 0 || fSwitchLevel > 0) {
     471           0 :         return std::unique_ptr<Statement>(new BreakStatement(b.fPosition));
     472             :     } else {
     473           0 :         fErrors.error(b.fPosition, "break statement must be inside a loop or switch");
     474           0 :         return nullptr;
     475             :     }
     476             : }
     477             : 
     478           0 : std::unique_ptr<Statement> IRGenerator::convertContinue(const ASTContinueStatement& c) {
     479           0 :     if (fLoopLevel > 0) {
     480           0 :         return std::unique_ptr<Statement>(new ContinueStatement(c.fPosition));
     481             :     } else {
     482           0 :         fErrors.error(c.fPosition, "continue statement must be inside a loop");
     483           0 :         return nullptr;
     484             :     }
     485             : }
     486             : 
     487           0 : std::unique_ptr<Statement> IRGenerator::convertDiscard(const ASTDiscardStatement& d) {
     488           0 :     return std::unique_ptr<Statement>(new DiscardStatement(d.fPosition));
     489             : }
     490             : 
     491           0 : std::unique_ptr<FunctionDefinition> IRGenerator::convertFunction(const ASTFunction& f) {
     492           0 :     const Type* returnType = this->convertType(*f.fReturnType);
     493           0 :     if (!returnType) {
     494           0 :         return nullptr;
     495             :     }
     496           0 :     std::vector<const Variable*> parameters;
     497           0 :     for (const auto& param : f.fParameters) {
     498           0 :         const Type* type = this->convertType(*param->fType);
     499           0 :         if (!type) {
     500           0 :             return nullptr;
     501             :         }
     502           0 :         for (int j = (int) param->fSizes.size() - 1; j >= 0; j--) {
     503           0 :             int size = param->fSizes[j];
     504           0 :             String name = type->name() + "[" + to_string(size) + "]";
     505           0 :             Type* newType = new Type(std::move(name), Type::kArray_Kind, *type, size);
     506           0 :             fSymbolTable->takeOwnership(newType);
     507           0 :             type = newType;
     508             :         }
     509           0 :         String name = param->fName;
     510           0 :         Position pos = param->fPosition;
     511           0 :         Variable* var = new Variable(pos, param->fModifiers, std::move(name), *type,
     512           0 :                                      Variable::kParameter_Storage);
     513           0 :         fSymbolTable->takeOwnership(var);
     514           0 :         parameters.push_back(var);
     515             :     }
     516             : 
     517             :     // find existing declaration
     518           0 :     const FunctionDeclaration* decl = nullptr;
     519           0 :     auto entry = (*fSymbolTable)[f.fName];
     520           0 :     if (entry) {
     521           0 :         std::vector<const FunctionDeclaration*> functions;
     522           0 :         switch (entry->fKind) {
     523             :             case Symbol::kUnresolvedFunction_Kind:
     524           0 :                 functions = ((UnresolvedFunction*) entry)->fFunctions;
     525           0 :                 break;
     526             :             case Symbol::kFunctionDeclaration_Kind:
     527           0 :                 functions.push_back((FunctionDeclaration*) entry);
     528           0 :                 break;
     529             :             default:
     530           0 :                 fErrors.error(f.fPosition, "symbol '" + f.fName + "' was already defined");
     531           0 :                 return nullptr;
     532             :         }
     533           0 :         for (const auto& other : functions) {
     534           0 :             ASSERT(other->fName == f.fName);
     535           0 :             if (parameters.size() == other->fParameters.size()) {
     536           0 :                 bool match = true;
     537           0 :                 for (size_t i = 0; i < parameters.size(); i++) {
     538           0 :                     if (parameters[i]->fType != other->fParameters[i]->fType) {
     539           0 :                         match = false;
     540           0 :                         break;
     541             :                     }
     542             :                 }
     543           0 :                 if (match) {
     544           0 :                     if (*returnType != other->fReturnType) {
     545           0 :                         FunctionDeclaration newDecl(f.fPosition, f.fName, parameters, *returnType);
     546           0 :                         fErrors.error(f.fPosition, "functions '" + newDecl.description() +
     547           0 :                                                    "' and '" + other->description() +
     548           0 :                                                    "' differ only in return type");
     549           0 :                         return nullptr;
     550             :                     }
     551           0 :                     decl = other;
     552           0 :                     for (size_t i = 0; i < parameters.size(); i++) {
     553           0 :                         if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) {
     554           0 :                             fErrors.error(f.fPosition, "modifiers on parameter " +
     555           0 :                                                        to_string((uint64_t) i + 1) +
     556             :                                                        " differ between declaration and "
     557           0 :                                                        "definition");
     558           0 :                             return nullptr;
     559             :                         }
     560             :                     }
     561           0 :                     if (other->fDefined) {
     562           0 :                         fErrors.error(f.fPosition, "duplicate definition of " +
     563           0 :                                                    other->description());
     564             :                     }
     565           0 :                     break;
     566             :                 }
     567             :             }
     568             :         }
     569             :     }
     570           0 :     if (!decl) {
     571             :         // couldn't find an existing declaration
     572           0 :         auto newDecl = std::unique_ptr<FunctionDeclaration>(new FunctionDeclaration(f.fPosition,
     573             :                                                                                     f.fName,
     574             :                                                                                     parameters,
     575           0 :                                                                                     *returnType));
     576           0 :         decl = newDecl.get();
     577           0 :         fSymbolTable->add(decl->fName, std::move(newDecl));
     578             :     }
     579           0 :     if (f.fBody) {
     580           0 :         ASSERT(!fCurrentFunction);
     581           0 :         fCurrentFunction = decl;
     582           0 :         decl->fDefined = true;
     583           0 :         std::shared_ptr<SymbolTable> old = fSymbolTable;
     584           0 :         AutoSymbolTable table(this);
     585           0 :         for (size_t i = 0; i < parameters.size(); i++) {
     586           0 :             fSymbolTable->addWithoutOwnership(parameters[i]->fName, decl->fParameters[i]);
     587             :         }
     588           0 :         std::unique_ptr<Block> body = this->convertBlock(*f.fBody);
     589           0 :         fCurrentFunction = nullptr;
     590           0 :         if (!body) {
     591           0 :             return nullptr;
     592             :         }
     593           0 :         return std::unique_ptr<FunctionDefinition>(new FunctionDefinition(f.fPosition, *decl,
     594           0 :                                                                           std::move(body)));
     595             :     }
     596           0 :     return nullptr;
     597             : }
     598             : 
     599           0 : std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInterfaceBlock& intf) {
     600           0 :     std::shared_ptr<SymbolTable> old = fSymbolTable;
     601           0 :     AutoSymbolTable table(this);
     602           0 :     std::vector<Type::Field> fields;
     603           0 :     for (size_t i = 0; i < intf.fDeclarations.size(); i++) {
     604             :         std::unique_ptr<VarDeclarations> decl = this->convertVarDeclarations(
     605           0 :                                                                          *intf.fDeclarations[i],
     606           0 :                                                                          Variable::kGlobal_Storage);
     607           0 :         if (!decl) {
     608           0 :             return nullptr;
     609             :         }
     610           0 :         for (const auto& var : decl->fVars) {
     611           0 :             fields.push_back(Type::Field(var.fVar->fModifiers, var.fVar->fName,
     612           0 :                                          &var.fVar->fType));
     613           0 :             if (var.fValue) {
     614           0 :                 fErrors.error(decl->fPosition,
     615           0 :                               "initializers are not permitted on interface block fields");
     616             :             }
     617           0 :             if (var.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag |
     618             :                                                Modifiers::kOut_Flag |
     619             :                                                Modifiers::kUniform_Flag |
     620             :                                                Modifiers::kConst_Flag)) {
     621           0 :                 fErrors.error(decl->fPosition,
     622           0 :                               "interface block fields may not have storage qualifiers");
     623             :             }
     624             :         }
     625             :     }
     626           0 :     Type* type = new Type(intf.fPosition, intf.fTypeName, fields);
     627           0 :     old->takeOwnership(type);
     628           0 :     std::vector<std::unique_ptr<Expression>> sizes;
     629           0 :     for (const auto& size : intf.fSizes) {
     630           0 :         if (size) {
     631           0 :             std::unique_ptr<Expression> converted = this->convertExpression(*size);
     632           0 :             if (!converted) {
     633           0 :                 return nullptr;
     634             :             }
     635           0 :             String name = type->fName;
     636             :             int64_t count;
     637           0 :             if (converted->fKind == Expression::kIntLiteral_Kind) {
     638           0 :                 count = ((IntLiteral&) *converted).fValue;
     639           0 :                 if (count <= 0) {
     640           0 :                     fErrors.error(converted->fPosition, "array size must be positive");
     641             :                 }
     642           0 :                 name += "[" + to_string(count) + "]";
     643             :             } else {
     644           0 :                 count = -1;
     645           0 :                 name += "[]";
     646             :             }
     647           0 :             type = new Type(name, Type::kArray_Kind, *type, (int) count);
     648           0 :             fSymbolTable->takeOwnership((Type*) type);
     649           0 :             sizes.push_back(std::move(converted));
     650             :         } else {
     651           0 :             type = new Type(type->fName + "[]", Type::kArray_Kind, *type, -1);
     652           0 :             fSymbolTable->takeOwnership((Type*) type);
     653           0 :             sizes.push_back(nullptr);
     654             :         }
     655             :     }
     656           0 :     Variable* var = new Variable(intf.fPosition, intf.fModifiers,
     657           0 :                                  intf.fInstanceName.size() ? intf.fInstanceName : intf.fTypeName,
     658           0 :                                  *type, Variable::kGlobal_Storage);
     659           0 :     old->takeOwnership(var);
     660           0 :     if (intf.fInstanceName.size()) {
     661           0 :         old->addWithoutOwnership(intf.fInstanceName, var);
     662             :     } else {
     663           0 :         for (size_t i = 0; i < fields.size(); i++) {
     664           0 :             old->add(fields[i].fName, std::unique_ptr<Field>(new Field(intf.fPosition, *var,
     665           0 :                                                                        (int) i)));
     666             :         }
     667             :     }
     668           0 :     return std::unique_ptr<InterfaceBlock>(new InterfaceBlock(intf.fPosition,
     669             :                                                               var,
     670             :                                                               intf.fTypeName,
     671             :                                                               intf.fInstanceName,
     672           0 :                                                               std::move(sizes),
     673           0 :                                                               fSymbolTable));
     674             : }
     675             : 
     676           0 : const Type* IRGenerator::convertType(const ASTType& type) {
     677           0 :     const Symbol* result = (*fSymbolTable)[type.fName];
     678           0 :     if (result && result->fKind == Symbol::kType_Kind) {
     679           0 :         for (int size : type.fSizes) {
     680           0 :             String name = result->fName + "[";
     681           0 :             if (size != -1) {
     682           0 :                 name += to_string(size);
     683             :             }
     684           0 :             name += "]";
     685           0 :             result = new Type(name, Type::kArray_Kind, (const Type&) *result, size);
     686           0 :             fSymbolTable->takeOwnership((Type*) result);
     687             :         }
     688           0 :         return (const Type*) result;
     689             :     }
     690           0 :     fErrors.error(type.fPosition, "unknown type '" + type.fName + "'");
     691           0 :     return nullptr;
     692             : }
     693             : 
     694           0 : std::unique_ptr<Expression> IRGenerator::convertExpression(const ASTExpression& expr) {
     695           0 :     switch (expr.fKind) {
     696             :         case ASTExpression::kIdentifier_Kind:
     697           0 :             return this->convertIdentifier((ASTIdentifier&) expr);
     698             :         case ASTExpression::kBool_Kind:
     699           0 :             return std::unique_ptr<Expression>(new BoolLiteral(fContext, expr.fPosition,
     700           0 :                                                                ((ASTBoolLiteral&) expr).fValue));
     701             :         case ASTExpression::kInt_Kind:
     702           0 :             return std::unique_ptr<Expression>(new IntLiteral(fContext, expr.fPosition,
     703           0 :                                                               ((ASTIntLiteral&) expr).fValue));
     704             :         case ASTExpression::kFloat_Kind:
     705           0 :             return std::unique_ptr<Expression>(new FloatLiteral(fContext, expr.fPosition,
     706           0 :                                                                 ((ASTFloatLiteral&) expr).fValue));
     707             :         case ASTExpression::kBinary_Kind:
     708           0 :             return this->convertBinaryExpression((ASTBinaryExpression&) expr);
     709             :         case ASTExpression::kPrefix_Kind:
     710           0 :             return this->convertPrefixExpression((ASTPrefixExpression&) expr);
     711             :         case ASTExpression::kSuffix_Kind:
     712           0 :             return this->convertSuffixExpression((ASTSuffixExpression&) expr);
     713             :         case ASTExpression::kTernary_Kind:
     714           0 :             return this->convertTernaryExpression((ASTTernaryExpression&) expr);
     715             :         default:
     716           0 :             ABORT("unsupported expression type: %d\n", expr.fKind);
     717             :     }
     718             : }
     719             : 
     720           0 : std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier& identifier) {
     721           0 :     const Symbol* result = (*fSymbolTable)[identifier.fText];
     722           0 :     if (!result) {
     723           0 :         fErrors.error(identifier.fPosition, "unknown identifier '" + identifier.fText + "'");
     724           0 :         return nullptr;
     725             :     }
     726           0 :     switch (result->fKind) {
     727             :         case Symbol::kFunctionDeclaration_Kind: {
     728             :             std::vector<const FunctionDeclaration*> f = {
     729             :                 (const FunctionDeclaration*) result
     730           0 :             };
     731           0 :             return std::unique_ptr<FunctionReference>(new FunctionReference(fContext,
     732           0 :                                                                             identifier.fPosition,
     733           0 :                                                                             f));
     734             :         }
     735             :         case Symbol::kUnresolvedFunction_Kind: {
     736           0 :             const UnresolvedFunction* f = (const UnresolvedFunction*) result;
     737           0 :             return std::unique_ptr<FunctionReference>(new FunctionReference(fContext,
     738           0 :                                                                             identifier.fPosition,
     739           0 :                                                                             f->fFunctions));
     740             :         }
     741             :         case Symbol::kVariable_Kind: {
     742           0 :             const Variable* var = (const Variable*) result;
     743           0 :             if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
     744           0 :                 fInputs.fFlipY = true;
     745           0 :                 if (fSettings->fFlipY &&
     746           0 :                     (!fSettings->fCaps ||
     747           0 :                      !fSettings->fCaps->fragCoordConventionsExtensionString())) {
     748           0 :                     fInputs.fRTHeight = true;
     749             :                 }
     750             :             }
     751             :             // default to kRead_RefKind; this will be corrected later if the variable is written to
     752           0 :             return std::unique_ptr<VariableReference>(new VariableReference(
     753           0 :                                                                  identifier.fPosition,
     754             :                                                                  *var,
     755           0 :                                                                  VariableReference::kRead_RefKind));
     756             :         }
     757             :         case Symbol::kField_Kind: {
     758           0 :             const Field* field = (const Field*) result;
     759           0 :             VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner,
     760           0 :                                                             VariableReference::kRead_RefKind);
     761             :             return std::unique_ptr<Expression>(new FieldAccess(
     762           0 :                                                   std::unique_ptr<Expression>(base),
     763           0 :                                                   field->fFieldIndex,
     764           0 :                                                   FieldAccess::kAnonymousInterfaceBlock_OwnerKind));
     765             :         }
     766             :         case Symbol::kType_Kind: {
     767           0 :             const Type* t = (const Type*) result;
     768           0 :             return std::unique_ptr<TypeReference>(new TypeReference(fContext, identifier.fPosition,
     769           0 :                                                                     *t));
     770             :         }
     771             :         default:
     772           0 :             ABORT("unsupported symbol type %d\n", result->fKind);
     773             :     }
     774             : 
     775             : }
     776             : 
     777           0 : std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr,
     778             :                                                 const Type& type) {
     779           0 :     if (!expr) {
     780           0 :         return nullptr;
     781             :     }
     782           0 :     if (expr->fType == type) {
     783           0 :         return expr;
     784             :     }
     785           0 :     this->checkValid(*expr);
     786           0 :     if (expr->fType == *fContext.fInvalid_Type) {
     787           0 :         return nullptr;
     788             :     }
     789           0 :     if (!expr->fType.canCoerceTo(type)) {
     790           0 :         fErrors.error(expr->fPosition, "expected '" + type.description() + "', but found '" +
     791           0 :                                         expr->fType.description() + "'");
     792           0 :         return nullptr;
     793             :     }
     794           0 :     if (type.kind() == Type::kScalar_Kind) {
     795           0 :         std::vector<std::unique_ptr<Expression>> args;
     796           0 :         args.push_back(std::move(expr));
     797           0 :         ASTIdentifier id(Position(), type.description());
     798           0 :         std::unique_ptr<Expression> ctor = this->convertIdentifier(id);
     799           0 :         ASSERT(ctor);
     800           0 :         return this->call(Position(), std::move(ctor), std::move(args));
     801             :     }
     802           0 :     std::vector<std::unique_ptr<Expression>> args;
     803           0 :     args.push_back(std::move(expr));
     804           0 :     return std::unique_ptr<Expression>(new Constructor(Position(), type, std::move(args)));
     805             : }
     806             : 
     807           0 : static bool is_matrix_multiply(const Type& left, const Type& right) {
     808           0 :     if (left.kind() == Type::kMatrix_Kind) {
     809           0 :         return right.kind() == Type::kMatrix_Kind || right.kind() == Type::kVector_Kind;
     810             :     }
     811           0 :     return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind;
     812             : }
     813             : 
     814             : /**
     815             :  * Determines the operand and result types of a binary expression. Returns true if the expression is
     816             :  * legal, false otherwise. If false, the values of the out parameters are undefined.
     817             :  */
     818           0 : static bool determine_binary_type(const Context& context,
     819             :                                   Token::Kind op,
     820             :                                   const Type& left,
     821             :                                   const Type& right,
     822             :                                   const Type** outLeftType,
     823             :                                   const Type** outRightType,
     824             :                                   const Type** outResultType,
     825             :                                   bool tryFlipped) {
     826             :     bool isLogical;
     827             :     bool validMatrixOrVectorOp;
     828           0 :     switch (op) {
     829             :         case Token::EQ:
     830           0 :             *outLeftType = &left;
     831           0 :             *outRightType = &left;
     832           0 :             *outResultType = &left;
     833           0 :             return right.canCoerceTo(left);
     834             :         case Token::EQEQ: // fall through
     835             :         case Token::NEQ:
     836           0 :             isLogical = true;
     837           0 :             validMatrixOrVectorOp = true;
     838           0 :             break;
     839             :         case Token::LT:   // fall through
     840             :         case Token::GT:   // fall through
     841             :         case Token::LTEQ: // fall through
     842             :         case Token::GTEQ:
     843           0 :             isLogical = true;
     844           0 :             validMatrixOrVectorOp = false;
     845           0 :             break;
     846             :         case Token::LOGICALOR: // fall through
     847             :         case Token::LOGICALAND: // fall through
     848             :         case Token::LOGICALXOR: // fall through
     849             :         case Token::LOGICALOREQ: // fall through
     850             :         case Token::LOGICALANDEQ: // fall through
     851             :         case Token::LOGICALXOREQ:
     852           0 :             *outLeftType = context.fBool_Type.get();
     853           0 :             *outRightType = context.fBool_Type.get();
     854           0 :             *outResultType = context.fBool_Type.get();
     855           0 :             return left.canCoerceTo(*context.fBool_Type) &&
     856           0 :                    right.canCoerceTo(*context.fBool_Type);
     857             :         case Token::STAR: // fall through
     858             :         case Token::STAREQ:
     859           0 :             if (is_matrix_multiply(left, right)) {
     860             :                 // determine final component type
     861           0 :                 if (determine_binary_type(context, Token::STAR, left.componentType(),
     862             :                                           right.componentType(), outLeftType, outRightType,
     863             :                                           outResultType, false)) {
     864           0 :                     *outLeftType = &(*outResultType)->toCompound(context, left.columns(),
     865           0 :                                                                  left.rows());;
     866           0 :                     *outRightType = &(*outResultType)->toCompound(context, right.columns(),
     867           0 :                                                                   right.rows());;
     868           0 :                     int leftColumns = left.columns();
     869           0 :                     int leftRows = left.rows();
     870             :                     int rightColumns;
     871             :                     int rightRows;
     872           0 :                     if (right.kind() == Type::kVector_Kind) {
     873             :                         // matrix * vector treats the vector as a column vector, so we need to
     874             :                         // transpose it
     875           0 :                         rightColumns = right.rows();
     876           0 :                         rightRows = right.columns();
     877           0 :                         ASSERT(rightColumns == 1);
     878             :                     } else {
     879           0 :                         rightColumns = right.columns();
     880           0 :                         rightRows = right.rows();
     881             :                     }
     882           0 :                     if (rightColumns > 1) {
     883           0 :                         *outResultType = &(*outResultType)->toCompound(context, rightColumns,
     884           0 :                                                                        leftRows);
     885             :                     } else {
     886             :                         // result was a column vector, transpose it back to a row
     887           0 :                         *outResultType = &(*outResultType)->toCompound(context, leftRows,
     888           0 :                                                                        rightColumns);
     889             :                     }
     890           0 :                     return leftColumns == rightRows;
     891             :                 } else {
     892           0 :                     return false;
     893             :                 }
     894             :             }
     895           0 :             isLogical = false;
     896           0 :             validMatrixOrVectorOp = true;
     897           0 :             break;
     898             :         case Token::PLUS:    // fall through
     899             :         case Token::PLUSEQ:  // fall through
     900             :         case Token::MINUS:   // fall through
     901             :         case Token::MINUSEQ: // fall through
     902             :         case Token::SLASH:   // fall through
     903             :         case Token::SLASHEQ:
     904           0 :             isLogical = false;
     905           0 :             validMatrixOrVectorOp = true;
     906           0 :             break;
     907             :         default:
     908           0 :             isLogical = false;
     909           0 :             validMatrixOrVectorOp = false;
     910             :     }
     911           0 :     bool isVectorOrMatrix = left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind;
     912             :     // FIXME: incorrect for shift
     913           0 :     if (right.canCoerceTo(left) && (left.kind() == Type::kScalar_Kind ||
     914           0 :                                    (isVectorOrMatrix && validMatrixOrVectorOp))) {
     915           0 :         *outLeftType = &left;
     916           0 :         *outRightType = &left;
     917           0 :         if (isLogical) {
     918           0 :             *outResultType = context.fBool_Type.get();
     919             :         } else {
     920           0 :             *outResultType = &left;
     921             :         }
     922           0 :         return true;
     923             :     }
     924           0 :     if ((left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind) &&
     925           0 :         (right.kind() == Type::kScalar_Kind)) {
     926           0 :         if (determine_binary_type(context, op, left.componentType(), right, outLeftType,
     927             :                                   outRightType, outResultType, false)) {
     928           0 :             *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows());
     929           0 :             if (!isLogical) {
     930           0 :                 *outResultType = &(*outResultType)->toCompound(context, left.columns(),
     931           0 :                                                                left.rows());
     932             :             }
     933           0 :             return true;
     934             :         }
     935           0 :         return false;
     936             :     }
     937           0 :     if (tryFlipped) {
     938             :         return determine_binary_type(context, op, right, left, outRightType, outLeftType,
     939           0 :                                      outResultType, false);
     940             :     }
     941           0 :     return false;
     942             : }
     943             : 
     944           0 : std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
     945             :                                                       Token::Kind op,
     946             :                                                       const Expression& right) const {
     947             :     // Note that we expressly do not worry about precision and overflow here -- we use the maximum
     948             :     // precision to calculate the results and hope the result makes sense. The plan is to move the
     949             :     // Skia caps into SkSL, so we have access to all of them including the precisions of the various
     950             :     // types, which will let us be more intelligent about this.
     951           0 :     if (left.fKind == Expression::kBoolLiteral_Kind &&
     952           0 :         right.fKind == Expression::kBoolLiteral_Kind) {
     953           0 :         bool leftVal  = ((BoolLiteral&) left).fValue;
     954           0 :         bool rightVal = ((BoolLiteral&) right).fValue;
     955             :         bool result;
     956           0 :         switch (op) {
     957           0 :             case Token::LOGICALAND: result = leftVal && rightVal; break;
     958           0 :             case Token::LOGICALOR:  result = leftVal || rightVal; break;
     959           0 :             case Token::LOGICALXOR: result = leftVal ^  rightVal; break;
     960           0 :             default: return nullptr;
     961             :         }
     962           0 :         return std::unique_ptr<Expression>(new BoolLiteral(fContext, left.fPosition, result));
     963             :     }
     964             :     #define RESULT(t, op) std::unique_ptr<Expression>(new t ## Literal(fContext, left.fPosition, \
     965             :                                                                        leftVal op rightVal))
     966           0 :     if (left.fKind == Expression::kIntLiteral_Kind && right.fKind == Expression::kIntLiteral_Kind) {
     967           0 :         int64_t leftVal  = ((IntLiteral&) left).fValue;
     968           0 :         int64_t rightVal = ((IntLiteral&) right).fValue;
     969           0 :         switch (op) {
     970           0 :             case Token::PLUS:       return RESULT(Int,  +);
     971           0 :             case Token::MINUS:      return RESULT(Int,  -);
     972           0 :             case Token::STAR:       return RESULT(Int,  *);
     973             :             case Token::SLASH:
     974           0 :                 if (rightVal) {
     975           0 :                     return RESULT(Int, /);
     976             :                 }
     977           0 :                 fErrors.error(right.fPosition, "division by zero");
     978           0 :                 return nullptr;
     979             :             case Token::PERCENT:
     980           0 :                 if (rightVal) {
     981           0 :                     return RESULT(Int, %);
     982             :                 }
     983           0 :                 fErrors.error(right.fPosition, "division by zero");
     984           0 :                 return nullptr;
     985           0 :             case Token::BITWISEAND: return RESULT(Int,  &);
     986           0 :             case Token::BITWISEOR:  return RESULT(Int,  |);
     987           0 :             case Token::BITWISEXOR: return RESULT(Int,  ^);
     988           0 :             case Token::SHL:        return RESULT(Int,  <<);
     989           0 :             case Token::SHR:        return RESULT(Int,  >>);
     990           0 :             case Token::EQEQ:       return RESULT(Bool, ==);
     991           0 :             case Token::NEQ:        return RESULT(Bool, !=);
     992           0 :             case Token::GT:         return RESULT(Bool, >);
     993           0 :             case Token::GTEQ:       return RESULT(Bool, >=);
     994           0 :             case Token::LT:         return RESULT(Bool, <);
     995           0 :             case Token::LTEQ:       return RESULT(Bool, <=);
     996           0 :             default:                return nullptr;
     997             :         }
     998             :     }
     999           0 :     if (left.fKind == Expression::kFloatLiteral_Kind &&
    1000           0 :         right.fKind == Expression::kFloatLiteral_Kind) {
    1001           0 :         double leftVal  = ((FloatLiteral&) left).fValue;
    1002           0 :         double rightVal = ((FloatLiteral&) right).fValue;
    1003           0 :         switch (op) {
    1004           0 :             case Token::PLUS:       return RESULT(Float, +);
    1005           0 :             case Token::MINUS:      return RESULT(Float, -);
    1006           0 :             case Token::STAR:       return RESULT(Float, *);
    1007             :             case Token::SLASH:
    1008           0 :                 if (rightVal) {
    1009           0 :                     return RESULT(Float, /);
    1010             :                 }
    1011           0 :                 fErrors.error(right.fPosition, "division by zero");
    1012           0 :                 return nullptr;
    1013           0 :             case Token::EQEQ:       return RESULT(Bool,  ==);
    1014           0 :             case Token::NEQ:        return RESULT(Bool,  !=);
    1015           0 :             case Token::GT:         return RESULT(Bool,  >);
    1016           0 :             case Token::GTEQ:       return RESULT(Bool,  >=);
    1017           0 :             case Token::LT:         return RESULT(Bool,  <);
    1018           0 :             case Token::LTEQ:       return RESULT(Bool,  <=);
    1019           0 :             default:                return nullptr;
    1020             :         }
    1021             :     }
    1022             :     #undef RESULT
    1023           0 :     return nullptr;
    1024             : }
    1025             : 
    1026           0 : std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(
    1027             :                                                             const ASTBinaryExpression& expression) {
    1028           0 :     std::unique_ptr<Expression> left = this->convertExpression(*expression.fLeft);
    1029           0 :     if (!left) {
    1030           0 :         return nullptr;
    1031             :     }
    1032           0 :     std::unique_ptr<Expression> right = this->convertExpression(*expression.fRight);
    1033           0 :     if (!right) {
    1034           0 :         return nullptr;
    1035             :     }
    1036             :     const Type* leftType;
    1037             :     const Type* rightType;
    1038             :     const Type* resultType;
    1039           0 :     if (!determine_binary_type(fContext, expression.fOperator, left->fType, right->fType, &leftType,
    1040             :                                &rightType, &resultType,
    1041           0 :                                !Token::IsAssignment(expression.fOperator))) {
    1042           0 :         fErrors.error(expression.fPosition, "type mismatch: '" +
    1043           0 :                                             Token::OperatorName(expression.fOperator) +
    1044           0 :                                             "' cannot operate on '" + left->fType.fName +
    1045           0 :                                             "', '" + right->fType.fName + "'");
    1046           0 :         return nullptr;
    1047             :     }
    1048           0 :     if (Token::IsAssignment(expression.fOperator)) {
    1049           0 :         this->markWrittenTo(*left, expression.fOperator != Token::EQ);
    1050             :     }
    1051           0 :     left = this->coerce(std::move(left), *leftType);
    1052           0 :     right = this->coerce(std::move(right), *rightType);
    1053           0 :     if (!left || !right) {
    1054           0 :         return nullptr;
    1055             :     }
    1056           0 :     std::unique_ptr<Expression> result = this->constantFold(*left.get(), expression.fOperator,
    1057           0 :                                                             *right.get());
    1058           0 :     if (!result) {
    1059           0 :         result = std::unique_ptr<Expression>(new BinaryExpression(expression.fPosition,
    1060           0 :                                                                   std::move(left),
    1061           0 :                                                                   expression.fOperator,
    1062           0 :                                                                   std::move(right),
    1063           0 :                                                                   *resultType));
    1064             :     }
    1065           0 :     return result;
    1066             : }
    1067             : 
    1068           0 : std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(
    1069             :                                                            const ASTTernaryExpression& expression) {
    1070           0 :     std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*expression.fTest),
    1071           0 :                                                     *fContext.fBool_Type);
    1072           0 :     if (!test) {
    1073           0 :         return nullptr;
    1074             :     }
    1075           0 :     std::unique_ptr<Expression> ifTrue = this->convertExpression(*expression.fIfTrue);
    1076           0 :     if (!ifTrue) {
    1077           0 :         return nullptr;
    1078             :     }
    1079           0 :     std::unique_ptr<Expression> ifFalse = this->convertExpression(*expression.fIfFalse);
    1080           0 :     if (!ifFalse) {
    1081           0 :         return nullptr;
    1082             :     }
    1083             :     const Type* trueType;
    1084             :     const Type* falseType;
    1085             :     const Type* resultType;
    1086           0 :     if (!determine_binary_type(fContext, Token::EQEQ, ifTrue->fType, ifFalse->fType, &trueType,
    1087           0 :                                &falseType, &resultType, true) || trueType != falseType) {
    1088           0 :         fErrors.error(expression.fPosition, "ternary operator result mismatch: '" +
    1089           0 :                                             ifTrue->fType.fName + "', '" +
    1090           0 :                                             ifFalse->fType.fName + "'");
    1091           0 :         return nullptr;
    1092             :     }
    1093           0 :     ifTrue = this->coerce(std::move(ifTrue), *trueType);
    1094           0 :     if (!ifTrue) {
    1095           0 :         return nullptr;
    1096             :     }
    1097           0 :     ifFalse = this->coerce(std::move(ifFalse), *falseType);
    1098           0 :     if (!ifFalse) {
    1099           0 :         return nullptr;
    1100             :     }
    1101           0 :     if (test->fKind == Expression::kBoolLiteral_Kind) {
    1102             :         // static boolean test, just return one of the branches
    1103           0 :         if (((BoolLiteral&) *test).fValue) {
    1104           0 :             return ifTrue;
    1105             :         } else {
    1106           0 :             return ifFalse;
    1107             :         }
    1108             :     }
    1109           0 :     return std::unique_ptr<Expression>(new TernaryExpression(expression.fPosition,
    1110           0 :                                                              std::move(test),
    1111           0 :                                                              std::move(ifTrue),
    1112           0 :                                                              std::move(ifFalse)));
    1113             : }
    1114             : 
    1115           0 : std::unique_ptr<Expression> IRGenerator::call(Position position,
    1116             :                                               const FunctionDeclaration& function,
    1117             :                                               std::vector<std::unique_ptr<Expression>> arguments) {
    1118           0 :     if (function.fParameters.size() != arguments.size()) {
    1119           0 :         String msg = "call to '" + function.fName + "' expected " +
    1120           0 :                                  to_string((uint64_t) function.fParameters.size()) +
    1121           0 :                                  " argument";
    1122           0 :         if (function.fParameters.size() != 1) {
    1123           0 :             msg += "s";
    1124             :         }
    1125           0 :         msg += ", but found " + to_string((uint64_t) arguments.size());
    1126           0 :         fErrors.error(position, msg);
    1127           0 :         return nullptr;
    1128             :     }
    1129           0 :     std::vector<const Type*> types;
    1130             :     const Type* returnType;
    1131           0 :     if (!function.determineFinalTypes(arguments, &types, &returnType)) {
    1132           0 :         String msg = "no match for " + function.fName + "(";
    1133           0 :         String separator;
    1134           0 :         for (size_t i = 0; i < arguments.size(); i++) {
    1135           0 :             msg += separator;
    1136           0 :             separator = ", ";
    1137           0 :             msg += arguments[i]->fType.description();
    1138             :         }
    1139           0 :         msg += ")";
    1140           0 :         fErrors.error(position, msg);
    1141           0 :         return nullptr;
    1142             :     }
    1143           0 :     for (size_t i = 0; i < arguments.size(); i++) {
    1144           0 :         arguments[i] = this->coerce(std::move(arguments[i]), *types[i]);
    1145           0 :         if (!arguments[i]) {
    1146           0 :             return nullptr;
    1147             :         }
    1148           0 :         if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) {
    1149           0 :             this->markWrittenTo(*arguments[i], true);
    1150             :         }
    1151             :     }
    1152           0 :     return std::unique_ptr<FunctionCall>(new FunctionCall(position, *returnType, function,
    1153           0 :                                                           std::move(arguments)));
    1154             : }
    1155             : 
    1156             : /**
    1157             :  * Determines the cost of coercing the arguments of a function to the required types. Returns true
    1158             :  * if the cost could be computed, false if the call is not valid. Cost has no particular meaning
    1159             :  * other than "lower costs are preferred".
    1160             :  */
    1161           0 : bool IRGenerator::determineCallCost(const FunctionDeclaration& function,
    1162             :                                     const std::vector<std::unique_ptr<Expression>>& arguments,
    1163             :                                     int* outCost) {
    1164           0 :     if (function.fParameters.size() != arguments.size()) {
    1165           0 :         return false;
    1166             :     }
    1167           0 :     int total = 0;
    1168           0 :     std::vector<const Type*> types;
    1169             :     const Type* ignored;
    1170           0 :     if (!function.determineFinalTypes(arguments, &types, &ignored)) {
    1171           0 :         return false;
    1172             :     }
    1173           0 :     for (size_t i = 0; i < arguments.size(); i++) {
    1174             :         int cost;
    1175           0 :         if (arguments[i]->fType.determineCoercionCost(*types[i], &cost)) {
    1176           0 :             total += cost;
    1177             :         } else {
    1178           0 :             return false;
    1179             :         }
    1180             :     }
    1181           0 :     *outCost = total;
    1182           0 :     return true;
    1183             : }
    1184             : 
    1185           0 : std::unique_ptr<Expression> IRGenerator::call(Position position,
    1186             :                                               std::unique_ptr<Expression> functionValue,
    1187             :                                               std::vector<std::unique_ptr<Expression>> arguments) {
    1188           0 :     if (functionValue->fKind == Expression::kTypeReference_Kind) {
    1189             :         return this->convertConstructor(position,
    1190           0 :                                         ((TypeReference&) *functionValue).fValue,
    1191           0 :                                         std::move(arguments));
    1192             :     }
    1193           0 :     if (functionValue->fKind != Expression::kFunctionReference_Kind) {
    1194           0 :         fErrors.error(position, "'" + functionValue->description() + "' is not a function");
    1195           0 :         return nullptr;
    1196             :     }
    1197           0 :     FunctionReference* ref = (FunctionReference*) functionValue.get();
    1198           0 :     int bestCost = INT_MAX;
    1199           0 :     const FunctionDeclaration* best = nullptr;
    1200           0 :     if (ref->fFunctions.size() > 1) {
    1201           0 :         for (const auto& f : ref->fFunctions) {
    1202             :             int cost;
    1203           0 :             if (this->determineCallCost(*f, arguments, &cost) && cost < bestCost) {
    1204           0 :                 bestCost = cost;
    1205           0 :                 best = f;
    1206             :             }
    1207             :         }
    1208           0 :         if (best) {
    1209           0 :             return this->call(position, *best, std::move(arguments));
    1210             :         }
    1211           0 :         String msg = "no match for " + ref->fFunctions[0]->fName + "(";
    1212           0 :         String separator;
    1213           0 :         for (size_t i = 0; i < arguments.size(); i++) {
    1214           0 :             msg += separator;
    1215           0 :             separator = ", ";
    1216           0 :             msg += arguments[i]->fType.description();
    1217             :         }
    1218           0 :         msg += ")";
    1219           0 :         fErrors.error(position, msg);
    1220           0 :         return nullptr;
    1221             :     }
    1222           0 :     return this->call(position, *ref->fFunctions[0], std::move(arguments));
    1223             : }
    1224             : 
    1225           0 : std::unique_ptr<Expression> IRGenerator::convertNumberConstructor(
    1226             :                                                     Position position,
    1227             :                                                     const Type& type,
    1228             :                                                     std::vector<std::unique_ptr<Expression>> args) {
    1229           0 :     ASSERT(type.isNumber());
    1230           0 :     if (args.size() != 1) {
    1231           0 :         fErrors.error(position, "invalid arguments to '" + type.description() +
    1232           0 :                                 "' constructor, (expected exactly 1 argument, but found " +
    1233           0 :                                 to_string((uint64_t) args.size()) + ")");
    1234           0 :         return nullptr;
    1235             :     }
    1236           0 :     if (type == *fContext.fFloat_Type && args.size() == 1 &&
    1237           0 :         args[0]->fKind == Expression::kIntLiteral_Kind) {
    1238           0 :         int64_t value = ((IntLiteral&) *args[0]).fValue;
    1239           0 :         return std::unique_ptr<Expression>(new FloatLiteral(fContext, position, (double) value));
    1240             :     }
    1241           0 :     if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type ||
    1242           0 :         type == *fContext.fUInt_Type)) {
    1243             :         return std::unique_ptr<Expression>(new IntLiteral(fContext,
    1244             :                                                           position,
    1245           0 :                                                           ((IntLiteral&) *args[0]).fValue,
    1246           0 :                                                           &type));
    1247             :     }
    1248           0 :     if (args[0]->fType == *fContext.fBool_Type) {
    1249           0 :         std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, position, 0));
    1250           0 :         std::unique_ptr<IntLiteral> one(new IntLiteral(fContext, position, 1));
    1251             :         return std::unique_ptr<Expression>(
    1252           0 :                                      new TernaryExpression(position, std::move(args[0]),
    1253           0 :                                                            this->coerce(std::move(one), type),
    1254           0 :                                                            this->coerce(std::move(zero),
    1255           0 :                                                                         type)));
    1256             :     }
    1257           0 :     if (!args[0]->fType.isNumber()) {
    1258           0 :         fErrors.error(position, "invalid argument to '" + type.description() +
    1259           0 :                                 "' constructor (expected a number or bool, but found '" +
    1260           0 :                                 args[0]->fType.description() + "')");
    1261           0 :         return nullptr;
    1262             :     }
    1263           0 :     return std::unique_ptr<Expression>(new Constructor(position, std::move(type), std::move(args)));
    1264             : }
    1265             : 
    1266           0 : int component_count(const Type& type) {
    1267           0 :     switch (type.kind()) {
    1268             :         case Type::kVector_Kind:
    1269           0 :             return type.columns();
    1270             :         case Type::kMatrix_Kind:
    1271           0 :             return type.columns() * type.rows();
    1272             :         default:
    1273           0 :             return 1;
    1274             :     }
    1275             : }
    1276             : 
    1277           0 : std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor(
    1278             :                                                     Position position,
    1279             :                                                     const Type& type,
    1280             :                                                     std::vector<std::unique_ptr<Expression>> args) {
    1281           0 :     ASSERT(type.kind() == Type::kVector_Kind || type.kind() == Type::kMatrix_Kind);
    1282           0 :     if (type.kind() == Type::kMatrix_Kind && args.size() == 1 &&
    1283           0 :         args[0]->fType.kind() == Type::kMatrix_Kind) {
    1284             :         // matrix from matrix is always legal
    1285             :         return std::unique_ptr<Expression>(new Constructor(position, std::move(type),
    1286           0 :                                                            std::move(args)));
    1287             :     }
    1288           0 :     int actual = 0;
    1289           0 :     int expected = type.rows() * type.columns();
    1290           0 :     if (args.size() != 1 || expected != component_count(args[0]->fType) ||
    1291           0 :         type.componentType().isNumber() != args[0]->fType.componentType().isNumber()) {
    1292           0 :         for (size_t i = 0; i < args.size(); i++) {
    1293           0 :             if (args[i]->fType.kind() == Type::kVector_Kind) {
    1294           0 :                 if (type.componentType().isNumber() !=
    1295           0 :                     args[i]->fType.componentType().isNumber()) {
    1296           0 :                     fErrors.error(position, "'" + args[i]->fType.description() + "' is not a valid "
    1297           0 :                                             "parameter to '" + type.description() +
    1298           0 :                                             "' constructor");
    1299           0 :                     return nullptr;
    1300             :                 }
    1301           0 :                 actual += args[i]->fType.columns();
    1302           0 :             } else if (args[i]->fType.kind() == Type::kScalar_Kind) {
    1303           0 :                 actual += 1;
    1304           0 :                 if (type.kind() != Type::kScalar_Kind) {
    1305           0 :                     args[i] = this->coerce(std::move(args[i]), type.componentType());
    1306           0 :                     if (!args[i]) {
    1307           0 :                         return nullptr;
    1308             :                     }
    1309             :                 }
    1310             :             } else {
    1311           0 :                 fErrors.error(position, "'" + args[i]->fType.description() + "' is not a valid "
    1312           0 :                                         "parameter to '" + type.description() + "' constructor");
    1313           0 :                 return nullptr;
    1314             :             }
    1315             :         }
    1316           0 :         if (actual != 1 && actual != expected) {
    1317           0 :             fErrors.error(position, "invalid arguments to '" + type.description() +
    1318           0 :                                     "' constructor (expected " + to_string(expected) +
    1319           0 :                                     " scalars, but found " + to_string(actual) + ")");
    1320           0 :             return nullptr;
    1321             :         }
    1322             :     }
    1323           0 :     return std::unique_ptr<Expression>(new Constructor(position, std::move(type), std::move(args)));
    1324             : }
    1325             : 
    1326           0 : std::unique_ptr<Expression> IRGenerator::convertConstructor(
    1327             :                                                     Position position,
    1328             :                                                     const Type& type,
    1329             :                                                     std::vector<std::unique_ptr<Expression>> args) {
    1330             :     // FIXME: add support for structs
    1331           0 :     Type::Kind kind = type.kind();
    1332           0 :     if (args.size() == 1 && args[0]->fType == type) {
    1333             :         // argument is already the right type, just return it
    1334           0 :         return std::move(args[0]);
    1335             :     }
    1336           0 :     if (type.isNumber()) {
    1337           0 :         return this->convertNumberConstructor(position, type, std::move(args));
    1338           0 :     } else if (kind == Type::kArray_Kind) {
    1339           0 :         const Type& base = type.componentType();
    1340           0 :         for (size_t i = 0; i < args.size(); i++) {
    1341           0 :             args[i] = this->coerce(std::move(args[i]), base);
    1342           0 :             if (!args[i]) {
    1343           0 :                 return nullptr;
    1344             :             }
    1345             :         }
    1346             :         return std::unique_ptr<Expression>(new Constructor(position, std::move(type),
    1347           0 :                                                            std::move(args)));
    1348           0 :     } else if (kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) {
    1349           0 :         return this->convertCompoundConstructor(position, type, std::move(args));
    1350             :     } else {
    1351           0 :         fErrors.error(position, "cannot construct '" + type.description() + "'");
    1352           0 :         return nullptr;
    1353             :     }
    1354             : }
    1355             : 
    1356           0 : std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(
    1357             :                                                             const ASTPrefixExpression& expression) {
    1358           0 :     std::unique_ptr<Expression> base = this->convertExpression(*expression.fOperand);
    1359           0 :     if (!base) {
    1360           0 :         return nullptr;
    1361             :     }
    1362           0 :     switch (expression.fOperator) {
    1363             :         case Token::PLUS:
    1364           0 :             if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) {
    1365           0 :                 fErrors.error(expression.fPosition,
    1366           0 :                               "'+' cannot operate on '" + base->fType.description() + "'");
    1367           0 :                 return nullptr;
    1368             :             }
    1369           0 :             return base;
    1370             :         case Token::MINUS:
    1371           0 :             if (!base->fType.isNumber() && base->fType.kind() != Type::kVector_Kind) {
    1372           0 :                 fErrors.error(expression.fPosition,
    1373           0 :                               "'-' cannot operate on '" + base->fType.description() + "'");
    1374           0 :                 return nullptr;
    1375             :             }
    1376           0 :             if (base->fKind == Expression::kIntLiteral_Kind) {
    1377           0 :                 return std::unique_ptr<Expression>(new IntLiteral(fContext, base->fPosition,
    1378           0 :                                                                   -((IntLiteral&) *base).fValue));
    1379             :             }
    1380           0 :             if (base->fKind == Expression::kFloatLiteral_Kind) {
    1381           0 :                 double value = -((FloatLiteral&) *base).fValue;
    1382           0 :                 return std::unique_ptr<Expression>(new FloatLiteral(fContext, base->fPosition,
    1383           0 :                                                                     value));
    1384             :             }
    1385           0 :             return std::unique_ptr<Expression>(new PrefixExpression(Token::MINUS, std::move(base)));
    1386             :         case Token::PLUSPLUS:
    1387           0 :             if (!base->fType.isNumber()) {
    1388           0 :                 fErrors.error(expression.fPosition,
    1389           0 :                               "'" + Token::OperatorName(expression.fOperator) +
    1390           0 :                               "' cannot operate on '" + base->fType.description() + "'");
    1391           0 :                 return nullptr;
    1392             :             }
    1393           0 :             this->markWrittenTo(*base, true);
    1394           0 :             break;
    1395             :         case Token::MINUSMINUS:
    1396           0 :             if (!base->fType.isNumber()) {
    1397           0 :                 fErrors.error(expression.fPosition,
    1398           0 :                               "'" + Token::OperatorName(expression.fOperator) +
    1399           0 :                               "' cannot operate on '" + base->fType.description() + "'");
    1400           0 :                 return nullptr;
    1401             :             }
    1402           0 :             this->markWrittenTo(*base, true);
    1403           0 :             break;
    1404             :         case Token::LOGICALNOT:
    1405           0 :             if (base->fType != *fContext.fBool_Type) {
    1406           0 :                 fErrors.error(expression.fPosition,
    1407           0 :                               "'" + Token::OperatorName(expression.fOperator) +
    1408           0 :                               "' cannot operate on '" + base->fType.description() + "'");
    1409           0 :                 return nullptr;
    1410             :             }
    1411           0 :             if (base->fKind == Expression::kBoolLiteral_Kind) {
    1412           0 :                 return std::unique_ptr<Expression>(new BoolLiteral(fContext, base->fPosition,
    1413           0 :                                                                    !((BoolLiteral&) *base).fValue));
    1414             :             }
    1415           0 :             break;
    1416             :         case Token::BITWISENOT:
    1417           0 :             if (base->fType != *fContext.fInt_Type) {
    1418           0 :                 fErrors.error(expression.fPosition,
    1419           0 :                               "'" + Token::OperatorName(expression.fOperator) +
    1420           0 :                               "' cannot operate on '" + base->fType.description() + "'");
    1421           0 :                 return nullptr;
    1422             :             }
    1423           0 :             break;
    1424             :         default:
    1425           0 :             ABORT("unsupported prefix operator\n");
    1426             :     }
    1427           0 :     return std::unique_ptr<Expression>(new PrefixExpression(expression.fOperator,
    1428           0 :                                                             std::move(base)));
    1429             : }
    1430             : 
    1431           0 : std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression> base,
    1432             :                                                       const ASTExpression& index) {
    1433           0 :     if (base->fKind == Expression::kTypeReference_Kind) {
    1434           0 :         if (index.fKind == ASTExpression::kInt_Kind) {
    1435           0 :             const Type& oldType = ((TypeReference&) *base).fValue;
    1436           0 :             int64_t size = ((const ASTIntLiteral&) index).fValue;
    1437           0 :             Type* newType = new Type(oldType.name() + "[" + to_string(size) + "]",
    1438           0 :                                      Type::kArray_Kind, oldType, size);
    1439           0 :             fSymbolTable->takeOwnership(newType);
    1440           0 :             return std::unique_ptr<Expression>(new TypeReference(fContext, base->fPosition,
    1441           0 :                                                                  *newType));
    1442             : 
    1443             :         } else {
    1444           0 :             fErrors.error(base->fPosition, "array size must be a constant");
    1445           0 :             return nullptr;
    1446             :         }
    1447             :     }
    1448           0 :     if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind &&
    1449           0 :             base->fType.kind() != Type::kVector_Kind) {
    1450           0 :         fErrors.error(base->fPosition, "expected array, but found '" + base->fType.description() +
    1451           0 :                                        "'");
    1452           0 :         return nullptr;
    1453             :     }
    1454           0 :     std::unique_ptr<Expression> converted = this->convertExpression(index);
    1455           0 :     if (!converted) {
    1456           0 :         return nullptr;
    1457             :     }
    1458           0 :     if (converted->fType != *fContext.fUInt_Type) {
    1459           0 :         converted = this->coerce(std::move(converted), *fContext.fInt_Type);
    1460           0 :         if (!converted) {
    1461           0 :             return nullptr;
    1462             :         }
    1463             :     }
    1464           0 :     return std::unique_ptr<Expression>(new IndexExpression(fContext, std::move(base),
    1465           0 :                                                            std::move(converted)));
    1466             : }
    1467             : 
    1468           0 : std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base,
    1469             :                                                       const String& field) {
    1470           0 :     auto fields = base->fType.fields();
    1471           0 :     for (size_t i = 0; i < fields.size(); i++) {
    1472           0 :         if (fields[i].fName == field) {
    1473           0 :             return std::unique_ptr<Expression>(new FieldAccess(std::move(base), (int) i));
    1474             :         }
    1475             :     }
    1476           0 :     fErrors.error(base->fPosition, "type '" + base->fType.description() + "' does not have a "
    1477           0 :                                    "field named '" + field + "");
    1478           0 :     return nullptr;
    1479             : }
    1480             : 
    1481           0 : std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base,
    1482             :                                                         const String& fields) {
    1483           0 :     if (base->fType.kind() != Type::kVector_Kind) {
    1484           0 :         fErrors.error(base->fPosition, "cannot swizzle type '" + base->fType.description() + "'");
    1485           0 :         return nullptr;
    1486             :     }
    1487           0 :     std::vector<int> swizzleComponents;
    1488           0 :     for (size_t i = 0; i < fields.size(); i++) {
    1489           0 :         switch (fields[i]) {
    1490             :             case 'x': // fall through
    1491             :             case 'r': // fall through
    1492             :             case 's':
    1493           0 :                 swizzleComponents.push_back(0);
    1494           0 :                 break;
    1495             :             case 'y': // fall through
    1496             :             case 'g': // fall through
    1497             :             case 't':
    1498           0 :                 if (base->fType.columns() >= 2) {
    1499           0 :                     swizzleComponents.push_back(1);
    1500           0 :                     break;
    1501             :                 }
    1502             :                 // fall through
    1503             :             case 'z': // fall through
    1504             :             case 'b': // fall through
    1505             :             case 'p':
    1506           0 :                 if (base->fType.columns() >= 3) {
    1507           0 :                     swizzleComponents.push_back(2);
    1508           0 :                     break;
    1509             :                 }
    1510             :                 // fall through
    1511             :             case 'w': // fall through
    1512             :             case 'a': // fall through
    1513             :             case 'q':
    1514           0 :                 if (base->fType.columns() >= 4) {
    1515           0 :                     swizzleComponents.push_back(3);
    1516           0 :                     break;
    1517             :                 }
    1518             :                 // fall through
    1519             :             default:
    1520           0 :                 fErrors.error(base->fPosition, String::printf("invalid swizzle component '%c'",
    1521           0 :                                                               fields[i]));
    1522           0 :                 return nullptr;
    1523             :         }
    1524             :     }
    1525           0 :     ASSERT(swizzleComponents.size() > 0);
    1526           0 :     if (swizzleComponents.size() > 4) {
    1527           0 :         fErrors.error(base->fPosition, "too many components in swizzle mask '" + fields + "'");
    1528           0 :         return nullptr;
    1529             :     }
    1530           0 :     return std::unique_ptr<Expression>(new Swizzle(fContext, std::move(base), swizzleComponents));
    1531             : }
    1532             : 
    1533           0 : std::unique_ptr<Expression> IRGenerator::getCap(Position position, String name) {
    1534           0 :     auto found = fCapsMap.find(name);
    1535           0 :     if (found == fCapsMap.end()) {
    1536           0 :         fErrors.error(position, "unknown capability flag '" + name + "'");
    1537           0 :         return nullptr;
    1538             :     }
    1539           0 :     switch (found->second.fKind) {
    1540             :         case CapValue::kBool_Kind:
    1541             :             return std::unique_ptr<Expression>(new BoolLiteral(fContext, position,
    1542           0 :                                                                (bool) found->second.fValue));
    1543             :         case CapValue::kInt_Kind:
    1544             :             return std::unique_ptr<Expression>(new IntLiteral(fContext, position,
    1545           0 :                                                               found->second.fValue));
    1546             :     }
    1547           0 :     ASSERT(false);
    1548           0 :     return nullptr;
    1549             : }
    1550             : 
    1551           0 : std::unique_ptr<Expression> IRGenerator::convertSuffixExpression(
    1552             :                                                             const ASTSuffixExpression& expression) {
    1553           0 :     std::unique_ptr<Expression> base = this->convertExpression(*expression.fBase);
    1554           0 :     if (!base) {
    1555           0 :         return nullptr;
    1556             :     }
    1557           0 :     switch (expression.fSuffix->fKind) {
    1558             :         case ASTSuffix::kIndex_Kind: {
    1559           0 :             const ASTExpression* expr = ((ASTIndexSuffix&) *expression.fSuffix).fExpression.get();
    1560           0 :             if (expr) {
    1561           0 :                 return this->convertIndex(std::move(base), *expr);
    1562           0 :             } else if (base->fKind == Expression::kTypeReference_Kind) {
    1563           0 :                 const Type& oldType = ((TypeReference&) *base).fValue;
    1564           0 :                 Type* newType = new Type(oldType.name() + "[]", Type::kArray_Kind, oldType,
    1565           0 :                                          -1);
    1566           0 :                 fSymbolTable->takeOwnership(newType);
    1567           0 :                 return std::unique_ptr<Expression>(new TypeReference(fContext, base->fPosition,
    1568           0 :                                                                      *newType));
    1569             :             } else {
    1570           0 :                 fErrors.error(expression.fPosition, "'[]' must follow a type name");
    1571           0 :                 return nullptr;
    1572             :             }
    1573             :         }
    1574             :         case ASTSuffix::kCall_Kind: {
    1575           0 :             auto rawArguments = &((ASTCallSuffix&) *expression.fSuffix).fArguments;
    1576           0 :             std::vector<std::unique_ptr<Expression>> arguments;
    1577           0 :             for (size_t i = 0; i < rawArguments->size(); i++) {
    1578             :                 std::unique_ptr<Expression> converted =
    1579           0 :                         this->convertExpression(*(*rawArguments)[i]);
    1580           0 :                 if (!converted) {
    1581           0 :                     return nullptr;
    1582             :                 }
    1583           0 :                 arguments.push_back(std::move(converted));
    1584             :             }
    1585           0 :             return this->call(expression.fPosition, std::move(base), std::move(arguments));
    1586             :         }
    1587             :         case ASTSuffix::kField_Kind: {
    1588           0 :             if (base->fType == *fContext.fSkCaps_Type) {
    1589             :                 return this->getCap(expression.fPosition,
    1590           0 :                                     ((ASTFieldSuffix&) *expression.fSuffix).fField);
    1591             :             }
    1592           0 :             switch (base->fType.kind()) {
    1593             :                 case Type::kVector_Kind:
    1594           0 :                     return this->convertSwizzle(std::move(base),
    1595           0 :                                                 ((ASTFieldSuffix&) *expression.fSuffix).fField);
    1596             :                 case Type::kStruct_Kind:
    1597           0 :                     return this->convertField(std::move(base),
    1598           0 :                                               ((ASTFieldSuffix&) *expression.fSuffix).fField);
    1599             :                 default:
    1600           0 :                     fErrors.error(base->fPosition, "cannot swizzle value of type '" +
    1601           0 :                                                    base->fType.description() + "'");
    1602           0 :                     return nullptr;
    1603             :             }
    1604             :         }
    1605             :         case ASTSuffix::kPostIncrement_Kind:
    1606           0 :             if (!base->fType.isNumber()) {
    1607           0 :                 fErrors.error(expression.fPosition,
    1608           0 :                               "'++' cannot operate on '" + base->fType.description() + "'");
    1609           0 :                 return nullptr;
    1610             :             }
    1611           0 :             this->markWrittenTo(*base, true);
    1612           0 :             return std::unique_ptr<Expression>(new PostfixExpression(std::move(base),
    1613           0 :                                                                      Token::PLUSPLUS));
    1614             :         case ASTSuffix::kPostDecrement_Kind:
    1615           0 :             if (!base->fType.isNumber()) {
    1616           0 :                 fErrors.error(expression.fPosition,
    1617           0 :                               "'--' cannot operate on '" + base->fType.description() + "'");
    1618           0 :                 return nullptr;
    1619             :             }
    1620           0 :             this->markWrittenTo(*base, true);
    1621           0 :             return std::unique_ptr<Expression>(new PostfixExpression(std::move(base),
    1622           0 :                                                                      Token::MINUSMINUS));
    1623             :         default:
    1624           0 :             ABORT("unsupported suffix operator");
    1625             :     }
    1626             : }
    1627             : 
    1628           0 : void IRGenerator::checkValid(const Expression& expr) {
    1629           0 :     switch (expr.fKind) {
    1630             :         case Expression::kFunctionReference_Kind:
    1631           0 :             fErrors.error(expr.fPosition, "expected '(' to begin function call");
    1632           0 :             break;
    1633             :         case Expression::kTypeReference_Kind:
    1634           0 :             fErrors.error(expr.fPosition, "expected '(' to begin constructor invocation");
    1635           0 :             break;
    1636             :         default:
    1637           0 :             if (expr.fType == *fContext.fInvalid_Type) {
    1638           0 :                 fErrors.error(expr.fPosition, "invalid expression");
    1639             :             }
    1640             :     }
    1641           0 : }
    1642             : 
    1643           0 : static bool has_duplicates(const Swizzle& swizzle) {
    1644           0 :     int bits = 0;
    1645           0 :     for (int idx : swizzle.fComponents) {
    1646           0 :         ASSERT(idx >= 0 && idx <= 3);
    1647           0 :         int bit = 1 << idx;
    1648           0 :         if (bits & bit) {
    1649           0 :             return true;
    1650             :         }
    1651           0 :         bits |= bit;
    1652             :     }
    1653           0 :     return false;
    1654             : }
    1655             : 
    1656           0 : void IRGenerator::markWrittenTo(const Expression& expr, bool readWrite) {
    1657           0 :     switch (expr.fKind) {
    1658             :         case Expression::kVariableReference_Kind: {
    1659           0 :             const Variable& var = ((VariableReference&) expr).fVariable;
    1660           0 :             if (var.fModifiers.fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
    1661           0 :                 fErrors.error(expr.fPosition,
    1662           0 :                               "cannot modify immutable variable '" + var.fName + "'");
    1663             :             }
    1664           0 :             ((VariableReference&) expr).setRefKind(readWrite ? VariableReference::kReadWrite_RefKind
    1665           0 :                                                              : VariableReference::kWrite_RefKind);
    1666           0 :             break;
    1667             :         }
    1668             :         case Expression::kFieldAccess_Kind:
    1669           0 :             this->markWrittenTo(*((FieldAccess&) expr).fBase, readWrite);
    1670           0 :             break;
    1671             :         case Expression::kSwizzle_Kind:
    1672           0 :             if (has_duplicates((Swizzle&) expr)) {
    1673           0 :                 fErrors.error(expr.fPosition,
    1674           0 :                               "cannot write to the same swizzle field more than once");
    1675             :             }
    1676           0 :             this->markWrittenTo(*((Swizzle&) expr).fBase, readWrite);
    1677           0 :             break;
    1678             :         case Expression::kIndex_Kind:
    1679           0 :             this->markWrittenTo(*((IndexExpression&) expr).fBase, readWrite);
    1680           0 :             break;
    1681             :         default:
    1682           0 :             fErrors.error(expr.fPosition, "cannot assign to '" + expr.description() + "'");
    1683           0 :             break;
    1684             :     }
    1685           0 : }
    1686             : 
    1687             : }

Generated by: LCOV version 1.13