Implement operator-based implicit type conversions.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20724 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-02-28 20:49:41 +00:00
parent ef8ae2e345
commit 4b67103b02
6 changed files with 182 additions and 44 deletions

View File

@ -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
}

View File

@ -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.

View File

@ -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());

View File

@ -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)]

View File

@ -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();

View File

@ -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