Преглед изворни кода

Add variadic function support for builtin functions

Add basic frontend support for variadic functions during builtin
function declaration parsing.  This is needed for the GL_ARM_tensors
extension.

Signed-off-by: Sven van Haastregt <[email protected]>
Sven van Haastregt пре 1 месец
родитељ
комит
d42b2a6b61

+ 47 - 0
Test/baseResults/variadic.comp.out

@@ -0,0 +1,47 @@
+variadic.comp
+ERROR: 0:3: '...' : variadic argument specifier is only available for builtins 
+ERROR: 0:10: 'foo' : no matching overloaded function found 
+ERROR: 0:11: 'foo' : no matching overloaded function found 
+ERROR: 3 compilation errors.  No code generated.
+
+
+Shader version: 450
+local_size = (1, 1, 1)
+ERROR: node is still EOpNull!
+0:3  Function Definition: foo(i1; ( global void)
+0:3    Function Parameters: 
+0:3      'n' ( in int)
+0:7  Function Definition: main( ( global void)
+0:7    Function Parameters: 
+0:9    Sequence
+0:9      Function Call: foo(i1; ( global void)
+0:9        Constant:
+0:9          7 (const int)
+0:10      Constant:
+0:10        0.000000
+0:11      Constant:
+0:11        0.000000
+0:?   Linker Objects
+
+
+Linked compute stage:
+
+
+Shader version: 450
+local_size = (1, 1, 1)
+ERROR: node is still EOpNull!
+0:3  Function Definition: foo(i1; ( global void)
+0:3    Function Parameters: 
+0:3      'n' ( in int)
+0:7  Function Definition: main( ( global void)
+0:7    Function Parameters: 
+0:9    Sequence
+0:9      Function Call: foo(i1; ( global void)
+0:9        Constant:
+0:9          7 (const int)
+0:10      Constant:
+0:10        0.000000
+0:11      Constant:
+0:11        0.000000
+0:?   Linker Objects
+

+ 12 - 0
Test/variadic.comp

@@ -0,0 +1,12 @@
+#version 450
+
+void foo(int n, ...)
+{
+}
+
+void main()
+{
+  foo(7);
+  foo(8, 43);
+  foo(9, 42.0, 21.05);
+}

+ 5 - 3
glslang/MachineIndependent/ParseContextBase.cpp

@@ -424,7 +424,7 @@ const TFunction* TParseContextBase::selectFunction(
         // to even be a potential match, number of arguments must be >= the number of
         // fixed (non-default) parameters, and <= the total (including parameter with defaults).
         if (call.getParamCount() < candidate.getFixedParamCount() ||
-            call.getParamCount() > candidate.getParamCount())
+            (call.getParamCount() > candidate.getParamCount() && !candidate.isVariadic()))
             continue;
 
         // see if arguments are convertible
@@ -463,7 +463,8 @@ const TFunction* TParseContextBase::selectFunction(
     const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
         // is call -> can2 better than call -> can1 for any parameter
         bool hasBetterParam = false;
-        for (int param = 0; param < call.getParamCount(); ++param) {
+        const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()});
+        for (int param = 0; param < paramCount; ++param) {
             if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
                 hasBetterParam = true;
                 break;
@@ -474,7 +475,8 @@ const TFunction* TParseContextBase::selectFunction(
 
     const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
         // is call -> can2 equivalent to call -> can1 for all the call parameters?
-        for (int param = 0; param < call.getParamCount(); ++param) {
+        const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()});
+        for (int param = 0; param < paramCount; ++param) {
             if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
                 better(*call[param].type, *can2[param].type, *can1[param].type))
                 return false;

+ 10 - 0
glslang/MachineIndependent/ParseHelper.cpp

@@ -1887,6 +1887,8 @@ void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction
         // find the maximum precision from the arguments and parameters
         for (unsigned int arg = 0; arg < numArgs; ++arg) {
             operationPrecision = std::max(operationPrecision, sequence[arg]->getAsTyped()->getQualifier().precision);
+        }
+        for (int arg = 0; arg < function.getParamCount(); ++arg) {
             operationPrecision = std::max(operationPrecision, function[arg].type->getQualifier().precision);
         }
         // compute the result precision
@@ -9430,6 +9432,14 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
     return intermediate.setAggregateOperator(newNode, op, type, loc);
 }
 
+void TParseContext::makeVariadic(TFunction *F, const TSourceLoc &loc) {
+    if (parsingBuiltins) {
+        F->setVariadic();
+    } else {
+        error(loc, "variadic argument specifier is only available for builtins", "...", "");
+    }
+}
+
 // This function tests for the type of the parameters to the structure or array constructor. Raises
 // an error message if the expected type does not match the parameter passed to the constructor.
 //

+ 1 - 0
glslang/MachineIndependent/ParseHelper.h

@@ -450,6 +450,7 @@ public:
     TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
     TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
     TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
+    void makeVariadic(TFunction *F, const TSourceLoc &loc);
     void inheritMemoryQualifiers(const TQualifier& from, TQualifier& to);
     void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = nullptr, TArraySizes* arraySizes = nullptr);
     void blockStorageRemap(const TSourceLoc&, const TString*, TQualifier&);

+ 1 - 0
glslang/MachineIndependent/SymbolTable.cpp

@@ -423,6 +423,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
     defined = copyOf.defined;
     prototyped = copyOf.prototyped;
     implicitThis = copyOf.implicitThis;
+    variadic = copyOf.variadic;
     illegalImplicitThis = copyOf.illegalImplicitThis;
     defaultParamCount = copyOf.defaultParamCount;
     spirvInst = copyOf.spirvInst;

+ 11 - 2
glslang/MachineIndependent/SymbolTable.h

@@ -245,12 +245,12 @@ public:
     explicit TFunction(TOperator o) :
         TSymbol(nullptr),
         op(o),
-        defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { }
+        defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), variadic(false), defaultParamCount(0) { }
     TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
         TSymbol(name),
         mangledName(*name + '('),
         op(tOp),
-        defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0),
+        defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), variadic(false), defaultParamCount(0),
         linkType(ELinkNone)
     {
         returnType.shallowCopy(retType);
@@ -268,6 +268,7 @@ public:
     virtual void addParameter(TParameter& p)
     {
         assert(writable);
+        assert(!variadic && "cannot add more parameters if function is marked variadic");
         parameters.push_back(p);
         p.type->appendMangledName(mangledName);
 
@@ -310,6 +311,13 @@ public:
     virtual bool hasImplicitThis() const { return implicitThis; }
     virtual void setIllegalImplicitThis() { assert(writable); illegalImplicitThis = true; }
     virtual bool hasIllegalImplicitThis() const { return illegalImplicitThis; }
+    virtual void setVariadic() {
+        assert(writable);
+        assert(!variadic && "function was already marked variadic");
+        variadic = true;
+        mangledName += 'z';
+    }
+    virtual bool isVariadic() const { return variadic; }
 
     // Return total number of parameters
     virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
@@ -352,6 +360,7 @@ protected:
                                // even if it finds member variables in the symbol table.
                                // This is important for a static member function that has member variables in scope,
                                // but is not allowed to use them, or see hidden symbols instead.
+    bool variadic;
     int  defaultParamCount;
 
     TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers

+ 4 - 0
glslang/MachineIndependent/glslang.y

@@ -1039,6 +1039,10 @@ function_header_with_parameters
                 parseContext.vkRelaxedRemapFunctionParameter($1, $3.param);
         }
     }
+    | function_header_with_parameters COMMA DOT DOT DOT {
+        $$ = $1;
+        parseContext.makeVariadic($1, $3.loc);
+    }
     ;
 
 function_header

Разлика између датотеке није приказан због своје велике величине
+ 524 - 380
glslang/MachineIndependent/glslang_tab.cpp


+ 1 - 0
gtests/AST.FromFile.cpp

@@ -225,6 +225,7 @@ INSTANTIATE_TEST_SUITE_P(
         "types.frag",
         "uniformArray.frag",
         "variableArrayIndex.frag",
+        "variadic.comp",
         "varyingArray.frag",
         "varyingArrayIndirect.frag",
         "voidFunction.frag",

Неке датотеке нису приказане због велике количине промена