Implement implicit conversions of function-call arguments (both in and out) as explicit conversions in the AST, through handleArgumentConversions().
Also
- uniformly handle EvqConstReadOnly as an input argument in a function, with
isParamInput() and isParamOutput() queries in TQualifier.
- provide a makeTemporary() in TQualifier, for erasing original qualification when making a temp
- provide a makeInternalVariable() call to make a shader variable not seen in the shader source
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@25912 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/Test/120.vert b/Test/120.vert
index 3981b2c..8790980 100644
--- a/Test/120.vert
+++ b/Test/120.vert
@@ -58,15 +58,15 @@
float overloadA(out float f, int);
float overloadA(int i);
-vec2 overloadB(float, float);
+void overloadB(float, const in float) { }
vec2 overloadC(int, int);
-vec2 overloadC(int, float);
+vec2 overloadC(const in int, float);
vec2 overloadC(float, int);
vec2 overloadC(vec2, vec2);
vec3 overloadD(int, float);
-vec3 overloadD(float, int);
+vec3 overloadD(float, in int);
vec3 overloadE(float[2]);
vec3 overloadE(mat2 m);
@@ -119,3 +119,21 @@
}
varying vec4 gl_TexCoord[35]; // ERROR, size too big
+
+// tests for output conversions
+void outFun(in float, out ivec2, in int, out float);
+int outFunRet(in float, out int, const in int, out ivec4);
+ivec2 outFunRet(in float, out ivec4, in int, out ivec4);
+
+void foo2()
+{
+ vec2 v2;
+ vec4 v4;
+ float f;
+ int i;
+
+ outFun(i, v2, i, f);
+ outFunRet(i, f, i, v4);
+ float ret = outFunRet(i, f, i, v4);
+ vec2 ret2 = outFunRet(i, v4, i, v4);
+}
diff --git a/Test/baseResults/120.vert.out b/Test/baseResults/120.vert.out
index a2063a0..df74e19 100644
--- a/Test/baseResults/120.vert.out
+++ b/Test/baseResults/120.vert.out
@@ -94,20 +94,25 @@
0:43 'gl_PointSize' (invariant gl_PointSize float)
0:43 Constant:
0:43 3.800000
+0:61 Function Definition: overloadB(f1;f1; (void)
+0:61 Function Parameters:
+0:61 '' (in float)
+0:61 '' (const (read only) float)
0:78 Function Definition: foo( (void)
0:78 Function Parameters:
0:? Sequence
-0:83 Function Call: overloadB(f1;f1; (2-component vector of float)
+0:83 Function Call: overloadB(f1;f1; (void)
0:83 'f' (float)
0:83 'f' (float)
-0:84 Function Call: overloadB(f1;f1; (2-component vector of float)
+0:84 Function Call: overloadB(f1;f1; (void)
0:84 'f' (float)
0:84 Constant:
-0:84 2 (const int)
-0:85 Function Call: overloadB(f1;f1; (2-component vector of float)
+0:84 2.000000
+0:85 Function Call: overloadB(f1;f1; (void)
0:85 Constant:
-0:85 1 (const int)
-0:85 'i' (int)
+0:85 1.000000
+0:85 Convert int to float (float)
+0:85 'i' (int)
0:87 Constant:
0:87 0.000000
0:88 Function Call: overloadC(i1;i1; (2-component vector of float)
@@ -125,8 +130,8 @@
0:90 0.000000
0:91 Function Call: overloadC(vf2;vf2; (2-component vector of float)
0:91 Constant:
-0:91 1 (const int)
-0:91 1 (const int)
+0:91 1.000000
+0:91 1.000000
0:91 Constant:
0:91 2.000000
0:91 2.000000
@@ -137,7 +142,8 @@
0:94 'f' (float)
0:94 'i' (int)
0:95 Function Call: overloadD(f1;i1; (3-component vector of float)
-0:95 'i' (int)
+0:95 Convert int to float (float)
+0:95 'i' (int)
0:95 'i' (int)
0:98 Constant:
0:98 0.000000
@@ -146,8 +152,8 @@
0:101 Function Call: texture2D(s21;vf2; (4-component vector of float)
0:101 's2D' (uniform sampler2D)
0:101 Constant:
-0:101 0 (const int)
-0:101 0 (const int)
+0:101 0.000000
+0:101 0.000000
0:102 clamp (4-component vector of float)
0:102 'attv4' (in 4-component vector of float)
0:102 Constant:
@@ -181,8 +187,8 @@
0:111 0.000000
0:112 Function Call: overloadE(vf2; (3-component vector of float)
0:112 Constant:
-0:112 1 (const int)
-0:112 1 (const int)
+0:112 1.000000
+0:112 1.000000
0:115 Function Call: overloadE(f1[2]; (3-component vector of float)
0:115 'b' (2-element array of float)
0:117 Constant:
@@ -190,6 +196,82 @@
0:118 Function Call: overloadF(i1; (3-component vector of float)
0:118 Constant:
0:118 1 (const int)
+0:128 Function Definition: foo2( (void)
+0:128 Function Parameters:
+0:? Sequence
+0:135 Comma (void)
+0:135 Function Call: outFun(f1;vi2;i1;f1; (void)
+0:135 Convert int to float (float)
+0:135 'i' (int)
+0:135 'tempArg' (out 2-component vector of int)
+0:135 'i' (int)
+0:135 'f' (float)
+0:135 move second child to first child (2-component vector of float)
+0:135 'v2' (2-component vector of float)
+0:135 Convert int to float (2-component vector of float)
+0:135 'tempArg' (out 2-component vector of int)
+0:136 Comma (int)
+0:136 move second child to first child (int)
+0:136 'tempReturn' (int)
+0:136 Function Call: outFunRet(f1;i1;i1;vi4; (int)
+0:136 Convert int to float (float)
+0:136 'i' (int)
+0:136 'tempArg' (out int)
+0:136 'i' (int)
+0:136 'tempArg' (out 4-component vector of int)
+0:136 move second child to first child (float)
+0:136 'f' (float)
+0:136 Convert int to float (float)
+0:136 'tempArg' (out int)
+0:136 move second child to first child (4-component vector of float)
+0:136 'v4' (4-component vector of float)
+0:136 Convert int to float (4-component vector of float)
+0:136 'tempArg' (out 4-component vector of int)
+0:136 'tempReturn' (int)
+0:137 Sequence
+0:137 move second child to first child (float)
+0:137 'ret' (float)
+0:137 Convert int to float (float)
+0:137 Comma (int)
+0:137 move second child to first child (int)
+0:137 'tempReturn' (int)
+0:137 Function Call: outFunRet(f1;i1;i1;vi4; (int)
+0:137 Convert int to float (float)
+0:137 'i' (int)
+0:137 'tempArg' (out int)
+0:137 'i' (int)
+0:137 'tempArg' (out 4-component vector of int)
+0:137 move second child to first child (float)
+0:137 'f' (float)
+0:137 Convert int to float (float)
+0:137 'tempArg' (out int)
+0:137 move second child to first child (4-component vector of float)
+0:137 'v4' (4-component vector of float)
+0:137 Convert int to float (4-component vector of float)
+0:137 'tempArg' (out 4-component vector of int)
+0:137 'tempReturn' (int)
+0:138 Sequence
+0:138 move second child to first child (2-component vector of float)
+0:138 'ret2' (2-component vector of float)
+0:138 Convert int to float (2-component vector of float)
+0:138 Comma (2-component vector of int)
+0:138 move second child to first child (2-component vector of int)
+0:138 'tempReturn' (2-component vector of int)
+0:138 Function Call: outFunRet(f1;vi4;i1;vi4; (2-component vector of int)
+0:138 Convert int to float (float)
+0:138 'i' (int)
+0:138 'tempArg' (out 4-component vector of int)
+0:138 'i' (int)
+0:138 'tempArg' (out 4-component vector of int)
+0:138 move second child to first child (4-component vector of float)
+0:138 'v4' (4-component vector of float)
+0:138 Convert int to float (4-component vector of float)
+0:138 'tempArg' (out 4-component vector of int)
+0:138 move second child to first child (4-component vector of float)
+0:138 'v4' (4-component vector of float)
+0:138 Convert int to float (4-component vector of float)
+0:138 'tempArg' (out 4-component vector of int)
+0:138 'tempReturn' (2-component vector of int)
0:? Linker Objects
0:? 'i' (in 4-component vector of float)
0:? 'o' (smooth out 4-component vector of float)
diff --git a/Test/baseResults/functionSemantics.frag.out b/Test/baseResults/functionSemantics.frag.out
index f164916..5ce38cb 100644
--- a/Test/baseResults/functionSemantics.frag.out
+++ b/Test/baseResults/functionSemantics.frag.out
@@ -1,122 +1,170 @@
../../LunarGLASS/test/functionSemantics.frag
+Warning, version 400 is not yet complete; some version-specific features are present, but many are missing.
0:? Sequence
-0:3 Function Definition: foo(i1;i1;i1;i1;i1;i1; (mediump int)
+0:3 Function Definition: foo(i1;i1;i1;i1;i1;i1; (int)
0:3 Function Parameters:
-0:3 'a' (in mediump int)
-0:3 'b' (const (read only) mediump int)
-0:3 'c' (in mediump int)
-0:3 'd' (const (read only) mediump int)
-0:3 'e' (out mediump int)
-0:3 'f' (inout mediump int)
+0:3 'a' (in int)
+0:3 'b' (const (read only) int)
+0:3 'c' (in int)
+0:3 'd' (const (read only) int)
+0:3 'e' (out int)
+0:3 'f' (inout int)
0:5 Sequence
0:5 Sequence
-0:5 move second child to first child (mediump int)
-0:5 'sum' (mediump int)
-0:5 add (mediump int)
-0:5 add (mediump int)
-0:5 add (mediump int)
-0:5 add (mediump int)
-0:5 'a' (in mediump int)
-0:5 'b' (const (read only) mediump int)
-0:5 'c' (in mediump int)
-0:5 'd' (const (read only) mediump int)
-0:5 'f' (inout mediump int)
-0:8 multiply second child into first child (mediump int)
-0:8 'a' (in mediump int)
+0:5 move second child to first child (int)
+0:5 'sum' (int)
+0:5 add (int)
+0:5 add (int)
+0:5 add (int)
+0:5 add (int)
+0:5 'a' (in int)
+0:5 'b' (const (read only) int)
+0:5 'c' (in int)
+0:5 'd' (const (read only) int)
+0:5 'f' (inout int)
+0:8 multiply second child into first child (int)
+0:8 'a' (in int)
0:8 Constant:
0:8 64 (const int)
-0:10 multiply second child into first child (mediump int)
-0:10 'c' (in mediump int)
+0:10 multiply second child into first child (int)
+0:10 'c' (in int)
0:10 Constant:
0:10 64 (const int)
-0:12 move second child to first child (mediump int)
-0:12 'e' (out mediump int)
+0:12 move second child to first child (int)
+0:12 'e' (out int)
0:12 Constant:
0:12 1024 (const int)
-0:13 multiply second child into first child (mediump int)
-0:13 'f' (inout mediump int)
+0:13 multiply second child into first child (int)
+0:13 'f' (inout int)
0:13 Constant:
0:13 64 (const int)
-0:15 add second child into first child (mediump int)
-0:15 'sum' (mediump int)
-0:15 add (mediump int)
-0:15 add (mediump int)
-0:15 add (mediump int)
-0:15 add (mediump int)
-0:15 add (mediump int)
-0:15 'a' (in mediump int)
-0:15 component-wise multiply (mediump int)
+0:15 add second child into first child (int)
+0:15 'sum' (int)
+0:15 add (int)
+0:15 add (int)
+0:15 add (int)
+0:15 add (int)
+0:15 add (int)
+0:15 'a' (in int)
+0:15 component-wise multiply (int)
0:15 Constant:
0:15 64 (const int)
-0:15 'b' (const (read only) mediump int)
-0:15 'c' (in mediump int)
-0:15 component-wise multiply (mediump int)
+0:15 'b' (const (read only) int)
+0:15 'c' (in int)
+0:15 component-wise multiply (int)
0:15 Constant:
0:15 64 (const int)
-0:15 'd' (const (read only) mediump int)
-0:15 'e' (out mediump int)
-0:15 'f' (inout mediump int)
+0:15 'd' (const (read only) int)
+0:15 'e' (out int)
+0:15 'f' (inout int)
0:18 Branch: Return with expression
-0:18 'sum' (mediump int)
-0:21 Function Definition: main( (void)
+0:18 'sum' (int)
+0:21 Function Definition: foo2(f1;vf3;i1; (int)
0:21 Function Parameters:
+0:21 'a' (in float)
+0:21 'b' (in 3-component vector of float)
+0:21 'r' (out int)
+0:23 Sequence
+0:23 move second child to first child (int)
+0:23 'r' (out int)
+0:23 Convert float to int (int)
+0:23 component-wise multiply (float)
+0:23 Constant:
+0:23 3.000000
+0:23 'a' (in float)
+0:24 Branch: Return with expression
+0:24 Convert float to int (int)
+0:24 component-wise multiply (float)
+0:24 Constant:
+0:24 5.000000
+0:24 direct index (float)
+0:24 'b' (in 3-component vector of float)
+0:24 Constant:
+0:24 1 (const int)
+0:27 Function Definition: main( (void)
+0:27 Function Parameters:
0:? Sequence
-0:24 Sequence
-0:24 move second child to first child (mediump int)
-0:24 't' (mediump int)
-0:24 Constant:
-0:24 2 (const int)
-0:28 move second child to first child (mediump int)
-0:28 direct index (mediump int)
-0:28 t: direct index for structure (mediump 4-component vector of int)
-0:28 'f' (structure{mediump 4-component vector of int t})
-0:28 Constant:
-0:28 0 (const int)
-0:28 Constant:
-0:28 1 (const int)
-0:28 Constant:
-0:28 32 (const int)
0:30 Sequence
-0:30 move second child to first child (mediump int)
-0:30 'color' (mediump int)
-0:30 Function Call: foo(i1;i1;i1;i1;i1;i1; (mediump int)
-0:30 Constant:
-0:30 1 (const int)
-0:30 Constant:
-0:30 2 (const int)
-0:30 add (mediump int)
-0:30 't' (mediump int)
-0:30 't' (mediump int)
-0:30 Constant:
-0:30 8 (const int)
-0:30 'e' (mediump int)
-0:30 direct index (mediump int)
-0:30 t: direct index for structure (mediump 4-component vector of int)
-0:30 'f' (structure{mediump 4-component vector of int t})
-0:30 Constant:
-0:30 0 (const int)
-0:30 Constant:
-0:30 1 (const int)
-0:32 add second child into first child (mediump int)
-0:32 'color' (mediump int)
-0:32 component-wise multiply (mediump int)
-0:32 Constant:
-0:32 128 (const int)
-0:32 add (mediump int)
-0:32 'e' (mediump int)
-0:32 direct index (mediump int)
-0:32 t: direct index for structure (mediump 4-component vector of int)
-0:32 'f' (structure{mediump 4-component vector of int t})
-0:32 Constant:
-0:32 0 (const int)
-0:32 Constant:
-0:32 1 (const int)
-0:35 move second child to first child (mediump 4-component vector of float)
-0:35 'gl_FragColor' (fragColor mediump 4-component vector of float)
-0:35 Construct vec4 (mediump 4-component vector of float)
-0:35 Convert int to float (mediump float)
-0:35 'color' (mediump int)
+0:30 move second child to first child (int)
+0:30 't' (int)
+0:30 Constant:
+0:30 2 (const int)
+0:34 move second child to first child (int)
+0:34 direct index (int)
+0:34 t: direct index for structure (4-component vector of int)
+0:34 'f' (structure{4-component vector of int t})
+0:34 Constant:
+0:34 0 (const int)
+0:34 Constant:
+0:34 1 (const int)
+0:34 Constant:
+0:34 32 (const int)
+0:37 Sequence
+0:37 move second child to first child (int)
+0:37 'color' (int)
+0:37 Function Call: foo(i1;i1;i1;i1;i1;i1; (int)
+0:37 Constant:
+0:37 1 (const int)
+0:37 Constant:
+0:37 2 (const int)
+0:37 add (int)
+0:37 't' (int)
+0:37 't' (int)
+0:37 Constant:
+0:37 8 (const int)
+0:37 'e' (int)
+0:37 direct index (int)
+0:37 t: direct index for structure (4-component vector of int)
+0:37 'f' (structure{4-component vector of int t})
+0:37 Constant:
+0:37 0 (const int)
+0:37 Constant:
+0:37 1 (const int)
+0:39 add second child into first child (int)
+0:39 'color' (int)
+0:39 component-wise multiply (int)
+0:39 Constant:
+0:39 128 (const int)
+0:39 add (int)
+0:39 'e' (int)
+0:39 direct index (int)
+0:39 t: direct index for structure (4-component vector of int)
+0:39 'f' (structure{4-component vector of int t})
+0:39 Constant:
+0:39 0 (const int)
+0:39 Constant:
+0:39 1 (const int)
+0:45 move second child to first child (float)
+0:45 'ret' (float)
+0:45 Convert int to float (float)
+0:45 Comma (int)
+0:45 move second child to first child (int)
+0:45 'tempReturn' (int)
+0:45 Function Call: foo2(f1;vf3;i1; (int)
+0:45 Constant:
+0:45 4.000000
+0:45 Constant:
+0:45 1.000000
+0:45 2.000000
+0:45 3.000000
+0:45 'tempArg' (out int)
+0:45 move second child to first child (float)
+0:45 'arg' (float)
+0:45 Convert int to float (float)
+0:45 'tempArg' (out int)
+0:45 'tempReturn' (int)
+0:46 add second child into first child (int)
+0:46 'color' (int)
+0:46 Convert float to int (int)
+0:46 add (float)
+0:46 'ret' (float)
+0:46 'arg' (float)
+0:48 move second child to first child (4-component vector of float)
+0:48 'gl_FragColor' (fragColor 4-component vector of float)
+0:48 Construct vec4 (4-component vector of float)
+0:48 Convert int to float (float)
+0:48 'color' (int)
0:? Linker Objects
diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h
index 93fa11a..1690df8 100644
--- a/glslang/Include/BaseTypes.h
+++ b/glslang/Include/BaseTypes.h
@@ -74,8 +74,7 @@
EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
EvqOut, // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter
EvqInOut,
-
- EvqConstReadOnly, // read-only types, not having a constant value or constant-value semantics
+ EvqConstReadOnly, // input; also other read-only types having neither a constant value nor constant-value semantics
// built-ins read by vertex shader
EvqVertexId,
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index ff9267c..b6caf50 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -238,9 +238,15 @@
public:
void clear()
{
- storage = EvqTemporary;
precision = EpqNone;
invariant = false;
+ makeTemporary();
+ }
+
+ // drop qualifiers that don't belong in a temporary variable
+ void makeTemporary()
+ {
+ storage = EvqTemporary;
centroid = false;
smooth = false;
flat = false;
@@ -255,6 +261,7 @@
writeonly = false;
clearLayout();
}
+
TStorageQualifier storage : 6;
TPrecisionQualifier precision : 3;
bool invariant : 1;
@@ -314,6 +321,29 @@
}
}
+ bool isParamInput() const
+ {
+ switch (storage) {
+ case EvqIn:
+ case EvqInOut:
+ case EvqConstReadOnly:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isParamOutput() const
+ {
+ switch (storage) {
+ case EvqOut:
+ case EvqInOut:
+ return true;
+ default:
+ return false;
+ }
+ }
+
bool isUniform() const
{
switch (storage) {
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 51a9144..66f8891 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -247,7 +247,7 @@
//
EOpConstructGuardStart,
- EOpConstructInt,
+ EOpConstructInt, // these first scalar forms also identify what implicit conversion is needed
EOpConstructUint,
EOpConstructBool,
EOpConstructFloat,
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 80c98f1..4224efd 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -67,6 +67,11 @@
return node;
}
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, TSourceLoc loc)
+{
+ return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), loc);
+}
+
//
// Connect two nodes with a new parent that does a binary operation on the nodes.
//
@@ -363,14 +368,16 @@
}
//
-// Convert one type to another.
+// Convert the node's type to the given type, as allowed by the operation involved 'op'.
+// For implicit conversions, 'op' is not the requested conversion, it is the explicit
+// operation requiring the implicit conversion.
//
// 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)
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
{
//
// Does the base type allow operation?
@@ -490,88 +497,86 @@
return 0;
}
- if (node->getAsConstantUnion()) {
-
+ if (node->getAsConstantUnion())
return promoteConstantUnion(promoteTo, node->getAsConstantUnion());
- } else {
- //
- // Add a new newNode for the conversion.
- //
- TIntermUnary* newNode = 0;
- TOperator newOp = EOpNull;
+ //
+ // Add a new newNode for the conversion.
+ //
+ TIntermUnary* newNode = 0;
- // 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 EbtUint: newOp = EOpConvUintToDouble; break;
- //case EbtBool: newOp = EOpConvBoolToDouble; break;
- //case EbtFloat: newOp = EOpConvFloatToDouble; break;
- //default:
- return 0;
- //}
- break;
- case EbtFloat:
- switch (node->getBasicType()) {
- case EbtInt: newOp = EOpConvIntToFloat; break;
- case EbtUint: newOp = EOpConvUintToFloat; break;
- case EbtBool: newOp = EOpConvBoolToFloat; break;
- case EbtDouble: newOp = EOpConvDoubleToFloat; break;
- default:
- return 0;
- }
- break;
- case EbtBool:
- switch (node->getBasicType()) {
- case EbtInt: newOp = EOpConvIntToBool; break;
- case EbtUint: newOp = EOpConvUintToBool; break;
- case EbtFloat: newOp = EOpConvFloatToBool; break;
- case EbtDouble: newOp = EOpConvDoubleToBool; break;
- default:
- return 0;
- }
- break;
- case EbtInt:
- switch (node->getBasicType()) {
- case EbtUint: newOp = EOpConvUintToInt; break;
- case EbtBool: newOp = EOpConvBoolToInt; break;
- case EbtFloat: newOp = EOpConvFloatToInt; break;
- case EbtDouble: newOp = EOpConvDoubleToInt; break;
- default:
- return 0;
- }
- break;
- case EbtUint:
- switch (node->getBasicType()) {
- case EbtInt: newOp = EOpConvIntToUint; break;
- case EbtBool: newOp = EOpConvBoolToUint; break;
- case EbtFloat: newOp = EOpConvFloatToUint; break;
- case EbtDouble: newOp = EOpConvDoubleToUint; break;
- default:
- return 0;
- }
- break;
- default:
+ 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 EbtUint: newOp = EOpConvUintToDouble; break;
+ //case EbtBool: newOp = EOpConvBoolToDouble; break;
+ //case EbtFloat: newOp = EOpConvFloatToDouble; break;
+ //default:
+ return 0;
+ //}
+ break;
+ case EbtFloat:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToFloat; break;
+ case EbtUint: newOp = EOpConvUintToFloat; break;
+ case EbtBool: newOp = EOpConvBoolToFloat; break;
+ case EbtDouble: newOp = EOpConvDoubleToFloat; break;
+ default:
return 0;
}
-
- TType type(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
- newNode = new TIntermUnary(newOp, type);
- newNode->setLoc(node->getLoc());
- newNode->setOperand(node);
-
- return newNode;
+ break;
+ case EbtBool:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToBool; break;
+ case EbtUint: newOp = EOpConvUintToBool; break;
+ case EbtFloat: newOp = EOpConvFloatToBool; break;
+ case EbtDouble: newOp = EOpConvDoubleToBool; break;
+ default:
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getBasicType()) {
+ case EbtUint: newOp = EOpConvUintToInt; break;
+ case EbtBool: newOp = EOpConvBoolToInt; break;
+ case EbtFloat: newOp = EOpConvFloatToInt; break;
+ case EbtDouble: newOp = EOpConvDoubleToInt; break;
+ default:
+ return 0;
+ }
+ break;
+ case EbtUint:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToUint; break;
+ case EbtBool: newOp = EOpConvBoolToUint; break;
+ case EbtFloat: newOp = EOpConvFloatToUint; break;
+ case EbtDouble: newOp = EOpConvDoubleToUint; break;
+ default:
+ return 0;
+ }
+ break;
+ default:
+ return 0;
}
+
+ TType newType(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
+ newNode = new TIntermUnary(newOp, newType);
+ newNode->setLoc(node->getLoc());
+ newNode->setOperand(node);
+
+ return newNode;
}
//
// 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)
+bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to) const
{
if (profile == EEsProfile || version == 110)
return false;
@@ -713,8 +718,7 @@
TIntermTyped *commaAggregate = growAggregate(left, right, loc);
commaAggregate->getAsAggregate()->setOperator(EOpComma);
commaAggregate->setType(right->getType());
- commaAggregate->getWritableType().getQualifier().storage = EvqTemporary;
- commaAggregate->getWritableType().getQualifier().precision = right->getType().getQualifier().precision;
+ commaAggregate->getWritableType().getQualifier().makeTemporary();
return commaAggregate;
}
@@ -782,7 +786,7 @@
// Returns the constant union node created.
//
-TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, TSourceLoc loc, bool literal)
+TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, TSourceLoc loc, bool literal) const
{
TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
node->setLoc(loc);
@@ -1028,7 +1032,7 @@
}
setType(operand->getType());
- getWritableType().getQualifier().storage = EvqTemporary;
+ getWritableType().getQualifier().makeTemporary();
return true;
}
@@ -1412,7 +1416,7 @@
}
}
-TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
{
const TConstUnionArray& rightUnionArray = node->getConstArray();
int size = node->getType().computeNumComponents();
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index aff1e62..35a126c 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -381,7 +381,7 @@
if (anon) {
// it was a member of an anonymous container, have to insert its dereference
const TVariable* variable = anon->getAnonContainer().getAsVariable();
- TIntermTyped* container = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
+ TIntermTyped* container = intermediate.addSymbol(*variable, loc);
TConstUnionArray unionArray(1);
unionArray[0].setUConst(anon->getMemberNumber());
TIntermTyped* constNode = intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc);
@@ -892,9 +892,7 @@
// Add the parameter to the HIL
paramNodes = intermediate.growAggregate(paramNodes,
- intermediate.addSymbol(variable->getUniqueId(),
- variable->getName(),
- variable->getType(), loc),
+ intermediate.addSymbol(*variable, loc),
loc);
}
} else
@@ -916,13 +914,13 @@
// - user function
// - subroutine call (not implemented yet)
//
-TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode)
+TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* function, TIntermNode* intermNode)
{
TIntermTyped* result = 0;
- TOperator op = fnCall->getBuiltInOp();
+ TOperator op = function->getBuiltInOp();
if (op == EOpArrayLength)
- result = handleLengthMethod(loc, fnCall, intermNode);
+ result = handleLengthMethod(loc, function, intermNode);
else if (op != EOpNull) {
//
// Then this should be a constructor.
@@ -930,7 +928,7 @@
// Their parameters will be verified algorithmically.
//
TType type(EbtVoid); // use this to get the type back
- if (! constructorError(loc, intermNode, *fnCall, op, type)) {
+ if (! constructorError(loc, intermNode, *function, op, type)) {
//
// It's a constructor, of type 'type'.
//
@@ -944,7 +942,7 @@
//
const TFunction* fnCandidate;
bool builtIn;
- fnCandidate = findFunction(loc, *fnCall, builtIn);
+ fnCandidate = findFunction(loc, *function, builtIn);
if (fnCandidate) {
// Error check for function requiring specific extensions present.
if (builtIn && fnCandidate->getNumExtensions())
@@ -966,30 +964,33 @@
} else {
// This is a function call not mapped to built-in operation
result = intermediate.setAggregateOperator(intermNode, EOpFunctionCall, fnCandidate->getType(), loc);
- result->getAsAggregate()->setName(fnCandidate->getMangledName());
+ TIntermAggregate* call = result->getAsAggregate();
+ call->setName(fnCandidate->getMangledName());
// this is how we know whether the given function is a built-in function or a user-defined function
// if builtIn == false, it's a userDefined -> could be an overloaded built-in function also
// if builtIn == true, it's definitely a built-in function with EOpNull
if (! builtIn) {
- result->getAsAggregate()->setUserDefined();
+ call->setUserDefined();
intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
}
// Make sure storage qualifications work for these arguments.
TStorageQualifier qual;
- TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
+ TQualifierList& qualifierList = call->getQualifierList();
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
qual = (*fnCandidate)[i].type->getQualifier().storage;
if (qual == EvqOut || qual == EvqInOut) {
- if (lValueErrorCheck(result->getLoc(), "assign", result->getAsAggregate()->getSequence()[i]->getAsTyped()))
+ if (lValueErrorCheck(call->getLoc(), "assign", call->getSequence()[i]->getAsTyped()))
error(intermNode->getLoc(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
}
qualifierList.push_back(qual);
}
+ result = handleArgumentConversions(*fnCandidate, *call);
+
if (builtIn)
- nonOpBuiltInCheck(loc, *fnCandidate, *result->getAsAggregate());
+ nonOpBuiltInCheck(loc, *fnCandidate, *call);
}
}
}
@@ -1007,14 +1008,14 @@
// Do all processing handling object.length().
// Return resulting tree node.
-TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode)
+TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* function, TIntermNode* intermNode)
{
int length = 0;
- if (fnCall->getParamCount() > 0)
- error(loc, "method does not accept any arguments", fnCall->getName().c_str(), "");
+ if (function->getParamCount() > 0)
+ error(loc, "method does not accept any arguments", function->getName().c_str(), "");
if (intermNode->getAsTyped() == 0 || ! intermNode->getAsTyped()->getType().isArray())
- error(loc, "", fnCall->getName().c_str(), "can only be applied to an array");
+ error(loc, "", function->getName().c_str(), "can only be applied to an array");
else if (intermNode->getAsTyped()->getType().getArraySize() == 0) {
bool implicitlySized = false;
if (intermNode->getAsSymbolNode() && isIoResizeArray(intermNode->getAsTyped()->getType())) {
@@ -1028,9 +1029,9 @@
}
if (length == 0) {
if (intermNode->getAsSymbolNode() && isIoResizeArray(intermNode->getAsTyped()->getType()))
- error(loc, "", fnCall->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
+ error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
else
- error(loc, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");
+ error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
}
} else
length = intermNode->getAsTyped()->getType().getArraySize();
@@ -1042,6 +1043,86 @@
return intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc);
}
+
+//
+// Add any needed implicit conversions for function-call arguments. This is
+// straightforward for input parameters, but output parameters need to
+// a different tree topology, complicated further by whether the function
+// has a return value. Create the new subtree, as neeeded.
+//
+// Returns a node of a subtree that evaluates to the return value of the function.
+//
+TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const
+{
+ TIntermSequence& arguments = intermNode.getSequence();
+
+ // Will there be any output conversions?
+ bool outputConversions = false;
+ for (int i = 0; i < function.getParamCount(); ++i) {
+ if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().storage == EvqOut) {
+ outputConversions = true;
+ break;
+ }
+ }
+
+ // Setup for the new tree, if needed:
+ //
+ // Output conversions need a different tree topology.
+ // Out-qualified arguments need a temporary of the correct type, with the call
+ // followed by an assignment of the temporary to the original argument:
+ // void: function(arg, ...) -> ( function(tempArg, ...), arg = tempArg, ...)
+ // ret = function(arg, ...) -> ret = (tempRet = function(tempArg, ...), arg = tempArg, ..., tempRet)
+ // Where the "tempArg" type needs no conversion as an argument, but will convert on assignment.
+ TIntermTyped* conversionTree = 0;
+ TVariable* tempRet = 0;
+ if (outputConversions) {
+ if (intermNode.getBasicType() != EbtVoid) {
+ // do the "tempRet = function(...), " bit from above
+ tempRet = makeInternalVariable("tempReturn", intermNode.getType());
+ TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+ conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, intermNode.getLoc());
+ } else
+ conversionTree = &intermNode;
+
+ conversionTree = intermediate.makeAggregate(conversionTree);
+ }
+
+ // Process each argument's conversion
+ for (int i = 0; i < function.getParamCount(); ++i) {
+ if (*function[i].type != arguments[i]->getAsTyped()->getType()) {
+ if (function[i].type->getQualifier().isParamInput()) {
+ // In-qualified arguments just need an extra node added above the argument to
+ // convert to the correct type.
+ arguments[i] = intermediate.addConversion(EOpAssign, *function[i].type, arguments[i]->getAsTyped());
+ } else if (function[i].type->getQualifier().isParamOutput()) {
+ // Out-qualified arguments need to use the topology set up above.
+ // do the " ...(tempArg, ...), arg = tempArg" bit from above
+ TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type);
+ tempArg->getWritableType().getQualifier().makeTemporary();
+ TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+ TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc());
+ conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc());
+ // replace the argument with another node for the same tempArg variable
+ arguments[i] = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+ }
+ }
+ }
+
+ // Done if no output conversions
+ if (! outputConversions)
+ return &intermNode;
+
+ // Otherwise, finalize the tree topology (see bigger comment above).
+ if (tempRet) {
+ // do the "..., tempRet" bit from above
+ TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+ conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, intermNode.getLoc());
+ }
+ conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc());
+
+ return conversionTree;
+}
+
//
// Do additional checking of built-in function calls that were not mapped
// to built-in operations (e.g., texturing functions).
@@ -1136,12 +1217,12 @@
}
//
-// Handle seeing a built-in-type constructor call in the grammar.
+// Handle seeing a built-in constructor in a grammar production.
//
-TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& publicType)
+TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, const TPublicType& publicType)
{
- publicType.qualifier.precision = EpqNone;
TType type(publicType);
+ type.getQualifier().precision = EpqNone;
if (type.isArray()) {
profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed constructor");
@@ -1151,10 +1232,9 @@
TOperator op = mapTypeToConstructorOp(type);
if (op == EOpNull) {
- error(loc, "cannot construct this type", TType::getBasicString(publicType.basicType), "");
+ error(loc, "cannot construct this type", type.getBasicString(), "");
op = EOpConstructFloat;
- publicType.basicType = EbtFloat;
- TType errorType(publicType);
+ TType errorType(EbtFloat);
type.shallowCopy(errorType);
}
@@ -1164,9 +1244,9 @@
}
//
-// Given a type, find what operation would construct it.
+// Given a type, find what operation would fully construct it.
//
-TOperator TParseContext::mapTypeToConstructorOp(const TType& type)
+TOperator TParseContext::mapTypeToConstructorOp(const TType& type) const
{
if (type.isStruct())
return EOpConstructStruct;
@@ -1335,9 +1415,7 @@
symbolTable.insert(*fakeVariable);
// substitute a symbol node for this new variable
- nodePtr = intermediate.addSymbol(fakeVariable->getUniqueId(),
- fakeVariable->getName(),
- fakeVariable->getType(), symbol->getLoc());
+ nodePtr = intermediate.addSymbol(*fakeVariable, symbol->getLoc());
} else {
switch (symbol->getQualifier().storage) {
case EvqPointCoord:
@@ -3340,12 +3418,11 @@
possibleMatch = false;
else {
// do direction-specific checks for conversion of basic type
- TStorageQualifier qualifier = function[i].type->getQualifier().storage;
- if (qualifier == EvqIn || qualifier == EvqInOut) {
+ if (function[i].type->getQualifier().isParamInput()) {
if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
possibleMatch = false;
}
- if (qualifier == EvqOut || qualifier == EvqInOut) {
+ if (function[i].type->getQualifier().isParamOutput()) {
if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
possibleMatch = false;
}
@@ -3472,6 +3549,22 @@
}
//
+// Make an internal-only variable whose name is for debug purposes only
+// and won't be searched for. Callers will only use the return value to use
+// the variable, not the name to look it up. It is okay if the name
+// is the same as other names; there won't be any conflict.
+//
+TVariable* TParseContext::makeInternalVariable(const char* name, const TType& type) const
+{
+ TString* nameString = new TString(name);
+ TSourceLoc loc = {0, 0};
+ TVariable* variable = new TVariable(nameString, type);
+ symbolTable.makeInternalVariable(*variable);
+
+ return variable;
+}
+
+//
// Declare a non-array variable, the main point being there is no redeclaration
// for resizing allowed.
//
@@ -3569,7 +3662,7 @@
variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
} else {
// normal assigning of a value to a variable...
- TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
+ TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
if (! initNode)
assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index 71338a5..f4a89ae 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -98,8 +98,9 @@
TIntermAggregate* handleFunctionDefinition(TSourceLoc, TFunction&);
TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*);
TIntermTyped* handleLengthMethod(TSourceLoc, TFunction*, TIntermNode*);
+ TIntermTyped* handleArgumentConversions(const TFunction&, TIntermAggregate&) const;
void nonOpBuiltInCheck(TSourceLoc, const TFunction&, TIntermAggregate&);
- TFunction* handleConstructorCall(TSourceLoc, TPublicType&);
+ TFunction* handleConstructorCall(TSourceLoc, const TPublicType&);
bool parseVectorFields(TSourceLoc, const TString&, int vecSize, TVectorFields&);
void assignError(TSourceLoc, const char* op, TString left, TString right);
@@ -205,11 +206,12 @@
protected:
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
void inheritGlobalDefaults(TQualifier& dst) const;
+ TVariable* makeInternalVariable(const char* name, const TType&) const;
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
TIntermTyped* convertInitializerList(TSourceLoc, const TType&, TIntermTyped* initializer);
- TOperator mapTypeToConstructorOp(const TType&);
+ TOperator mapTypeToConstructorOp(const TType&) const;
void finalErrorCheck();
public:
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index fd19c69..7d9afaf 100644
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -502,6 +502,12 @@
table.pop_back();
}
+ //
+ // Insert a visible symbol into the symbol table so it can
+ // be found later by name.
+ //
+ // Returns false if the was a name collision.
+ //
bool insert(TSymbol& symbol)
{
symbol.setUniqueId(++uniqueId);
@@ -524,6 +530,17 @@
}
//
+ // To allocate an internal temporary, which will need to be uniquely
+ // identified by the consumer of the AST, but never need to
+ // found by doing a symbol table search by name, hence allowed an
+ // arbitrary name in the symbol with no worry of collision.
+ //
+ void makeInternalVariable(TSymbol& symbol)
+ {
+ symbol.setUniqueId(++uniqueId);
+ }
+
+ //
// Copy a variable or anonymous member's structure from a shared level up
// to the current level, so it can be modified without impacting other users
// of the shared table.
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 9bb1709..7c91686 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -102,6 +102,7 @@
class TSymbolTable;
class TSymbol;
+class TVariable;
//
// Set of helper functions to help parse and build the tree.
@@ -133,13 +134,14 @@
bool isRecursive() const { return recursive; }
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc);
- TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+ TIntermSymbol* addSymbol(const TVariable&, TSourceLoc);
+ TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
TIntermTyped* addUnaryMath(TOperator, TIntermNode* child, TSourceLoc);
TIntermTyped* addBuiltInFunctionCall(TSourceLoc line, TOperator, bool unary, TIntermNode*, const TType& returnType);
- bool canImplicitlyPromote(TBasicType from, TBasicType to);
+ bool canImplicitlyPromote(TBasicType from, TBasicType to) const;
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc);
TIntermAggregate* makeAggregate(TIntermNode* node);
@@ -150,8 +152,8 @@
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
- TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc, bool literal = false);
- TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+ TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc, bool literal = false) const;
+ TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
TIntermBranch* addBranch(TOperator, TSourceLoc);