bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, int indexSymbolId) { TIntermNode *cond = node->getCondition(); if (cond == NULL) { error(node->getLine(), "Missing condition", "for"); return false; } // // condition has the form: // loop_index relational_operator constant_expression // TIntermBinary *binOp = cond->getAsBinaryNode(); if (binOp == NULL) { error(node->getLine(), "Invalid condition", "for"); return false; } // Loop index should be to the left of relational operator. TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode(); if (symbol == NULL) { error(binOp->getLine(), "Invalid condition", "for"); return false; } if (symbol->getId() != indexSymbolId) { error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // Relational operator is one of: > >= < <= == or !=. switch (binOp->getOp()) { case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: break; default: error(binOp->getLine(), "Invalid relational operator", GetOperatorString(binOp->getOp())); break; } // Loop index must be compared with a constant. if (!isConstExpr(binOp->getRight())) { error(binOp->getLine(), "Loop index cannot be compared with non-constant expression", symbol->getSymbol().c_str()); return false; } return true; }
// Returns name to be used in generated assembly for a given node string ARBVar::GetNodeVarName(TIntermTyped* node) { TIntermSymbol* symbol = node->getAsSymbolNode(); if (symbol) { return string("symbol_") + symbol->getSymbol().c_str(); } TIntermConstantUnion* cu = node->getAsConstantUnion(); if (cu) { string ret = ""; if (cu->getBasicType() == EbtFloat) { if (cu->getNominalSize() == 1) { ret = "const_" + floattostr(cu->getUnionArrayPointer()[0].getFConst()); } else if (cu->isVector() && cu->getNominalSize() > 1 && cu->getNominalSize() <= 4) { ret = "const_vec" + inttostr(cu->getNominalSize()); for (int i = 0; i < cu->getNominalSize(); ++i) { ret += "_" + floattostr(cu->getUnionArrayPointer()[i].getFConst()); } } } if (ret != "") { for (unsigned int i = 0; i < ret.size(); ++i) { if (ret[i] == '.') { ret[i] = 'x'; } } return ret; } } failmsg() << "Unknown node in GetNodeVarName [" << node->getCompleteString() << "]\n"; return "{unknown 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 TGlslOutputTraverser::parseInitializer( TIntermBinary *node ) { TIntermTyped *left, *right; left = node->getLeft(); right = node->getRight(); if (!left->getAsSymbolNode()) return false; //Something is likely seriously wrong TIntermSymbol *symNode = left->getAsSymbolNode(); if (symNode->getBasicType() == EbtStruct) return false; GlslSymbol * sym = NULL; if ( !current->hasSymbol( symNode->getId() ) ) { int array = symNode->getTypePointer()->isArray() ? symNode->getTypePointer()->getArraySize() : 0; const char* semantic = ""; if (symNode->getInfo()) semantic = symNode->getInfo()->getSemantic().c_str(); sym = new GlslSymbol( symNode->getSymbol().c_str(), semantic, symNode->getId(), translateType(symNode->getTypePointer()), m_UsePrecision?node->getPrecision():EbpUndefined, translateQualifier(symNode->getQualifier()), array); current->addSymbol(sym); } else return false; //can't init already declared variable if (right->getAsTyped()) { std::stringstream ss; std::stringstream* oldOut = ¤t->getActiveOutput(); current->pushDepth(0); current->setActiveOutput(&ss); right->getAsTyped()->traverse(this); current->setActiveOutput(oldOut); current->popDepth(); sym->setInitializer(ss.str()); } return true; }
bool ValidateLimitations::validateOperation(TIntermOperator *node, TIntermNode* operand) { // Check if loop index is modified in the loop body. if (!withinLoopBody() || !node->isAssignment()) return true; TIntermSymbol *symbol = operand->getAsSymbolNode(); if (symbol && isLoopIndex(symbol)) { error(node->getLine(), "Loop index cannot be statically assigned to within the body of the loop", symbol->getSymbol().c_str()); } return true; }
bool TGlslOutputTraverser::traverseDeclaration(bool preVisit, TIntermDeclaration* decl, TIntermTraverser* it) { TGlslOutputTraverser* goit = static_cast<TGlslOutputTraverser*>(it); GlslFunction *current = goit->current; std::stringstream& out = current->getActiveOutput(); EGlslSymbolType symbol_type = translateType(decl->getTypePointer()); TType& type = *decl->getTypePointer(); bool emit_osx10_6_arrays = goit->m_EmitSnowLeopardCompatibleArrayInitializers && decl->containsArrayInitialization(); if (emit_osx10_6_arrays) { assert(decl->isSingleInitialization() && "Emission of multiple in-line array declarations isn't supported when running in OS X 10.6 compatible mode."); current->indent(out); out << "#if defined(OSX_SNOW_LEOPARD)" << std::endl; current->increaseDepth(); TQualifier q = type.getQualifier(); if (q == EvqConst) q = EvqTemporary; current->beginStatement(); if (q != EvqTemporary && q != EvqGlobal) out << type.getQualifierString() << " "; TIntermBinary* assign = decl->getDeclaration()->getAsBinaryNode(); TIntermSymbol* sym = assign->getLeft()->getAsSymbolNode(); TIntermSequence& init = assign->getRight()->getAsAggregate()->getSequence(); writeType(out, symbol_type, NULL, goit->m_UsePrecision ? decl->getPrecision() : EbpUndefined); out << "[" << type.getArraySize() << "] " << sym->getSymbol(); current->endStatement(); unsigned n_vals = init.size(); for (unsigned i = 0; i != n_vals; ++i) { current->beginStatement(); sym->traverse(goit); out << "[" << i << "]" << " = "; init[i]->traverse(goit); current->endStatement(); } current->decreaseDepth(); current->indent(out); out << "#else" << std::endl; current->increaseDepth(); } current->beginStatement(); if (type.getQualifier() != EvqTemporary && type.getQualifier() != EvqGlobal) out << type.getQualifierString() << " "; if (type.getBasicType() == EbtStruct) out << type.getTypeName(); else writeType(out, symbol_type, NULL, goit->m_UsePrecision ? decl->getPrecision() : EbpUndefined); if (type.isArray()) out << "[" << type.getArraySize() << "]"; out << " "; decl->getDeclaration()->traverse(goit); current->endStatement(); if (emit_osx10_6_arrays) { current->decreaseDepth(); current->indent(out); out << "#endif" << std::endl; } return false; }
// // Both test and if necessary, spit out an error, to see if the node is really // an l-value that can be operated on this way. // // Returns true if the was an error. // bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node) { TIntermSymbol* symNode = node->getAsSymbolNode(); TIntermBinary* binaryNode = node->getAsBinaryNode(); if (binaryNode) { bool errorReturn; switch(binaryNode->getOp()) { case EOpIndexDirect: case EOpIndexIndirect: case EOpIndexDirectStruct: return lValueErrorCheck(line, op, binaryNode->getLeft()); case EOpVectorSwizzle: errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); if (!errorReturn) { int offset[4] = {0,0,0,0}; TIntermTyped* rightNode = binaryNode->getRight(); TIntermAggregate *aggrNode = rightNode->getAsAggregate(); for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); p != aggrNode->getSequence().end(); p++) { int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); offset[value]++; if (offset[value] > 1) { error(line, " l-value of swizzle cannot have duplicate components", op, "", ""); return true; } } } return errorReturn; default: break; } error(line, " l-value required", op, "", ""); return true; } const char* symbol = 0; if (symNode != 0) symbol = symNode->getSymbol().c_str(); const char* message = 0; switch (node->getQualifier()) { case EvqConst: message = "can't modify a const"; break; case EvqConstReadOnly: message = "can't modify a const"; break; case EvqAttribute: message = "can't modify an attribute"; break; case EvqUniform: message = "can't modify a uniform"; break; case EvqVaryingIn: message = "can't modify a varying"; break; case EvqInput: message = "can't modify an input"; break; case EvqFragCoord: message = "can't modify gl_FragCoord"; break; case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; case EvqPointCoord: message = "can't modify gl_PointCoord"; break; default: // // Type that can't be written to? // switch (node->getBasicType()) { case EbtSampler2D: case EbtSamplerCube: message = "can't modify a sampler"; break; case EbtVoid: message = "can't modify void"; break; default: break; } } if (message == 0 && binaryNode == 0 && symNode == 0) { error(line, " l-value required", op, "", ""); return true; } // // Everything else is okay, no error. // if (message == 0) return false; // // If we get here, we have an error and a message. // if (symNode) error(line, " l-value required", op, "\"%s\" (%s)", symbol, message); else error(line, " l-value required", op, "(%s)", message); return true; }
bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) { TInfoSinkBase &out = objSink(); incrementDepth(node); // Loop header. TLoopType loopType = node->getType(); if (loopType == ELoopFor) // for loop { if (!node->getUnrollFlag()) { out << "for ("; if (node->getInit()) node->getInit()->traverse(this); out << "; "; if (node->getCondition()) node->getCondition()->traverse(this); out << "; "; if (node->getExpression()) node->getExpression()->traverse(this); out << ")\n"; } else { // Need to put a one-iteration loop here to handle break. TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence(); TIntermSymbol *indexSymbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); TString name = hashVariableName(indexSymbol->getSymbol()); out << "for (int " << name << " = 0; " << name << " < 1; " << "++" << name << ")\n"; } } else if (loopType == ELoopWhile) // while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ")\n"; } else // do-while loop { ASSERT(loopType == ELoopDoWhile); out << "do\n"; } // Loop body. if (node->getUnrollFlag()) { out << "{\n"; mLoopUnrollStack.push(node); while (mLoopUnrollStack.satisfiesLoopCondition()) { visitCodeBlock(node->getBody()); mLoopUnrollStack.step(); } mLoopUnrollStack.pop(); out << "}\n"; } else { visitCodeBlock(node->getBody()); } // Loop footer. if (loopType == ELoopDoWhile) // do-while loop { out << "while ("; ASSERT(node->getCondition() != NULL); node->getCondition()->traverse(this); out << ");\n"; } decrementDepth(); // No need to visit children. They have been already processed in // this function. return false; }
bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, int indexSymbolId) { TIntermNode *expr = node->getExpression(); if (expr == NULL) { error(node->getLine(), "Missing expression", "for"); return false; } // for expression has one of the following forms: // loop_index++ // loop_index-- // loop_index += constant_expression // loop_index -= constant_expression // ++loop_index // --loop_index // The last two forms are not specified in the spec, but I am assuming // its an oversight. TIntermUnary *unOp = expr->getAsUnaryNode(); TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); TOperator op = EOpNull; TIntermSymbol *symbol = NULL; if (unOp != NULL) { op = unOp->getOp(); symbol = unOp->getOperand()->getAsSymbolNode(); } else if (binOp != NULL) { op = binOp->getOp(); symbol = binOp->getLeft()->getAsSymbolNode(); } // The operand must be loop index. if (symbol == NULL) { error(expr->getLine(), "Invalid expression", "for"); return false; } if (symbol->getId() != indexSymbolId) { error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // The operator is one of: ++ -- += -=. switch (op) { case EOpPostIncrement: case EOpPostDecrement: case EOpPreIncrement: case EOpPreDecrement: ASSERT((unOp != NULL) && (binOp == NULL)); break; case EOpAddAssign: case EOpSubAssign: ASSERT((unOp == NULL) && (binOp != NULL)); break; default: error(expr->getLine(), "Invalid operator", GetOperatorString(op)); return false; } // Loop index must be incremented/decremented with a constant. if (binOp != NULL) { if (!isConstExpr(binOp->getRight())) { error(binOp->getLine(), "Loop index cannot be modified by non-constant expression", symbol->getSymbol().c_str()); return false; } } return true; }