Implement 1.20 style function signature matching under implicit conversion. This was the last key unimplemented feature of versions 120 through 330.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23798 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-30 23:17:34 +00:00
parent 8cbd18ecaa
commit 0d22e31c75
36 changed files with 323 additions and 65 deletions

View File

@ -51,3 +51,62 @@ int[2][3] foo( // ERROR
float[2][3] a, // ERROR
float[2] b[3], // ERROR
float c[2][3]); // ERROR
int overloadA(in float f);
int overloadA(out float f); // ERROR, different qualifiers
float overloadA(float); // ERROR, different return value for same signature
float overloadA(out float f, int);
float overloadA(int i);
vec2 overloadB(float, float);
vec2 overloadC(int, int);
vec2 overloadC(int, float);
vec2 overloadC(float, int);
vec2 overloadC(vec2, vec2);
vec3 overloadD(int, float);
vec3 overloadD(float, int);
vec3 overloadE(float[2]);
vec3 overloadE(mat2 m);
vec3 overloadE(vec2 v);
void foo()
{
float f;
int i;
overloadB(f, f);
overloadB(f, 2);
overloadB(1, i);
overloadC(1, i);
overloadC(vec2(1), vec2(2));
overloadC(f, 3.0); // ERROR, no way
overloadC(ivec2(1), vec2(2));
overloadD(i, f);
overloadD(f, i);
overloadD(i, i); // ERROR, ambiguous
int overloadB; // hiding
overloadB(1, i); // ERROR
sin(1);
texture2D(s2D, ivec2(0));
clamp(attv4, 0, 1);
clamp(ivec4(attv4), 0, 1);
int a[2];
overloadC(a, 3); // ERROR
overloadE(a); // ERROR
overloadE(3.3); // ERROR
overloadE(vec2(3.3));
overloadE(mat2(0.5));
overloadE(ivec4(1)); // ERROR
overloadE(ivec2(1));
float b[2];
overloadE(b);
}

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
ERROR: 0:9: 'in for stage inputs' : not supported for this version or the enabled extensions
ERROR: 0:10: 'out for stage outputs' : not supported for this version or the enabled extensions
ERROR: 0:54: '+' : wrong operand types: no operation '+' exists that takes a left-hand operand of type '2-component vector of float' and a right operand of type '3-component vector of float' (or there is no acceptable conversion)

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
ERROR: 0:3: 'in for stage inputs' : not supported for this version or the enabled extensions
ERROR: 0:4: 'out for stage outputs' : not supported for this version or the enabled extensions
ERROR: 0:11: 'gl_Position' : cannot add storage, auxiliary, memory, interpolation, or precision qualifier to an existing variable
@ -33,7 +32,15 @@ ERROR: 0:50: 'arrays of arrays' : not supported with this profile: none
ERROR: 0:51: 'arrays of arrays' : not supported with this profile: none
ERROR: 0:52: 'arrays of arrays' : not supported with this profile: none
ERROR: 0:53: 'arrays of arrays' : not supported with this profile: none
ERROR: 34 compilation errors. No code generated.
ERROR: 0:56: 'out' : overloaded functions must have the same parameter qualifiers
ERROR: 0:57: 'float' : overloaded functions must have the same return type
ERROR: 0:86: 'overloadC' : no matching overloaded function found
ERROR: 0:91: 'overloadD' : ambiguous function signature match: multiple signatures match under implicit type conversion
ERROR: 0:102: 'overloadC' : no matching overloaded function found
ERROR: 0:103: 'overloadE' : no matching overloaded function found
ERROR: 0:104: 'overloadE' : no matching overloaded function found
ERROR: 0:107: 'overloadE' : no matching overloaded function found
ERROR: 42 compilation errors. No code generated.
ERROR: node is still EOpNull!
0:15 Function Definition: main( (void)
@ -81,6 +88,97 @@ ERROR: node is still EOpNull!
0:43 'gl_PointSize' (invariant gl_PointSize float)
0:43 Constant:
0:43 3.800000
0:75 Function Definition: foo( (void)
0:75 Function Parameters:
0:? Sequence
0:80 Function Call: overloadB(f1;f1; (2-component vector of float)
0:80 'f' (float)
0:80 'f' (float)
0:81 Function Call: overloadB(f1;f1; (2-component vector of float)
0:81 'f' (float)
0:81 Constant:
0:81 2 (const int)
0:82 Function Call: overloadB(f1;f1; (2-component vector of float)
0:82 Constant:
0:82 1 (const int)
0:82 'i' (int)
0:84 Function Call: overloadC(i1;i1; (2-component vector of float)
0:84 Constant:
0:84 1 (const int)
0:84 'i' (int)
0:85 Function Call: overloadC(vf2;vf2; (2-component vector of float)
0:85 Constant:
0:85 1.000000
0:85 1.000000
0:85 Constant:
0:85 2.000000
0:85 2.000000
0:86 Constant:
0:86 0.000000
0:87 Function Call: overloadC(vf2;vf2; (2-component vector of float)
0:87 Constant:
0:87 1 (const int)
0:87 1 (const int)
0:87 Constant:
0:87 2.000000
0:87 2.000000
0:89 Function Call: overloadD(i1;f1; (3-component vector of float)
0:89 'i' (int)
0:89 'f' (float)
0:90 Function Call: overloadD(f1;i1; (3-component vector of float)
0:90 'f' (float)
0:90 'i' (int)
0:91 Function Call: overloadD(f1;i1; (3-component vector of float)
0:91 'i' (int)
0:91 'i' (int)
0:94 Function Call: overloadB(f1;f1; (2-component vector of float)
0:94 Constant:
0:94 1 (const int)
0:94 'i' (int)
0:96 Constant:
0:96 0.000000
0:97 Function Call: texture2D(s21;vf2; (4-component vector of float)
0:97 's2D' (uniform sampler2D)
0:97 Constant:
0:97 0 (const int)
0:97 0 (const int)
0:98 clamp (4-component vector of float)
0:98 'attv4' (in 4-component vector of float)
0:98 Constant:
0:98 0 (const int)
0:98 Constant:
0:98 1 (const int)
0:99 clamp (4-component vector of float)
0:99 Convert float to int (4-component vector of int)
0:99 'attv4' (in 4-component vector of float)
0:99 Constant:
0:99 0 (const int)
0:99 Constant:
0:99 1 (const int)
0:102 Constant:
0:102 0.000000
0:103 Constant:
0:103 0.000000
0:104 Constant:
0:104 0.000000
0:105 Function Call: overloadE(vf2; (3-component vector of float)
0:105 Constant:
0:105 3.300000
0:105 3.300000
0:106 Function Call: overloadE(mf22; (3-component vector of float)
0:106 Constant:
0:106 0.500000
0:106 0.000000
0:106 0.000000
0:106 0.500000
0:107 Constant:
0:107 0.000000
0:108 Function Call: overloadE(vf2; (3-component vector of float)
0:108 Constant:
0:108 1 (const int)
0:108 1 (const int)
0:111 Function Call: overloadE(f1[2]; (3-component vector of float)
0:111 'b' (2-element array of float)
0:? Linker Objects
0:? 'i' (in 4-component vector of float)
0:? 'o' (smooth out 4-component vector of float)

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:4 Function Definition: main( (void)
0:4 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:4 Function Definition: main( (void)
0:4 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:6 Function Definition: main( (void)
0:6 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:5 Sequence
0:5 move second child to first child (float)

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:5 Sequence
0:5 move second child to first child (float)

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
ERROR: 0:77: '#error' : good1
ERROR: 0:81: '#error' : good2
ERROR: 0:85: '#error' : good3

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
ERROR: 0:19: 'vi4' : illegal use of type 'void'
ERROR: 0:20: 'vj' : illegal use of type 'void'
ERROR: 0:20: 'vk5' : illegal use of type 'void'

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:5 Sequence
0:5 move second child to first child (4-component vector of float)

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:4 Function Definition: main( (void)
0:4 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:7 Function Definition: main( (void)
0:7 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:19 Function Definition: main( (void)
0:19 Function Parameters:

View File

@ -11,7 +11,6 @@ WARNING: #version: statement missing; use #version on first line of shader
0:? Linker Objects
empty3.frag
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:? Linker Objects

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:10 Function Definition: main( (void)
0:10 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:8 Function Definition: main( (void)
0:8 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:11 Function Definition: main( (void)
0:11 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:11 Function Definition: main( (void)
0:11 Function Parameters:

View File

@ -1,5 +1,4 @@
mains1.frag
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:3 Function Definition: main( (void)
@ -7,7 +6,6 @@ Warning, version 110 is not yet complete; most features are present, but a few a
0:? Linker Objects
mains2.frag
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:3 Function Definition: main( (void)

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
ERROR: 0:10: 'constructor' : too many arguments
ERROR: 0:7: 'const' : non-matching or non-convertible constant type for const initializer
ERROR: 0:17: 'assign' : cannot convert from '2-component vector of float' to '3-component vector of float'

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:15 Function Definition: main( (void)
0:15 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:38 Function Definition: main( (void)
0:38 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:38 Function Definition: main( (void)
0:38 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:9 Function Definition: main( (void)
0:9 Function Parameters:

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
ERROR: 0:9: 'vec5' : undeclared identifier
ERROR: 0:9: '' : syntax error
ERROR: 2 compilation errors. No code generated.

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:13 Function Definition: main( (void)
0:13 Function Parameters:

View File

@ -1,5 +1,4 @@
ERROR: #version: versions before 150 do not allow a profile token
Warning, version 110 is not yet complete; most features are present, but a few are missing.
ERROR: 0:38: 'attribute' : not supported in this stage: fragment
ERROR: 0:40: 'sampler2DRect' : Reserved word.
ERROR: 0:40: 'rectangle texture' : not supported for this version or the enabled extensions

View File

@ -1,4 +1,3 @@
Warning, version 120 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:7 Sequence
0:7 move second child to first child (float)

View File

@ -1,4 +1,3 @@
Warning, version 110 is not yet complete; most features are present, but a few are missing.
0:? Sequence
0:7 Function Definition: main( (void)
0:7 Function Parameters:

View File

@ -57,7 +57,7 @@ Shader Functionality to Implement/Finish
GLSL 1.2
+ Handle multiple compilation units per stage
+ Allow initializers on uniform declarations
- signature matching takes type conversions into account, ambiguity is an error
+ signature matching takes type conversions into account, ambiguity is an error
- allow constructors to contain non-dereferenced arrays?
GLSL 1.3
. flat is for both user and predeclared built-in in/out variables

View File

@ -846,20 +846,30 @@ public:
// See if two types match, in all aspects except arrayness
bool sameElementType(const TType& right) const
{
return basicType == right.basicType &&
sampler == right.sampler &&
return basicType == right.basicType && sameElementShape(right);
}
// See if two type's arrayness match
bool sameArrayness(const TType& right) const
{
return ((arraySizes == 0 && right.arraySizes == 0) ||
(arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
}
// See if two type's elements match in all ways except basic type
bool sameElementShape(const TType& right) const
{
return sampler == right.sampler &&
vectorSize == right.vectorSize &&
matrixCols == right.matrixCols &&
matrixRows == right.matrixRows &&
sameStructType(right);
}
// See if two types match in all ways (just the actual type, not qualification
// See if two types match in all ways (just the actual type, not qualification)
bool operator==(const TType& right) const
{
return sameElementType(right) &&
((arraySizes == 0 && right.arraySizes == 0) ||
(arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
return sameElementType(right) && sameArrayness(right);
}
bool operator!=(const TType& right) const

View File

@ -829,7 +829,13 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
}
//
// Handle seeing a function call in the grammar.
// Handle seeing function call syntax in the grammar, which could be any of
// - .length() method
// - constructor
// - a call to a built-in function mapped to an operator
// - a call to a built-in function that will remain a function call (e.g., texturing)
// - user function
// - subroutine call (not implemented yet)
//
TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode, TIntermAggregate* intermAggregate)
{
@ -866,11 +872,11 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
}
} else {
//
// Not a constructor. Find it in the symbol table.
// Find it in the symbol table.
//
const TFunction* fnCandidate;
bool builtIn;
fnCandidate = findFunction(loc, fnCall, &builtIn);
fnCandidate = findFunction(loc, *fnCall, builtIn);
if (fnCandidate) {
//
// A declared function. But, it might still map to a built-in
@ -898,6 +904,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
}
// Make sure storage qualifications work for these arguments.
TStorageQualifier qual;
TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
@ -912,12 +919,6 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
if (builtIn)
nonOpBuiltInCheck(loc, *fnCandidate, result->getAsAggregate());
}
} else {
// error message was put out by PaFindFunction()
// Put on a dummy node for error recovery
TConstUnionArray unionArray(1);
unionArray[0].setDConst(0.0);
result = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), loc);
}
}
@ -2543,26 +2544,107 @@ void TParseContext::checkNoShaderLayouts(TSourceLoc loc, const TPublicType& publ
//
// Return the function symbol if found, otherwise 0.
//
const TFunction* TParseContext::findFunction(TSourceLoc loc, TFunction* call, bool *builtIn)
const TFunction* TParseContext::findFunction(TSourceLoc loc, const TFunction& call, bool& builtIn)
{
TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn);
const TFunction* function = 0;
if (symbol == 0) {
error(loc, "no matching overloaded function found", call->getName().c_str(), "");
return 0;
}
const TFunction* function = symbol->getAsFunction();
if (! function) {
error(loc, "function name expected", call->getName().c_str(), "");
return 0;
}
if (profile == EEsProfile || version < 120)
function = findFunctionExact(loc, call, builtIn);
else if (version < 400)
function = findFunction120(loc, call, builtIn);
else
function = findFunction400(loc, call, builtIn);
return function;
}
// Function finding algorithm for ES and desktop 110.
const TFunction* TParseContext::findFunctionExact(TSourceLoc loc, const TFunction& call, bool& builtIn)
{
const TFunction* function = 0;
TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
if (symbol == 0) {
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
return 0;
}
return symbol->getAsFunction();
}
// Function finding algorithm for desktop versions 120 through 330.
const TFunction* TParseContext::findFunction120(TSourceLoc loc, const TFunction& call, bool& builtIn)
{
// first, look for an exact match
TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
if (symbol)
return symbol->getAsFunction();
// exact match not found, look through a list of overloaded functions of the same name
// "If no exact match is found, then [implicit conversions] will be applied to find a match. Mismatched types
// on input parameters (in or inout or default) must have a conversion from the calling argument type to the
// formal parameter type. Mismatched types on output parameters (out or inout) must have a conversion
// from the formal parameter type to the calling argument type. When argument conversions are used to find
// a match, it is a semantic error if there are multiple ways to apply these conversions to make the call match
// more than one function."
const TFunction* candidate = 0;
TVector<TFunction*> candidateList;
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
int numPossibleMatches = 0;
for (TVector<TFunction*>::const_iterator it = candidateList.begin(); it != candidateList.end(); ++it) {
bool possibleMatch = true;
const TFunction& function = *(*it);
for (int i = 0; i < function.getParamCount(); ++i) {
// same types is easy
if (*function[i].type == *call[i].type)
continue;
// We have a mismatch in type, see if it is implicitly convertible
if (function[i].type->isArray() || call[i].type->isArray() ||
! function[i].type->sameElementShape(*call[i].type))
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 (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
possibleMatch = false;
}
if (qualifier == EvqOut || qualifier == EvqInOut) {
if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
possibleMatch = false;
}
}
if (! possibleMatch)
break;
}
if (possibleMatch) {
if (candidate) {
// our second match, meaning ambiguity
error(loc, "ambiguous function signature match: multiple signatures match under implicit type conversion", call.getName().c_str(), "");
} else
candidate = &function;
}
}
if (candidate == 0)
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
return candidate;
}
// Function finding algorithm for desktop version 400 and above.
const TFunction* TParseContext::findFunction400(TSourceLoc loc, const TFunction& call, bool& builtIn)
{
// TODO: 4.00 functionality: findFunction400()
return findFunction120(loc, call, builtIn);
}
//
// Do everything necessary to handle a variable (non-block) declaration.
// Either redeclaring a variable, or making a new one, updating the symbol

View File

@ -140,7 +140,10 @@ public:
void layoutQualifierCheck(TSourceLoc, const TQualifier&);
void checkNoShaderLayouts(TSourceLoc, const TPublicType&);
const TFunction* findFunction(TSourceLoc, TFunction* pfnCall, bool *builtIn = 0);
const TFunction* findFunction(TSourceLoc loc, const TFunction& call, bool& builtIn);
const TFunction* findFunctionExact(TSourceLoc loc, const TFunction& call, bool& builtIn);
const TFunction* findFunction120(TSourceLoc loc, const TFunction& call, bool& builtIn);
const TFunction* findFunction400(TSourceLoc loc, const TFunction& call, bool& builtIn);
TIntermNode* declareVariable(TSourceLoc, TString& identifier, TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
TIntermTyped* addConstructor(TSourceLoc, TIntermNode*, const TType&, TOperator);
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);

View File

@ -378,10 +378,11 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
switch(version) {
case 100:
case 300:
// versions are complete
break;
case 110:
case 120:
// versions are complete
break;
case 130:
case 140:
infoSink.info << "Warning, version " << version << " is not yet complete; most features are present, but a few are missing.\n";

View File

@ -322,6 +322,19 @@ public:
return (*it).second;
}
void findFunctionNameList(const TString& name, TVector<TFunction*>& list)
{
size_t parenAt = name.find_first_of('(');
TString base(name, 0, parenAt + 1);
tLevel::const_iterator begin = level.lower_bound(base);
base[parenAt] = ')'; // assume ')' is lexically after '('
tLevel::const_iterator end = level.upper_bound(base);
for (tLevel::const_iterator it = begin; it != end; ++it)
list.push_back(it->second->getAsFunction());
}
// See if there is already a function in the table having the given non-function-style name.
bool hasFunctionName(const TString& name) const
{
tLevel::const_iterator candidate = level.lower_bound(name);
@ -511,6 +524,27 @@ public:
return symbol;
}
void findFunctionNameList(const TString& name, TVector<TFunction*>& list, bool& builtIn)
{
// For user levels, return the set found in the first scope with a match
builtIn = false;
int level = currentLevel();
do {
table[level]->findFunctionNameList(name, list);
--level;
} while (list.empty() && level >= globalLevel);
if (! list.empty())
return;
// Gather across all built-in levels; they don't hide each other
builtIn = true;
do {
table[level]->findFunctionNameList(name, list);
--level;
} while (level >= 0);
}
void relateToOperator(const char* name, TOperator op)
{
for (unsigned int level = 0; level < table.size(); ++level)