// For "if" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are in the // nodePair. TIntermNode* ir_add_selection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line, TInfoSink& infoSink) { // Convert float/int to bool if ( cond->getBasicType() != EbtBool) { cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getColsCount(), cond->getRowsCount(), cond->isMatrix(), cond->isArray()), cond, infoSink); } TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; }
// For "if" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are in the // nodePair. TIntermNode* ir_add_selection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line, TInfoSink& infoSink) { // Convert float/int to bool switch ( cond->getBasicType() ) { case EbtFloat: case EbtInt: cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getNominalSize(), cond->isMatrix(), cond->isArray()), cond, infoSink); break; default: // Do nothing break; } TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; }
// Connect two nodes through an assignment. TIntermTyped* ir_add_assign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TParseContext& ctx) { // // Like adding binary math, except the conversion can only go // from right to left. // TIntermBinary* node = new TIntermBinary(op); if (line.line == 0) line = left->getLine(); node->setLine(line); TIntermTyped* child = ir_add_conversion(op, left->getType(), right, ctx.infoSink); if (child == 0) return 0; node->setLeft(left); node->setRight(child); if (! node->promote(ctx)) return 0; return node; }
// For "?:" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are specified // as separate parameters. TIntermTyped* ir_add_selection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line, TInfoSink& infoSink) { bool bPromoteFromTrueBlockType = true; if (cond->getBasicType() != EbtBool) { cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getColsCount(), cond->getRowsCount(), cond->isMatrix(), cond->isArray()), cond, infoSink); } // Choose which one to try to promote to based on which has more precision // By default, it will promote from the falseBlock type to the trueBlock type. However, // what we want to do is promote to the type with the most precision of the two. So here, // check whether the false block has more precision than the true block, and if so use // its type instead. if ( trueBlock->getBasicType() == EbtBool ) { if ( falseBlock->getBasicType() == EbtInt || falseBlock->getBasicType() == EbtFloat ) { bPromoteFromTrueBlockType = false; } } else if ( trueBlock->getBasicType() == EbtInt ) { if ( falseBlock->getBasicType() == EbtFloat ) { bPromoteFromTrueBlockType = false; } } // // Get compatible types. // if ( bPromoteFromTrueBlockType ) { TIntermTyped* child = ir_add_conversion(EOpSequence, trueBlock->getType(), falseBlock, infoSink); if (child) falseBlock = child; else { child = ir_add_conversion(EOpSequence, falseBlock->getType(), trueBlock, infoSink); if (child) trueBlock = child; else return 0; } } else { TIntermTyped* child = ir_add_conversion(EOpSequence, falseBlock->getType(), trueBlock, infoSink); if (child) trueBlock = child; else { child = ir_add_conversion(EOpSequence, trueBlock->getType(), falseBlock, infoSink); if (child) falseBlock = child; else return 0; } } // // Make a selection node. // TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); node->setLine(line); if (!node->promoteTernary(infoSink)) return 0; return node; }
// Connect two nodes with a new parent that does a binary operation on the nodes. TIntermTyped* ir_add_binary_math(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TParseContext& ctx) { if (!left || !right) return 0; switch (op) { case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if (left->getType().isMatrix() || left->getType().isArray() || left->getType().getBasicType() == EbtStruct) { return 0; } break; case EOpLogicalOr: case EOpLogicalXor: case EOpLogicalAnd: if (left->getType().isMatrix() || left->getType().isArray()) return 0; if ( left->getBasicType() != EbtBool ) { if ( left->getType().getBasicType() != EbtInt && left->getType().getBasicType() != EbtFloat ) return 0; else { // If the left is a float or int, convert to a bool. This is the conversion that HLSL // does left = ir_add_conversion(EOpConstructBool, TType ( EbtBool, left->getPrecision(), left->getQualifier(), left->getColsCount(), left->getRowsCount(), left->isMatrix(), left->isArray()), left, ctx.infoSink); if ( left == 0 ) return 0; } } if (right->getType().isMatrix() || right->getType().isArray() || right->getType().isVector()) return 0; if ( right->getBasicType() != EbtBool ) { if ( right->getType().getBasicType() != EbtInt && right->getType().getBasicType() != EbtFloat ) return 0; else { // If the right is a float or int, convert to a bool. This is the conversion that HLSL // does right = ir_add_conversion(EOpConstructBool, TType ( EbtBool, right->getPrecision(), right->getQualifier(), right->getColsCount(), right->getRowsCount(), right->isMatrix(), right->isArray()), right, ctx.infoSink); if ( right == 0 ) return 0; } } break; case EOpAdd: case EOpSub: case EOpDiv: case EOpMul: case EOpMod: { TBasicType ltype = left->getType().getBasicType(); TBasicType rtype = right->getType().getBasicType(); if (ltype == EbtStruct) return 0; // If left or right type is a bool, convert to float. bool leftToFloat = (ltype == EbtBool); bool rightToFloat = (rtype == EbtBool); // For modulus, if either is an integer, convert to float as well. if (op == EOpMod) { leftToFloat |= (ltype == EbtInt); rightToFloat |= (rtype == EbtInt); } if (leftToFloat) { left = ir_add_conversion (EOpConstructFloat, TType (EbtFloat, left->getPrecision(), left->getQualifier(), left->getColsCount(), left->getRowsCount(), left->isMatrix(), left->isArray()), left, ctx.infoSink); if (left == 0) return 0; } if (rightToFloat) { right = ir_add_conversion (EOpConstructFloat, TType (EbtFloat, right->getPrecision(), right->getQualifier(), right->getColsCount(), right->getRowsCount(), right->isMatrix(), right->isArray()), right, ctx.infoSink); if (right == 0) return 0; } } break; default: break; } // // First try converting the children to compatible types. // if (!(left->getType().getStruct() && right->getType().getStruct())) { TIntermTyped* child = 0; bool useLeft = true; //default to using the left child as the type to promote to //need to always convert up if ( left->getType().getBasicType() != EbtFloat) { if ( right->getType().getBasicType() == EbtFloat) { useLeft = false; } else { if ( left->getType().getBasicType() != EbtInt) { if ( right->getType().getBasicType() == EbtInt) useLeft = false; } } } if (useLeft) { child = ir_add_conversion(op, left->getType(), right, ctx.infoSink); if (child) right = child; else { child = ir_add_conversion(op, right->getType(), left, ctx.infoSink); if (child) left = child; else return 0; } } else { child = ir_add_conversion(op, right->getType(), left, ctx.infoSink); if (child) left = child; else { child = ir_add_conversion(op, left->getType(), right, ctx.infoSink); if (child) right = child; else return 0; } } } else { if (left->getType() != right->getType()) return 0; } // // Need a new node holding things together then. Make // one and promote it to the right type. // TIntermBinary* node = new TIntermBinary(op); if (line.line == 0) line = right->getLine(); node->setLine(line); node->setLeft(left); node->setRight(right); if (! node->promote(ctx)) return 0; // // See if we can fold constants TIntermConstant* constA = left->getAsConstant(); TIntermConstant* constB = right->getAsConstant(); if (constA && constB) { TIntermConstant* FoldBinaryConstantExpression(TOperator op, TIntermConstant* nodeA, TIntermConstant* nodeB); TIntermConstant* res = FoldBinaryConstantExpression(node->getOp(), constA, constB); if (res) { delete node; return res; } } return node; }
// Add one node as the parent of another that it operates on. TIntermTyped* ir_add_unary_math(TOperator op, TIntermNode* childNode, TSourceLoc line, TParseContext& ctx) { TIntermUnary* node; TIntermTyped* child = childNode->getAsTyped(); if (child == 0) { ctx.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, ctx.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(ctx)) return 0; // // See if we can fold constants if (childConst) { TIntermConstant* FoldUnaryConstantExpression(TOperator op, TIntermConstant* node); TIntermConstant* res = FoldUnaryConstantExpression(node->getOp(), childConst); if (res) { delete node; return res; } } return node; }
// 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->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 = ir_add_conversion(op, TType(newType, child->getPrecision(), EvqTemporary, child->getNominalSize(), 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 *childTempConstant = 0; if (child->getAsConstant()) childTempConstant = 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; return node; }