// Convert one type to another. // // Returns the node representing the conversion, which could be the same // node passed in if no conversion was needed. Returns NULL if conversion can't be done. TIntermTyped* ir_add_conversion(TOperator op, const TType& type, TIntermTyped* node, TInfoSink& infoSink) { if (!node) return 0; // // Does the base type allow operation? // switch (node->getBasicType()) { case EbtVoid: case EbtSampler1D: case EbtSampler2D: case EbtSampler3D: case EbtSamplerCube: case EbtSampler1DShadow: case EbtSampler2DShadow: case EbtSamplerRect: // ARB_texture_rectangle case EbtSamplerRectShadow: // ARB_texture_rectangle return 0; default: break; } // // Otherwise, if types are identical, no problem // if (type == node->getType()) return node; // if basic types are identical, promotions will handle everything if (type.getBasicType() == node->getTypePointer()->getBasicType()) return node; // // If one's a structure, then no conversions. // if (type.getStruct() || node->getType().getStruct()) return 0; // // If one's an array, then no conversions. // if (type.isArray() || node->getType().isArray()) return 0; TBasicType promoteTo; switch (op) { // // Explicit conversions // case EOpConstructBool: promoteTo = EbtBool; break; case EOpConstructFloat: promoteTo = EbtFloat; break; case EOpConstructInt: promoteTo = EbtInt; break; default: // // implicit conversions are required for hlsl // promoteTo = type.getBasicType(); } if (node->getAsConstant()) { return ir_promote_constant(promoteTo, node->getAsConstant(), infoSink); } else { // // Add a new newNode for the conversion. // TIntermUnary* newNode = 0; TOperator newOp = EOpNull; switch (promoteTo) { case EbtFloat: switch (node->getBasicType()) { case EbtInt: newOp = EOpConvIntToFloat; break; case EbtBool: newOp = EOpConvBoolToFloat; break; default: infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); return 0; } break; case EbtBool: switch (node->getBasicType()) { case EbtInt: newOp = EOpConvIntToBool; break; case EbtFloat: newOp = EOpConvFloatToBool; break; default: infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); return 0; } break; case EbtInt: switch (node->getBasicType()) { case EbtBool: newOp = EOpConvBoolToInt; break; case EbtFloat: newOp = EOpConvFloatToInt; break; default: infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); return 0; } break; default: infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine()); return 0; } TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); newNode = new TIntermUnary(newOp, type); newNode->setLine(node->getLine()); newNode->setOperand(node); return newNode; } }
// // Add one node as the parent of another that it operates on. // // Returns the added node. // TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable) { TIntermUnary* node; TIntermTyped* child = childNode->getAsTyped(); if (child == 0) { infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); return 0; } switch (op) { case EOpLogicalNot: if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { return 0; } break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) return 0; default: break; } // // Do we need to promote the operand? // // Note: Implicit promotions were removed from the language. // TBasicType newType = EbtVoid; switch (op) { case EOpConstructInt: newType = EbtInt; break; case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; default: break; } if (newType != EbtVoid) { child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, child->getNominalSize(), child->isMatrix(), child->isArray()), child); if (child == 0) return 0; } // // For constructors, we are now done, it's all in the conversion. // switch (op) { case EOpConstructInt: case EOpConstructBool: case EOpConstructFloat: return child; default: break; } TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); // // Make a new node for the operator. // node = new TIntermUnary(op); node->setLine(line); node->setOperand(child); if (! node->promote(infoSink)) return 0; if (childTempConstant) { TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); if (newChild) return newChild; } return node; }
TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) { TIntermUnary *unary = new TIntermUnary(op, operand->getType()); unary->setOperand(operand); return unary; }
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; }
// Add one node as the parent of another that it operates on. TIntermTyped* ir_add_unary_math(TOperator op, TIntermNode* childNode, TSourceLoc line, TInfoSink& infoSink) { TIntermUnary* node; TIntermTyped* child = childNode->getAsTyped(); if (child == 0) { infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); return 0; } switch (op) { case EOpLogicalNot: if (!child->isScalar()) return 0; break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) return 0; default: break; } // // Do we need to promote the operand? // // Note: Implicit promotions were removed from the language. // TBasicType newType = EbtVoid; switch (op) { case EOpConstructInt: newType = EbtInt; break; case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; case EOpLogicalNot: newType = EbtBool; break; default: break; } if (newType != EbtVoid) { child = ir_add_conversion(op, TType(newType, child->getPrecision(), EvqTemporary, child->getColsCount(), child->getRowsCount(), child->isMatrix(), child->isArray()), child, infoSink); if (child == 0) return 0; } // // For constructors, we are now done, it's all in the conversion. // switch (op) { case EOpConstructInt: case EOpConstructBool: case EOpConstructFloat: return child; default: break; } TIntermConstant* childConst = child->getAsConstant(); // // Make a new node for the operator. // node = new TIntermUnary(op); if (line.line == 0) line = child->getLine(); node->setLine(line); node->setOperand(child); if (! node->promote(infoSink)) return 0; // // See if we can fold constants if (childConst) { TIntermConstant* FoldUnaryConstantExpression(TOperator op, TIntermConstant* node); TIntermConstant* res = FoldUnaryConstantExpression(node->getOp(), childConst); if (res) return res; } return node; }
// // Add one node as the parent of another that it operates on. // // Returns the added node. // TIntermTyped *TIntermediate::addUnaryMath( TOperator op, TIntermNode *childNode, const TSourceLoc &line) { TIntermUnary *node; TIntermTyped *child = childNode->getAsTyped(); if (child == NULL) { mInfoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); return NULL; } switch (op) { case EOpLogicalNot: if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { return NULL; } break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: case EOpPositive: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) { return NULL; } default: break; } TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); // // Make a new node for the operator. // node = new TIntermUnary(op); node->setLine(line); node->setOperand(child); if (!node->promote(mInfoSink)) return 0; if (childTempConstant) { TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink); if (newChild) return newChild; } return node; }
// // Convert one type to another. // // Returns the node representing the conversion, which could be the same // node passed in if no conversion was needed. // // Return 0 if a conversion can't be done. // TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) { // // Does the base type allow operation? // switch (node->getBasicType()) { case EbtVoid: case EbtSampler2D: case EbtSamplerCube: return 0; default: break; } // // Otherwise, if types are identical, no problem // if (type == node->getType()) return node; // // If one's a structure, then no conversions. // if (type.getStruct() || node->getType().getStruct()) return 0; // // If one's an array, then no conversions. // if (type.isArray() || node->getType().isArray()) return 0; TBasicType promoteTo; switch (op) { // // Explicit conversions // case EOpConstructBool: promoteTo = EbtBool; break; case EOpConstructFloat: promoteTo = EbtFloat; break; case EOpConstructInt: promoteTo = EbtInt; break; default: // // implicit conversions were removed from the language. // if (type.getBasicType() != node->getType().getBasicType()) return 0; // // Size and structure could still differ, but that's // handled by operator promotion. // return node; } if (node->getAsConstantUnion()) { return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); } else { // // Add a new newNode for the conversion. // TIntermUnary* newNode = 0; TOperator newOp = EOpNull; switch (promoteTo) { case EbtFloat: switch (node->getBasicType()) { case EbtInt: newOp = EOpConvIntToFloat; break; case EbtBool: newOp = EOpConvBoolToFloat; break; default: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); return 0; } break; case EbtBool: switch (node->getBasicType()) { case EbtInt: newOp = EOpConvIntToBool; break; case EbtFloat: newOp = EOpConvFloatToBool; break; default: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); return 0; } break; case EbtInt: switch (node->getBasicType()) { case EbtBool: newOp = EOpConvBoolToInt; break; case EbtFloat: newOp = EOpConvFloatToInt; break; default: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); return 0; } break; default: infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); return 0; } TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); newNode = new TIntermUnary(newOp, type); newNode->setLine(node->getLine()); newNode->setOperand(node); return newNode; } }