From f5dd2f5c7c30b16fe36136296aa530f885b47c12 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Wed, 26 Mar 2014 03:17:31 +0000 Subject: [PATCH] Expand implicit argument conversions to also include handling built-in function calls. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@26080 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Test/120.vert | 1 + Test/140.frag | 6 + Test/400.frag | 6 + Test/baseResults/120.vert.out | 22 +- Test/baseResults/140.frag.out | 43 ++- Test/baseResults/400.frag.out | 25 ++ Test/baseResults/functionSemantics.frag.out | 338 +++++++++++--------- glslang/MachineIndependent/Intermediate.cpp | 14 +- glslang/MachineIndependent/ParseHelper.cpp | 143 ++++++--- glslang/MachineIndependent/ParseHelper.h | 3 +- 10 files changed, 374 insertions(+), 227 deletions(-) diff --git a/Test/120.vert b/Test/120.vert index 8790980d..65e1a782 100644 --- a/Test/120.vert +++ b/Test/120.vert @@ -136,4 +136,5 @@ void foo2() outFunRet(i, f, i, v4); float ret = outFunRet(i, f, i, v4); vec2 ret2 = outFunRet(i, v4, i, v4); + bool b = any(lessThan(v4, attv4)); // tests aggregate arg to unary built-in } diff --git a/Test/140.frag b/Test/140.frag index a252c2d9..50fe3918 100644 --- a/Test/140.frag +++ b/Test/140.frag @@ -26,3 +26,9 @@ layout(location=3) in vec4 vl; // ERROR #extension GL_ARB_separate_shader_objects : enable layout(location=4) in vec4 vl2; + +void foo() +{ + vec2 r1 = modf(v.xy, v.zw); // ERROR, v.zw not l-value + vec2 r2 = modf(o.xy, o.zw); +} diff --git a/Test/400.frag b/Test/400.frag index 0d8bec2c..e0b14d7f 100644 --- a/Test/400.frag +++ b/Test/400.frag @@ -56,3 +56,9 @@ void foo23() patch in vec4 patchIn; // ERROR patch out vec4 patchOut; // ERROR + +void foo24() +{ + dvec3 df, di; + df = modf(outp.xyz, di); +} \ No newline at end of file diff --git a/Test/baseResults/120.vert.out b/Test/baseResults/120.vert.out index 2072007f..663e5946 100644 --- a/Test/baseResults/120.vert.out +++ b/Test/baseResults/120.vert.out @@ -148,7 +148,7 @@ ERROR: node is still EOpNull! 0:98 Constant: 0:98 0.000000 0:100 Constant: -0:100 0.000000 +0:100 0.841471 0:101 Function Call: texture2D(s21;vf2; (4-component vector of float) 0:101 's2D' (uniform sampler2D) 0:101 Constant: @@ -157,16 +157,17 @@ ERROR: node is still EOpNull! 0:102 clamp (4-component vector of float) 0:102 'attv4' (in 4-component vector of float) 0:102 Constant: -0:102 0 (const int) +0:102 0.000000 0:102 Constant: -0:102 1 (const int) +0:102 1.000000 0:103 clamp (4-component vector of float) -0:103 Convert float to int (4-component vector of int) -0:103 'attv4' (in 4-component vector of float) +0:103 Convert int to float (4-component vector of float) +0:103 Convert float to int (4-component vector of int) +0:103 'attv4' (in 4-component vector of float) 0:103 Constant: -0:103 0 (const int) +0:103 0.000000 0:103 Constant: -0:103 1 (const int) +0:103 1.000000 0:106 Constant: 0:106 0.000000 0:107 Constant: @@ -272,6 +273,13 @@ ERROR: node is still EOpNull! 0:138 Convert int to float (4-component vector of float) 0:138 'tempArg' (4-component vector of int) 0:138 'tempReturn' (2-component vector of int) +0:139 Sequence +0:139 move second child to first child (bool) +0:139 'b' (bool) +0:139 any (bool) +0:139 Compare Less Than (4-component vector of bool) +0:139 'v4' (4-component vector of float) +0:139 'attv4' (in 4-component vector of float) 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/140.frag.out b/Test/baseResults/140.frag.out index ba04a4eb..526c8b79 100644 --- a/Test/baseResults/140.frag.out +++ b/Test/baseResults/140.frag.out @@ -5,7 +5,9 @@ ERROR: 0:17: '#error' : GL_ES is not set ERROR: 0:20: 'fragment-shader struct input' : not supported for this version or the enabled extensions ERROR: 0:24: 'location' : not supported for this version or the enabled extensions ERROR: 0:24: 'location qualifier on input' : not supported for this version or the enabled extensions -ERROR: 4 compilation errors. No code generated. +ERROR: 0:32: 'assign' : l-value required "v" (can't modify shader input) +ERROR: 0:32: 'out' : Non-L-value cannot be passed for 'out' or 'inout' parameters. +ERROR: 6 compilation errors. No code generated. ERROR: node is still EOpNull! @@ -24,6 +26,45 @@ ERROR: node is still EOpNull! 0:22 'patch' (float) 0:22 Constant: 0:22 3.100000 +0:30 Function Definition: foo( (void) +0:30 Function Parameters: +0:32 Sequence +0:32 Sequence +0:32 move second child to first child (2-component vector of float) +0:32 'r1' (2-component vector of float) +0:32 modf (2-component vector of float) +0:32 vector swizzle (2-component vector of float) +0:32 'v' (smooth in 4-component vector of float) +0:32 Sequence +0:32 Constant: +0:32 0 (const int) +0:32 Constant: +0:32 1 (const int) +0:32 vector swizzle (2-component vector of float) +0:32 'v' (smooth in 4-component vector of float) +0:32 Sequence +0:32 Constant: +0:32 2 (const int) +0:32 Constant: +0:32 3 (const int) +0:33 Sequence +0:33 move second child to first child (2-component vector of float) +0:33 'r2' (2-component vector of float) +0:33 modf (2-component vector of float) +0:33 vector swizzle (2-component vector of float) +0:33 'o' (out 4-component vector of float) +0:33 Sequence +0:33 Constant: +0:33 0 (const int) +0:33 Constant: +0:33 1 (const int) +0:33 vector swizzle (2-component vector of float) +0:33 'o' (out 4-component vector of float) +0:33 Sequence +0:33 Constant: +0:33 2 (const int) +0:33 Constant: +0:33 3 (const int) 0:? Linker Objects 0:? 'v' (smooth in 4-component vector of float) 0:? 'i' (smooth in 4-component vector of float) diff --git a/Test/baseResults/400.frag.out b/Test/baseResults/400.frag.out index 889a0242..6e2de57e 100644 --- a/Test/baseResults/400.frag.out +++ b/Test/baseResults/400.frag.out @@ -190,6 +190,31 @@ ERROR: node is still EOpNull! 0:54 Constant: 0:54 -10 (const int) 0:54 20 (const int) +0:60 Function Definition: foo24( (void) +0:60 Function Parameters: +0:? Sequence +0:63 move second child to first child (3-component vector of double) +0:63 'df' (3-component vector of double) +0:63 Convert float to double (3-component vector of double) +0:63 Comma (3-component vector of float) +0:63 move second child to first child (3-component vector of float) +0:63 'tempReturn' (3-component vector of float) +0:63 modf (3-component vector of float) +0:63 vector swizzle (3-component vector of float) +0:63 'outp' (out 4-component vector of float) +0:63 Sequence +0:63 Constant: +0:63 0 (const int) +0:63 Constant: +0:63 1 (const int) +0:63 Constant: +0:63 2 (const int) +0:63 'tempArg' (3-component vector of float) +0:63 move second child to first child (3-component vector of double) +0:63 'di' (3-component vector of double) +0:63 Convert float to double (3-component vector of double) +0:63 'tempArg' (3-component vector of float) +0:63 'tempReturn' (3-component vector of float) 0:? Linker Objects 0:? 'c2D' (smooth in 2-component vector of float) 0:? 'i' (flat in int) diff --git a/Test/baseResults/functionSemantics.frag.out b/Test/baseResults/functionSemantics.frag.out index 4bebc596..4780bf87 100644 --- a/Test/baseResults/functionSemantics.frag.out +++ b/Test/baseResults/functionSemantics.frag.out @@ -2,170 +2,192 @@ 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; (int) -0:3 Function Parameters: -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 (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:5 Function Definition: foo(i1;i1;i1;i1;i1;i1; (int) +0:5 Function Parameters: +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 'e' (out int) +0:5 'f' (inout int) +0:7 Sequence +0:7 Sequence +0:7 move second child to first child (int) +0:7 'sum' (int) +0:7 add (int) +0:7 add (int) +0:7 add (int) +0:7 add (int) +0:7 'a' (in int) +0:7 'b' (const (read only) int) +0:7 'c' (in int) +0:7 'd' (const (read only) int) +0:7 'f' (inout int) 0:10 multiply second child into first child (int) -0:10 'c' (in int) +0:10 'a' (in int) 0:10 Constant: 0:10 64 (const int) -0:12 move second child to first child (int) -0:12 'e' (out int) +0:12 multiply second child into first child (int) +0:12 'c' (in int) 0:12 Constant: -0:12 1024 (const 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 (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) 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) int) -0:15 'e' (out int) -0:15 'f' (inout int) -0:18 Branch: Return with expression -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:12 64 (const int) +0:14 move second child to first child (int) +0:14 'e' (out int) +0:14 Constant: +0:14 1024 (const int) +0:15 multiply second child into first child (int) +0:15 'f' (inout int) +0:15 Constant: +0:15 64 (const int) +0:17 add second child into first child (int) +0:17 'sum' (int) +0:17 add (int) +0:17 add (int) +0:17 add (int) +0:17 add (int) +0:17 add (int) +0:17 'a' (in int) +0:17 component-wise multiply (int) +0:17 Constant: +0:17 64 (const int) +0:17 'b' (const (read only) int) +0:17 'c' (in int) +0:17 component-wise multiply (int) +0:17 Constant: +0:17 64 (const int) +0:17 'd' (const (read only) int) +0:17 'e' (out int) +0:17 'f' (inout int) +0:20 Branch: Return with expression +0:20 'sum' (int) +0:23 Function Definition: foo2(f1;vf3;i1; (int) +0:23 Function Parameters: +0:23 'a' (in float) +0:23 'b' (in 3-component vector of float) +0:23 'r' (out int) +0:25 Sequence +0:25 move second child to first child (int) +0:25 'r' (out int) +0:25 Convert float to int (int) +0:25 component-wise multiply (float) +0:25 Constant: +0:25 3.000000 +0:25 'a' (in float) +0:26 Branch: Return with expression +0:26 Convert float to int (int) +0:26 component-wise multiply (float) +0:26 Constant: +0:26 5.000000 +0:26 direct index (float) +0:26 'b' (in 3-component vector of float) +0:26 Constant: +0:26 1 (const int) +0:29 Function Definition: foo3( (int) +0:29 Function Parameters: +0:31 Sequence +0:31 Test condition and select (void) +0:31 Condition +0:31 Compare Greater Than (bool) +0:31 'u' (uniform float) +0:31 Constant: +0:31 3.200000 +0:31 true case +0:32 Sequence +0:32 Branch: Kill +0:33 Branch: Return with expression +0:33 Constant: +0:33 1000000 (const int) +0:36 Branch: Return with expression +0:36 Constant: +0:36 2000000 (const int) +0:39 Function Definition: main( (void) +0:39 Function Parameters: 0:? Sequence -0:30 Sequence -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' (int) -0:45 move second child to first child (float) -0:45 'arg' (float) -0:45 Convert int to float (float) -0:45 'tempArg' (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:42 Sequence +0:42 move second child to first child (int) +0:42 't' (int) +0:42 Constant: +0:42 2 (const int) +0:46 move second child to first child (int) +0:46 direct index (int) +0:46 t: direct index for structure (4-component vector of int) +0:46 'f' (structure{4-component vector of int t}) +0:46 Constant: +0:46 0 (const int) +0:46 Constant: +0:46 1 (const int) +0:46 Constant: +0:46 32 (const int) +0:49 Sequence +0:49 move second child to first child (int) +0:49 'color' (int) +0:49 Function Call: foo(i1;i1;i1;i1;i1;i1; (int) +0:49 Constant: +0:49 1 (const int) +0:49 Constant: +0:49 2 (const int) +0:49 add (int) +0:49 't' (int) +0:49 't' (int) +0:49 Constant: +0:49 8 (const int) +0:49 'e' (int) +0:49 direct index (int) +0:49 t: direct index for structure (4-component vector of int) +0:49 'f' (structure{4-component vector of int t}) +0:49 Constant: +0:49 0 (const int) +0:49 Constant: +0:49 1 (const int) +0:51 add second child into first child (int) +0:51 'color' (int) +0:51 component-wise multiply (int) +0:51 Constant: +0:51 128 (const int) +0:51 add (int) +0:51 'e' (int) +0:51 direct index (int) +0:51 t: direct index for structure (4-component vector of int) +0:51 'f' (structure{4-component vector of int t}) +0:51 Constant: +0:51 0 (const int) +0:51 Constant: +0:51 1 (const int) +0:57 move second child to first child (float) +0:57 'ret' (float) +0:57 Convert int to float (float) +0:57 Comma (int) +0:57 move second child to first child (int) +0:57 'tempReturn' (int) +0:57 Function Call: foo2(f1;vf3;i1; (int) +0:57 Constant: +0:57 4.000000 +0:57 Constant: +0:57 1.000000 +0:57 2.000000 +0:57 3.000000 +0:57 'tempArg' (int) +0:57 move second child to first child (float) +0:57 'arg' (float) +0:57 Convert int to float (float) +0:57 'tempArg' (int) +0:57 'tempReturn' (int) +0:58 add second child into first child (int) +0:58 'color' (int) +0:58 Convert float to int (int) +0:58 add (float) +0:58 'ret' (float) +0:58 'arg' (float) +0:60 add second child into first child (int) +0:60 'color' (int) +0:60 Function Call: foo3( (int) +0:62 move second child to first child (4-component vector of float) +0:62 'gl_FragColor' (fragColor 4-component vector of float) +0:62 Construct vec4 (4-component vector of float) +0:62 Convert int to float (float) +0:62 'color' (int) 0:? Linker Objects +0:? 'u' (uniform float) Linked fragment stage: diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 4224efd0..5195a0b7 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -511,14 +511,14 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt // 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: + 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()) { diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 35a126c9..97c8c127 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -914,13 +914,13 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct // - user function // - subroutine call (not implemented yet) // -TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* function, TIntermNode* intermNode) +TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* function, TIntermNode* arguments) { TIntermTyped* result = 0; TOperator op = function->getBuiltInOp(); if (op == EOpArrayLength) - result = handleLengthMethod(loc, function, intermNode); + result = handleLengthMethod(loc, function, arguments); else if (op != EOpNull) { // // Then this should be a constructor. @@ -928,11 +928,11 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct // Their parameters will be verified algorithmically. // TType type(EbtVoid); // use this to get the type back - if (! constructorError(loc, intermNode, *function, op, type)) { + if (! constructorError(loc, arguments, *function, op, type)) { // // It's a constructor, of type 'type'. // - result = addConstructor(loc, intermNode, type, op); + result = addConstructor(loc, arguments, type, op); if (result == 0) error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); } @@ -944,26 +944,46 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct bool builtIn; fnCandidate = findFunction(loc, *function, builtIn); if (fnCandidate) { - // Error check for function requiring specific extensions present. + // This is a declared function that might map to + // - a built-in operator, + // - a built-in function not mapped to an operator, or + // - a user function. + + // Error check for a function requiring specific extensions present. if (builtIn && fnCandidate->getNumExtensions()) requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str()); - // - // A declared function. But, it might still map to a built-in - // operation. - // + if (arguments) { + // Make sure storage qualifications work for these arguments. + TIntermAggregate* aggregate = arguments->getAsAggregate(); + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage; + if (qual == EvqOut || qual == EvqInOut) { + // At this early point there is a slight ambiguity between whether an aggregate 'arguments' + // is the single argument itself or its children are the arguments. Only one argument + // means take 'arguments' itself as the one argument. + TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments); + if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped())) + error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", ""); + } + } + + // Convert 'in' arguments + addInputArgumentConversions(*fnCandidate, arguments); // arguments may be modified if it's just a single argument node + } + op = fnCandidate->getBuiltInOp(); if (builtIn && op != EOpNull) { // A function call mapped to a built-in operation. - result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getType()); + result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType()); if (result == 0) { - error(intermNode->getLoc(), " wrong operand type", "Internal Error", + error(arguments->getLoc(), " wrong operand type", "Internal Error", "built in unary operator function. Type: %s", - static_cast(intermNode)->getCompleteString().c_str()); + static_cast(arguments)->getCompleteString().c_str()); } } else { - // This is a function call not mapped to built-in operation - result = intermediate.setAggregateOperator(intermNode, EOpFunctionCall, fnCandidate->getType(), loc); + // This is a function call not mapped to built-in operator, but it could still be a built-in function + result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc); TIntermAggregate* call = result->getAsAggregate(); call->setName(fnCandidate->getMangledName()); @@ -975,23 +995,21 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName()); } - // Make sure storage qualifications work for these arguments. - TStorageQualifier qual; - 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(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, *call); } + + // Convert 'out' arguments. If it was a constant folded built-in, it won't be an aggregate anymore. + // Built-ins with a single argument aren't called with an aggregate, but they also don't have an output. + // Also, build the qualifier list for user function calls, which are always called with an aggregate. + if (result->getAsAggregate()) { + TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList(); + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage; + qualifierList.push_back(qual); + } + result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate()); + } } } @@ -1045,14 +1063,40 @@ TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* funct } // -// 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. +// Add any needed implicit conversions for function-call arguments to input parameters. +// +void TParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const +{ + TIntermAggregate* aggregate = arguments->getAsAggregate(); + + // Process each argument's conversion + for (int i = 0; i < function.getParamCount(); ++i) { + // At this early point there is a slight ambiguity between whether an aggregate 'arguments' + // is the single argument itself or its children are the arguments. Only one argument + // means take 'arguments' itself as the one argument. + TIntermTyped* arg = function.getParamCount() == 1 ? arguments->getAsTyped() : (aggregate ? aggregate->getSequence()[i]->getAsTyped() : arguments->getAsTyped()); + if (*function[i].type != arg->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. + arg = intermediate.addConversion(EOpAssign, *function[i].type, arg); + if (aggregate) + aggregate->getSequence()[i] = arg; + else + arguments = arg; + } + } + } +} + +// +// Add any needed implicit output conversions for function-call arguments. This +// can require a new tree topology, complicated further by whether the function +// has a return value. // // Returns a node of a subtree that evaluates to the return value of the function. // -TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const +TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const { TIntermSequence& arguments = intermNode.getSequence(); @@ -1065,6 +1109,9 @@ TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function } } + if (! outputConversions) + return &intermNode; + // Setup for the new tree, if needed: // // Output conversions need a different tree topology. @@ -1075,26 +1122,20 @@ TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function // 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; + 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); - } + 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()) { + 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); @@ -1108,11 +1149,7 @@ TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function } } - // Done if no output conversions - if (! outputConversions) - return &intermNode; - - // Otherwise, finalize the tree topology (see bigger comment above). + // Finalize the tree topology (see bigger comment above). if (tempRet) { // do the "..., tempRet" bit from above TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc()); diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index f4a89aeb..ef24c4bd 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -98,7 +98,8 @@ public: TIntermAggregate* handleFunctionDefinition(TSourceLoc, TFunction&); TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*); TIntermTyped* handleLengthMethod(TSourceLoc, TFunction*, TIntermNode*); - TIntermTyped* handleArgumentConversions(const TFunction&, TIntermAggregate&) const; + void addInputArgumentConversions(const TFunction&, TIntermNode*&) const; + TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; void nonOpBuiltInCheck(TSourceLoc, const TFunction&, TIntermAggregate&); TFunction* handleConstructorCall(TSourceLoc, const TPublicType&);