bool isChildofMain(TIntermNode *node, TIntermNode *root) { TIntermNode *main = getFunctionBySignature(MAIN_FUNC_SIGNATURE, root); if (!main) { dbgPrint(DBGLVL_ERROR, "CodeTools - could not find main function\n"); exit(1); } TIntermAggregate *aggregate; if (!(aggregate = main->getAsAggregate())) { dbgPrint(DBGLVL_ERROR, "CodeTools - main is not Aggregate\n"); exit(1); } TIntermSequence sequence = aggregate->getSequence(); TIntermSequence::iterator sit; for(sit = sequence.begin(); sit != sequence.end(); sit++) { if (*sit == node) { return true; } } return false; }
TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) { ASSERT(selection->getFalseBlock() != NULL); TString temporaryName = "cond_" + str(mTemporaryIndex++); TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); TType resultType(EbtBool, EbpUndefined); TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool); TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool); TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool); TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA, typedCondition, resultType); TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB); TIntermSelection *falseBlock = new TIntermSelection(negatedCondition, selection->getFalseBlock(), NULL); TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC, selection->getTrueBlock(), falseBlock); TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); declaration->getSequence().push_back(storeCondition); TIntermAggregate *block = new TIntermAggregate(EOpSequence); block->getSequence().push_back(declaration); block->getSequence().push_back(newIfElse); return block; }
// // This is the safe way to change the operator on an aggregate, as it // does lots of error checking and fixing. Especially for establishing // a function call's operation on it's set of parameters. Sequences // of instructions are also aggregates, but they just direnctly set // their operator to EOpSequence. // // Returns an aggregate node, which could be the one passed in if // it was already an aggregate but no operator was set. // TIntermAggregate *TIntermediate::setAggregateOperator( TIntermNode *node, TOperator op, const TSourceLoc &line) { TIntermAggregate *aggNode; // // Make sure we have an aggregate. If not turn it into one. // if (node) { aggNode = node->getAsAggregate(); if (aggNode == NULL || aggNode->getOp() != EOpNull) { // // Make an aggregate containing this node. // aggNode = new TIntermAggregate(); aggNode->getSequence()->push_back(node); } } else { aggNode = new TIntermAggregate(); } // // Set the operator. // aggNode->setOp(op); aggNode->setLine(line); return aggNode; }
// This is the safe way to change the operator on an aggregate, as it // does lots of error checking and fixing. Especially for establishing // a function call's operation on it's set of parameters. Sequences // of instructions are also aggregates, but they just direnctly set // their operator to EOpSequence. // // Returns an aggregate node, which could be the one passed in if // it was already an aggregate. TIntermAggregate* ir_set_aggregate_op(TIntermNode* node, TOperator op, TSourceLoc line) { TIntermAggregate* aggNode; // // Make sure we have an aggregate. If not turn it into one. // if (node) { aggNode = node->getAsAggregate(); if (aggNode == 0 || aggNode->getOp() != EOpNull) { // // Make an aggregate containing this node. // aggNode = new TIntermAggregate(); aggNode->getNodes().push_back(node); if (line.line == 0) line = node->getLine(); } } else aggNode = new TIntermAggregate(); // // Set the operator. // aggNode->setOperator(op); if (line.line != 0) aggNode->setLine(line); return aggNode; }
void TLValueTrackingTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node) { TIntermAggregate *params = node->getFunctionParameters(); ASSERT(params != nullptr); ASSERT(params->getOp() == EOpParameters); addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), params->getSequence()); TIntermTraverser::traverseFunctionDefinition(node); }
int ValidateLimitations::validateForLoopInit(TIntermLoop *node) { TIntermNode *init = node->getInit(); if (init == NULL) { error(node->getLine(), "Missing init declaration", "for"); return -1; } // // init-declaration has the form: // type-specifier identifier = constant-expression // TIntermAggregate *decl = init->getAsAggregate(); if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { error(init->getLine(), "Invalid init declaration", "for"); return -1; } // To keep things simple do not allow declaration list. TIntermSequence &declSeq = decl->getSequence(); if (declSeq.size() != 1) { error(decl->getLine(), "Invalid init declaration", "for"); return -1; } TIntermBinary *declInit = declSeq[0]->getAsBinaryNode(); if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { error(decl->getLine(), "Invalid init declaration", "for"); return -1; } TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); if (symbol == NULL) { error(declInit->getLine(), "Invalid init declaration", "for"); return -1; } // The loop index has type int or float. TBasicType type = symbol->getBasicType(); if ((type != EbtInt) && (type != EbtFloat)) { error(symbol->getLine(), "Invalid type for loop index", getBasicString(type)); return -1; } // The loop index is initialized with constant expression. if (!isConstExpr(declInit->getRight())) { error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression", symbol->getSymbol().c_str()); return -1; } return symbol->getId(); }
bool TCompiler::pruneUnusedFunctions(TIntermNode *root) { TIntermAggregate *rootNode = root->getAsAggregate(); ASSERT(rootNode != nullptr); UnusedPredicate isUnused(&mCallDag, &functionMetadata); TIntermSequence *sequence = rootNode->getSequence(); sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end()); return true; }
// // Turn an existing node into an aggregate. // // Returns an aggregate, unless 0 was passed in for the existing node. // TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) { if (node == 0) return 0; TIntermAggregate* aggNode = new TIntermAggregate; aggNode->getSequence().push_back(node); aggNode->setLine(line); return aggNode; }
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier) { ASSERT(initializer != nullptr); TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier); TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration); TIntermBinary *tempInit = new TIntermBinary(EOpInitialize); tempInit->setLeft(tempSymbol); tempInit->setRight(initializer); tempInit->setType(tempSymbol->getType()); tempDeclaration->getSequence()->push_back(tempInit); return tempDeclaration; }
// If the input node is nullptr, return nullptr. // If the input node is a sequence (block) node, return it. // If the input node is not a sequence node, put it inside a sequence node and return that. TIntermAggregate *TIntermediate::ensureSequence(TIntermNode *node) { if (node == nullptr) return nullptr; TIntermAggregate *aggNode = node->getAsAggregate(); if (aggNode != nullptr && aggNode->getOp() == EOpSequence) return aggNode; aggNode = makeAggregate(node, node->getLine()); aggNode->setOp(EOpSequence); return aggNode; }
// // This is to be executed once the final root is put on top by the parsing // process. // bool TIntermediate::postProcess(TIntermNode *root) { if (root == NULL) return true; // // First, finish off the top level sequence, if any // TIntermAggregate *aggRoot = root->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOp(EOpSequence); return true; }
TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original) { TString tempVarName = "_webgl_tmp_"; if (original->isScalar()) { tempVarName += "scalar_"; } else if (original->isVector()) { tempVarName += "vec_"; } else { ASSERT(original->isMatrix()); tempVarName += "mat_"; } tempVarName += Str(mTempVarCount).c_str(); mTempVarCount++; ASSERT(original); TType type = original->getType(); type.setQualifier(EvqTemporary); if (mShaderType == GL_FRAGMENT_SHADER && type.getBasicType() == EbtFloat && type.getPrecision() == EbpUndefined) { // We use the highest available precision for the temporary variable // to avoid computing the actual precision using the rules defined // in GLSL ES 1.0 Section 4.5.2. type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); } TIntermBinary *init = new TIntermBinary(EOpInitialize); TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type); init->setLeft(symbolNode); init->setRight(original); init->setType(type); TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration); decl->getSequence()->push_back(init); ASSERT(mSequenceStack.size() > 0); TIntermSequence &sequence = mSequenceStack.back(); sequence.push_back(decl); return tempVarName; }
TIntermTyped* ir_add_swizzle(TVectorFields& fields, TSourceLoc line) { TIntermAggregate* node = new TIntermAggregate(EOpSequence); node->setLine(line); TNodeArray& nodes = node->getNodes(); for (int i = 0; i < fields.num; i++) { TIntermConstant* constant = ir_add_constant(TType(EbtInt, EbpUndefined, EvqConst), line); constant->setValue(fields.offsets[i]); nodes.push_back(constant); } return node; }
TIntermAggregate* ir_grow_declaration(TIntermTyped* declaration, TIntermSymbol *symbol, TIntermTyped *initializer, TParseContext& ctx) { TIntermTyped* added_decl = ir_add_declaration (symbol, initializer, symbol->getLine(), ctx); if (declaration->getAsDeclaration()) { TIntermAggregate* aggregate = ir_make_aggregate(declaration, declaration->getLine()); aggregate->setOperator(EOpSequence); declaration = aggregate; } assert (declaration->getAsAggregate()); TIntermAggregate* aggregate = ir_grow_aggregate(declaration, added_decl, added_decl->getLine(), EOpSequence); aggregate->setOperator(EOpSequence); return aggregate; }
// Turn an existing node into an aggregate. TIntermAggregate* ir_make_aggregate(TIntermNode* node, TSourceLoc line) { if (node == 0) return 0; TIntermAggregate* aggNode = new TIntermAggregate; if (node->getAsTyped()) aggNode->setType(*node->getAsTyped()->getTypePointer()); aggNode->getNodes().push_back(node); if (line.line != 0) aggNode->setLine(line); else aggNode->setLine(node->getLine()); return aggNode; }
// // Merge the function bodies and global-level initializers from unitGlobals into globals. // Will error check duplication of function bodies for the same signature. // void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals) { // TODO: link-time performance: Processing in alphabetical order will be faster // Error check the global objects, not including the linker objects for (unsigned int child = 0; child < globals.size() - 1; ++child) { for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) { TIntermAggregate* body = globals[child]->getAsAggregate(); TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate(); if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) { error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:"); infoSink.info << " " << globals[child]->getAsAggregate()->getName() << "\n"; } } } // Merge the global objects, just in front of the linker objects globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); }
TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) { TIntermAggregate* node = new TIntermAggregate(EOpSequence); node->setLine(line); TIntermConstantUnion* constIntNode; TIntermSequence &sequenceVector = node->getSequence(); ConstantUnion* unionArray; for (int i = 0; i < fields.num; i++) { unionArray = new ConstantUnion[1]; unionArray->setIConst(fields.offsets[i]); constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); sequenceVector.push_back(constIntNode); } return node; }
TIntermDeclaration* ir_grow_declaration(TIntermDeclaration* declaration, TIntermSymbol *symbol, TIntermTyped *initializer, TInfoSink& infoSink) { TIntermTyped* added_decl = symbol; if (initializer) added_decl = ir_add_assign(EOpAssign, symbol, initializer, symbol->getLine(), infoSink); if (declaration->isSingleDeclaration()) { TIntermTyped* current = declaration->getDeclaration(); TIntermAggregate* aggregate = ir_make_aggregate(current, current->getLine()); aggregate->setOperator(EOpComma); declaration->getDeclaration() = aggregate; } TIntermAggregate* aggregate = ir_grow_aggregate(declaration->getDeclaration(), added_decl, added_decl->getLine()); aggregate->setOperator(EOpComma); declaration->getDeclaration() = aggregate; return declaration; }
ParsedHxsl Parser::parse(TIntermNode* e) { TIntermAggregate* aggregate = e->getAsAggregate(); for (auto it = aggregate->getSequence().begin(); it != aggregate->getSequence().end(); ++it) { parseDecl(*it); } if (main == nullptr) error("Missing main function", e->getLine().first_line); allowReturn = false; ParsedCode s = buildShader(main); std::map<std::string, ParsedCode> help; allowReturn = true; for (auto it = helpers.begin(); it != helpers.end(); ++it) { help[it->first] = buildShader(it->second); } ParsedHxsl hxsl; hxsl.shader = s; hxsl.globals = globals; hxsl.pos = e->getLine().first_line; hxsl.helpers = help; return hxsl; }
// // Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. // // Returns the resulting aggregate, unless 0 was passed in for // both existing nodes. // TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) { if (left == 0 && right == 0) return 0; TIntermAggregate* aggNode = 0; if (left) aggNode = left->getAsAggregate(); if (!aggNode || aggNode->getOp() != EOpNull) { aggNode = new TIntermAggregate; if (left) aggNode->getSequence().push_back(left); } if (right) aggNode->getSequence().push_back(right); aggNode->setLine(line); return aggNode; }
TIntermNode* getFunctionBySignature(const char *sig, TIntermNode* root) // Assumption: 1. roots hold all function definitions. // for single file shaders this should hold. // Todo: Add solution for multiple files compiled in one shader. { TIntermAggregate *aggregate; TIntermSequence sequence; TIntermSequence::iterator sit; // Root must be aggregate if (!(aggregate = root->getAsAggregate())) { return NULL; } if (aggregate->getOp() == EOpFunction) { // do not stop search at function prototypes if (aggregate->getSequence().size() != 0) { if (!strcmp(sig, aggregate->getName().c_str())) { return aggregate; } } } else { sequence = aggregate->getSequence(); for (sit = sequence.begin(); sit != sequence.end(); sit++) { if ((*sit)->getAsAggregate() && (*sit)->getAsAggregate()->getOp() == EOpFunction) { // do not stop search at function prototypes if ((*sit)->getAsAggregate()->getSequence().size() != 0) { if (!strcmp(sig, (*sit)->getAsAggregate()->getName().c_str())) { return *sit; } } } } } return NULL; }
void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info) { ASSERT(node->getType() == ELoopFor); ASSERT(node->getUnrollFlag()); TIntermNode* init = node->getInit(); ASSERT(init != NULL); TIntermAggregate* decl = init->getAsAggregate(); ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration)); TIntermSequence& declSeq = decl->getSequence(); ASSERT(declSeq.size() == 1); TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize)); TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); ASSERT(symbol != NULL); ASSERT(symbol->getBasicType() == EbtInt); info.id = symbol->getId(); ASSERT(declInit->getRight() != NULL); TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); ASSERT(initNode != NULL); info.initValue = evaluateIntConstant(initNode); info.currentValue = info.initValue; TIntermNode* cond = node->getCondition(); ASSERT(cond != NULL); TIntermBinary* binOp = cond->getAsBinaryNode(); ASSERT(binOp != NULL); ASSERT(binOp->getRight() != NULL); ASSERT(binOp->getRight()->getAsConstantUnion() != NULL); info.incrementValue = getLoopIncrement(node); info.stopValue = evaluateIntConstant( binOp->getRight()->getAsConstantUnion()); info.op = binOp->getOp(); }
// Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. // // Returns the resulting aggregate, unless 0 was passed in for // both existing nodes. TIntermAggregate* ir_grow_aggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line, TOperator expectedOp) { if (left == 0 && right == 0) return 0; TIntermAggregate* aggNode = 0; if (left) aggNode = left->getAsAggregate(); if (!aggNode || aggNode->getOp() != expectedOp) { aggNode = new TIntermAggregate; if (left) aggNode->getNodes().push_back(left); } if (right) aggNode->getNodes().push_back(right); if (line.line != 0) aggNode->setLine(line); return aggNode; }
bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = !mCodeInserted; switch (node->getOp()) { case EOpSequence: break; case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); if (node->getName() == "main(") { TIntermSequence *sequence = node->getSequence(); ASSERT((sequence->size() == 1) || (sequence->size() == 2)); TIntermAggregate *body = NULL; if (sequence->size() == 1) { body = new TIntermAggregate(EOpSequence); sequence->push_back(body); } else { body = (*sequence)[1]->getAsAggregate(); } ASSERT(body); insertInitCode(body->getSequence()); mCodeInserted = true; } break; } default: visitChildren = false; break; } return visitChildren; }
// constructor // : type argument_list // bool HlslGrammar::acceptConstructor(TIntermTyped*& node) { // type TType type; if (acceptType(type)) { TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type); if (constructorFunction == nullptr) return false; // arguments TIntermAggregate* arguments = nullptr; if (! acceptArguments(constructorFunction, arguments)) { expected("constructor arguments"); return false; } // hook it up node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments); return true; } return false; }
bool TIntermSelection::promoteTernary(TInfoSink& infoSink) { if (!condition->isVector()) return true; int size = condition->getRowsCount(); TIntermTyped* trueb = trueBlock->getAsTyped(); TIntermTyped* falseb = falseBlock->getAsTyped(); if (!trueb || !falseb) return false; if (trueb->getRowsCount() == size && falseb->getRowsCount() == size) return true; // Base assumption: just make the type a float vector TPrecision higherPrecision = GetHigherPrecision(trueb->getPrecision(), falseb->getPrecision()); setType(TType(EbtFloat, higherPrecision, EvqTemporary, 1, size, condition->isMatrix())); TOperator convert = EOpNull; { convert = TOperator( EOpConstructVec2 + size - 2); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(trueb->getLine()); node->setType(TType(condition->getBasicType(), higherPrecision, trueb->getQualifier() == EvqConst ? EvqConst : EvqTemporary, 1, size, condition->isMatrix())); node->getNodes().push_back(trueb); trueBlock = node; } { convert = TOperator( EOpConstructVec2 + size - 2); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(falseb->getLine()); node->setType(TType(condition->getBasicType(), higherPrecision, falseb->getQualifier() == EvqConst ? EvqConst : EvqTemporary, 1, size, condition->isMatrix())); node->getNodes().push_back(falseb); falseBlock = node; } return true; }
// // This is to be executed once the final root is put on top by the parsing // process. // TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) { if (root == nullptr) return nullptr; // // Finish off the top level sequence, if any // TIntermAggregate *aggRoot = root->getAsAggregate(); if (aggRoot != nullptr && aggRoot->getOp() == EOpNull) { aggRoot->setOp(EOpSequence); } else if (aggRoot == nullptr || aggRoot->getOp() != EOpSequence) { aggRoot = new TIntermAggregate(EOpSequence); aggRoot->setLine(root->getLine()); aggRoot->getSequence()->push_back(root); } return aggRoot; }
bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node) { bool visitChildren = true; TInfoSinkBase& out = objSink(); TString preString; bool delayedWrite = false; switch (node->getOp()) { case EOpSequence: { // Scope the sequences except when at the global scope. if (depth > 0) out << "{\n"; incrementDepth(); const TIntermSequence& sequence = node->getSequence(); for (TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) { TIntermNode* node = *iter; ASSERT(node != NULL); node->traverse(this); if (isSingleStatement(node)) out << ";\n"; } decrementDepth(); // Scope the sequences except when at the global scope. if (depth > 0) out << "}\n"; visitChildren = false; break; } case EOpPrototype: { // Function declaration. ASSERT(visit == PreVisit); writeVariableType(node->getType()); out << " " << node->getName(); out << "("; writeFunctionParameters(node->getSequence()); out << ")"; visitChildren = false; break; } case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); writeVariableType(node->getType()); out << " " << TFunction::unmangleName(node->getName()); incrementDepth(); // Function definition node contains one or two children nodes // representing function parameters and function body. The latter // is not present in case of empty function bodies. const TIntermSequence& sequence = node->getSequence(); ASSERT((sequence.size() == 1) || (sequence.size() == 2)); TIntermSequence::const_iterator seqIter = sequence.begin(); // Traverse function parameters. TIntermAggregate* params = (*seqIter)->getAsAggregate(); ASSERT(params != NULL); ASSERT(params->getOp() == EOpParameters); params->traverse(this); // Traverse function body. TIntermAggregate* body = ++seqIter != sequence.end() ? (*seqIter)->getAsAggregate() : NULL; visitCodeBlock(body); decrementDepth(); // Fully processed; no need to visit children. visitChildren = false; break; } case EOpFunctionCall: // Function call. if (visit == PreVisit) { TString functionName = TFunction::unmangleName(node->getName()); out << functionName << "("; } else if (visit == InVisit) { out << ", "; } else { out << ")"; } break; case EOpParameters: { // Function parameters. ASSERT(visit == PreVisit); out << "("; writeFunctionParameters(node->getSequence()); out << ")"; visitChildren = false; break; } case EOpDeclaration: { // Variable declaration. if (visit == PreVisit) { const TIntermSequence& sequence = node->getSequence(); const TIntermTyped* variable = sequence.front()->getAsTyped(); writeVariableType(variable->getType()); out << " "; mDeclaringVariables = true; } else if (visit == InVisit) { out << ", "; mDeclaringVariables = true; } else { mDeclaringVariables = false; } break; } case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break; case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break; case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break; case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break; case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break; case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break; case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break; case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break; case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break; case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break; case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break; case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break; case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break; case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break; case EOpConstructStruct: if (visit == PreVisit) { const TType& type = node->getType(); ASSERT(type.getBasicType() == EbtStruct); out << type.getTypeName() << "("; } else if (visit == InVisit) { out << ", "; } else { out << ")"; } break; case EOpLessThan: preString = "lessThan("; delayedWrite = true; break; case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break; case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break; case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break; case EOpVectorEqual: preString = "equal("; delayedWrite = true; break; case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break; case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break; case EOpMod: preString = "mod("; delayedWrite = true; break; case EOpPow: preString = "pow("; delayedWrite = true; break; case EOpAtan: preString = "atan("; delayedWrite = true; break; case EOpMin: preString = "min("; delayedWrite = true; break; case EOpMax: preString = "max("; delayedWrite = true; break; case EOpClamp: preString = "clamp("; delayedWrite = true; break; case EOpMix: preString = "mix("; delayedWrite = true; break; case EOpStep: preString = "step("; delayedWrite = true; break; case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break; case EOpDistance: preString = "distance("; delayedWrite = true; break; case EOpDot: preString = "dot("; delayedWrite = true; break; case EOpCross: preString = "cross("; delayedWrite = true; break; case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break; case EOpReflect: preString = "reflect("; delayedWrite = true; break; case EOpRefract: preString = "refract("; delayedWrite = true; break; case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break; default: UNREACHABLE(); break; } if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction()) preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); if (delayedWrite) writeTriplet(visit, preString.c_str(), ", ", ")"); return visitChildren; }
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) { bool visitChildren = true; TInfoSinkBase& out = objSink(); switch (node->getOp()) { case EOpInitialize: if (visit == InVisit) { out << " = "; // RHS of initialize is not being declared. mDeclaringVariables = false; } break; case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; case EOpIndexDirect: case EOpIndexIndirect: writeTriplet(visit, NULL, "[", "]"); break; case EOpIndexDirectStruct: if (visit == InVisit) { out << "."; // TODO(alokp): ASSERT out << node->getType().getFieldName(); visitChildren = false; } break; case EOpVectorSwizzle: if (visit == InVisit) { out << "."; TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); TIntermSequence& sequence = rightChild->getSequence(); for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) { TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); ASSERT(element->getBasicType() == EbtInt); ASSERT(element->getNominalSize() == 1); const ConstantUnion& data = element->getUnionArrayPointer()[0]; ASSERT(data.getType() == EbtInt); switch (data.getIConst()) { case 0: out << "x"; break; case 1: out << "y"; break; case 2: out << "z"; break; case 3: out << "w"; break; default: UNREACHABLE(); break; } } visitChildren = false; } break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; case EOpMod: UNIMPLEMENTED(); break; case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; // Notice the fall-through. case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: writeTriplet(visit, "(", " * ", ")"); break; case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; default: UNREACHABLE(); break; } return visitChildren; }
// // Establishes the type of the resultant operation, as well as // makes the operator the correct one for the operands. // // Returns false if operator can't work on operands. // bool TIntermBinary::promote(TParseContext& ctx) { TBasicType type = left->getBasicType(); // // Arrays have to be exact matches. // if ((left->isArray() || right->isArray()) && (left->getType() != right->getType())) return false; // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(TType(type, left->getPrecision(), EvqTemporary, left->getColsCount(), left->getRowsCount(), left->isMatrix())); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // // Array operations. // if (left->isArray()) { switch (op) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: setType(TType(EbtBool, EbpUndefined)); break; // // Set array information. // case EOpAssign: getType().setArraySize(left->getType().getArraySize()); getType().setArrayInformationType(left->getType().getArrayInformationType()); break; default: return false; } return true; } // // All scalars. Code after this test assumes this case is removed! // if (left->isScalar() && right->isScalar()) { switch (op) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: setType(TType(EbtBool, EbpUndefined)); break; // // And and Or operate on conditionals // case EOpLogicalAnd: case EOpLogicalOr: if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) return false; setType(TType(EbtBool, EbpUndefined)); break; // // Check for integer only operands. // case EOpRightShift: case EOpLeftShift: case EOpAnd: case EOpInclusiveOr: case EOpExclusiveOr: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; break; case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; // fall through // // Everything else should have matching types // default: if (left->getBasicType() != right->getBasicType() || left->isMatrix() != right->isMatrix()) return false; } return true; } // this is not an allowed promotion : float3x4 * float4x3 if (left->getRowsCount() != right->getRowsCount() && left->getColsCount() != right->getColsCount() && (left->getRowsCount() > right->getRowsCount()) != (left->getColsCount() > right->getColsCount())) return false; //determine if this is an assignment bool assignment = ( op >= EOpAssign && op <= EOpRightShiftAssign) ? true : false; // find size of the resulting value int cols = 0; int rows = 0; if (!left->isScalar() && !right->isScalar()) // no scalars, so downcast of the larger type { cols = std::min(left->getColsCount(), right->getColsCount()); rows = std::min(left->getRowsCount(), right->getRowsCount()); } else { cols = std::max(left->getColsCount(), right->getColsCount()); rows = std::max(left->getRowsCount(), right->getRowsCount()); } assert(cols > 0); assert(rows > 0); // // Downcast needed ? // if ( left->getColsCount() > cols || left->getRowsCount() > rows) { if (assignment) return false; //can't promote the destination //down convert left to match right TOperator convert = EOpNull; if (left->getTypePointer()->isMatrix()) { convert = getMatrixConstructOp(*right, ctx); if (convert == EOpNull) return false; } else if (left->getTypePointer()->isVector()) { switch (right->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + rows - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + rows - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + rows - 2); break; default: break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(left->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getColsCount(), right->getRowsCount(), left->isMatrix())); node->getNodes().push_back(left); left = node; //now reset this node's type setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getColsCount(), right->getRowsCount(), left->isMatrix())); } else if ( right->getColsCount() > cols || right->getRowsCount() > rows) { //down convert right to match left TOperator convert = EOpNull; if (right->getTypePointer()->isMatrix()) { convert = getMatrixConstructOp(*left, ctx); if (convert == EOpNull) return false; } else if (right->getTypePointer()->isVector()) { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + rows - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + rows - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + rows - 2); break; default: break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(right->getBasicType(), right->getPrecision(), EvqTemporary, left->getColsCount(), left->getRowsCount(), right->isMatrix())); node->getNodes().push_back(right); right = node; } // // Can these two operands be combined? // switch (op) { case EOpMul: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrix; else { op = EOpMatrixTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, true)); } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { op = EOpMatrixTimesVector; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } else { op = EOpMatrixTimesScalar; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrix; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { op = EOpVectorTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } } else { ctx.infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpMulAssign: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrixAssign; else { return false; } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { return false; } else { op = EOpMatrixTimesScalarAssign; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrixAssign; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { if (! left->isVector()) return false; op = EOpVectorTimesScalarAssign; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } } else { ctx.infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpAssign: if ( left->getColsCount() != right->getColsCount() || left->getRowsCount() != right->getRowsCount()) { //right needs to be forced to match left TOperator convert = EOpNull; if (left->isMatrix() ) { convert = getMatrixConstructOp(*left, ctx); if (convert == EOpNull) return false; } else if (left->isVector() ) { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + left->getRowsCount() - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + left->getRowsCount() - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + left->getRowsCount() - 2); break; default: break; } } else { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = EOpConstructBool; break; case EbtInt: convert = EOpConstructInt; break; case EbtFloat: convert = EOpConstructFloat; break; default: break; } } assert( convert != EOpNull); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), right->getQualifier() == EvqConst ? EvqConst : EvqTemporary, left->getColsCount(), left->getRowsCount(), left->isMatrix())); node->getNodes().push_back(right); right = node; cols = right->getColsCount(); rows = right->getRowsCount(); } // fall through case EOpMod: case EOpAdd: case EOpSub: case EOpDiv: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: case EOpModAssign: if (op == EOpMod) type = EbtFloat; if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()) || left->getBasicType() != right->getBasicType()) return false; setType(TType(type, left->getPrecision(), EvqTemporary, cols, rows, left->isMatrix() || right->isMatrix())); break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()) || left->getBasicType() != right->getBasicType()) return false; setType(TType(EbtBool, higherPrecision, EvqTemporary, cols, rows, false)); break; default: return false; } // // One more check for assignment. The Resulting type has to match the left operand. // switch (op) { case EOpAssign: case EOpAddAssign: case EOpSubAssign: case EOpMulAssign: case EOpDivAssign: case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (getType() != left->getType()) return false; break; default: break; } return true; }