diff --git a/Test/120.frag b/Test/120.frag index 85fce22f..6c35332c 100644 --- a/Test/120.frag +++ b/Test/120.frag @@ -11,7 +11,51 @@ out vec4 o; uniform mat4x2 m; +struct s { + float f; +}; + void main() { mat2x3 m23 = mat2x3(m); + + int a; + bool b; + s sv = s(a); + float[2] ia = float[2](3, i.y); + float f1 = 1; + float f = a; + f = a; + ivec3 iv3; + vec3 v3 = iv3; + f = f + a; + f = a - f; + f += a; + f = a - f; + v3 *= iv3; + v3 = iv3 / 2.0; + v3 = 3.0 * iv3; + v3 = 2 * v3; + v3 = v3 - 2; + if (f < a || + a <= f || + f > a || + f >= a || + a == f || + f != a); + f = b ? a : f; + f = b ? f : a; + f = b ? a : a; + s news = sv; + + i.xy + i.xyz; // ERROR + m * i.xyz; // ERROR + m + i; // ERROR + int aoeu = 1.0; // ERROR + f = b; // ERROR + f = a + b; // ERROR + f = b * a; // ERROR + b = a; // ERROR + b = b + f; // ERROR + f |= b; // ERROR } diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 8273bf41..eac2701e 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -93,32 +93,24 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn case EOpSub: case EOpDiv: case EOpMul: - if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool) + if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool || left->getType().isArray()) return 0; - default: break; } // // First try converting the children to compatible types. // - - if (!(left->getType().getStruct() && right->getType().getStruct())) { - TIntermTyped* child = addConversion(op, left->getType(), right); + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child) + right = child; + else { + child = addConversion(op, right->getType(), left); if (child) - right = child; - else { - child = addConversion(op, right->getType(), left); - if (child) - left = child; - else - return 0; - } - } else { - if (left->getType() != right->getType()) + left = child; + else return 0; } - - + // // Need a new node holding things together then. Make // one and promote it to the right type. @@ -228,21 +220,17 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, 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 EOpConstructDouble: newType = EbtDouble; break; - default: break; } if (newType != EbtVoid) { @@ -261,8 +249,8 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, case EOpConstructInt: case EOpConstructBool: case EOpConstructFloat: + case EOpConstructDouble: return child; - default: break; } TIntermConstantUnion *childTempConstant = 0; @@ -370,11 +358,14 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt if (type.isArray() || node->getType().isArray()) return 0; + // Note: callers are responsible for other aspects of shape, + // like vector and matrix sizes. + TBasicType promoteTo; switch (op) { // - // Explicit conversions + // Explicit conversions (unary operations) // case EOpConstructBool: promoteTo = EbtBool; @@ -385,31 +376,83 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpConstructInt: promoteTo = EbtInt; break; - default: - // - // implicit conversions were removed from the language. - // - if (type.getBasicType() != node->getType().getBasicType()) + + // + // List all the binary ops that can implicitly convert one operand to the other's type; + // This implements the 'policy' for implicit type conversion. + // + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpEqual: + case EOpNotEqual: + + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpDivAssign: + case EOpModAssign: + + case EOpSequence: + case EOpConstructStruct: + + if (type.getBasicType() == node->getType().getBasicType()) + return node; + + if (canImplicitlyPromote(node->getType().getBasicType(), type.getBasicType())) + promoteTo = type.getBasicType(); + else + return 0; + + break; + + default: + // default is to require a match; all exceptions should have case statements above + + if (type.getBasicType() == node->getType().getBasicType()) + return node; + else 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 { - + } else { // // Add a new newNode for the conversion. // TIntermUnary* newNode = 0; TOperator newOp = EOpNull; + + // This is 'mechanism' here, it does any conversion told. The policy comes + // from the shader or the above code. switch (promoteTo) { + case EbtDouble: + //switch (node->getBasicType()) { + //case EbtInt: newOp = EOpConvIntToDouble; break; + //case EbtBool: newOp = EOpConvBoolToDouble; break; + //case EbtFloat: newOp = EOpConvFloatToDouble; break; + //default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + //} + break; case EbtFloat: switch (node->getBasicType()) { case EbtInt: newOp = EOpConvIntToFloat; break; @@ -451,6 +494,55 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt } } +// +// See if the 'from' type is allowed to be implicitly converted to the +// 'to' type. This is not about vector/array/struct, only about basic type. +// +bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to) +{ + if (profile == EEsProfile || version == 110) + return 0; + + switch (to) { + case EbtDouble: + switch (from) { + case EbtInt: + case EbtUint: + case EbtFloat: + case EbtDouble: + return true; + default: + return false; + } + case EbtFloat: + switch (from) { + case EbtInt: + case EbtUint: + case EbtFloat: + return true; + default: + return false; + } + case EbtUint: + switch (from) { + case EbtInt: + case EbtUint: + return true; + default: + return false; + } + case EbtInt: + switch (from) { + case EbtInt: + return true; + default: + return false; + } + default: + return false; + } +} + // // Safe way to combine two nodes into an aggregate. Works with null pointers, // a node that's not a aggregate yet, etc. diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 0bdf7935..419021d0 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -1326,11 +1326,12 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, T // TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset) { - if (*type == node->getAsTyped()->getType()) { + TIntermNode* converted = intermediate.addConversion(EOpConstructStruct, *type, node->getAsTyped()); + if (converted->getAsTyped()->getType() == *type) { if (subset) - return node->getAsTyped(); + return converted->getAsTyped(); else - return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); + return intermediate.setAggregateOperator(converted->getAsTyped(), EOpConstructStruct, line); } else { error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, node->getAsTyped()->getType().getCompleteTypeString().c_str(), type->getCompleteTypeString().c_str()); diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 6b416fb6..0e34d177 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -89,7 +89,7 @@ TPoolAllocator* PerProcessGPA = 0; bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource* resources, TSymbolTable* symbolTables) { - TIntermediate intermediate(infoSink); + TIntermediate intermediate(infoSink, version, profile); TSymbolTable* symbolTable; if (resources) @@ -509,7 +509,7 @@ int ShCompile( version = defaultVersion; bool goodProfile = DeduceProfile(compiler->infoSink, version, profile); - TIntermediate intermediate(compiler->infoSink); + TIntermediate intermediate(compiler->infoSink, version, profile); SetupBuiltinSymbolTable(version, profile); TSymbolTable symbolTable(*SharedSymbolTables[MapVersionToIndex(version)] diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index b807650f..9ae857c8 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -1073,9 +1073,6 @@ conditional_expression parseContext.recover(); $$ = parseContext.intermediate.addSelection($1, $3, $5, $2.line); - if ($3->getType() != $5->getType()) - $$ = 0; - if ($$ == 0) { parseContext.binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString()); parseContext.recover(); diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 5ef75102..0676bcc2 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -38,6 +38,7 @@ #include "../Include/intermediate.h" #include "../Public/ShaderLang.h" #include "SymbolTable.h" +#include "Versions.h" struct TVectorFields { int offsets[4]; @@ -52,13 +53,14 @@ class TIntermediate { public: POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) - TIntermediate(TInfoSink& i) : infoSink(i) { } + TIntermediate(TInfoSink& i, int v, EProfile p) : infoSink(i), version(v), profile(p) { } TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc); TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&); TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&); + bool canImplicitlyPromote(TBasicType from, TBasicType to); TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc); TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc); TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc); @@ -79,6 +81,8 @@ public: protected: TInfoSink& infoSink; + EProfile profile; + int version; private: void operator=(TIntermediate&); // prevent assignments