From 5e69ec683d90aed5c6cedbf4e8da9c9f81a7aab9 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Tue, 5 Jul 2016 00:02:40 -0600 Subject: [PATCH] HLSL: Add typedef grammar and production. --- Test/baseResults/hlsl.typedef.frag.out | 132 +++++++++++++++++++++++++ Test/hlsl.typedef.frag | 11 +++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 31 ++++-- hlsl/hlslParseHelper.cpp | 27 ++++- hlsl/hlslParseHelper.h | 1 + 6 files changed, 192 insertions(+), 11 deletions(-) create mode 100755 Test/baseResults/hlsl.typedef.frag.out create mode 100644 Test/hlsl.typedef.frag diff --git a/Test/baseResults/hlsl.typedef.frag.out b/Test/baseResults/hlsl.typedef.frag.out new file mode 100755 index 000000000..ca0235ae5 --- /dev/null +++ b/Test/baseResults/hlsl.typedef.frag.out @@ -0,0 +1,132 @@ +hlsl.typedef.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:12 Function Definition: ShaderFunction(vf4;i1; (global 4-component vector of float) +0:4 Function Parameters: +0:4 'input' (in 4-component vector of float) +0:4 'ii' (in int) +0:? Sequence +0:6 Sequence +0:6 move second child to first child (temp 4-component vector of float) +0:6 'a1' (temp 4-component vector of float) +0:6 Constant: +0:6 1.000000 +0:6 1.000000 +0:6 1.000000 +0:6 1.000000 +0:7 Sequence +0:7 move second child to first child (temp int) +0:7 'i' (temp int) +0:7 Constant: +0:7 2 (const int) +0:9 Sequence +0:9 move second child to first child (temp int) +0:9 'j' (temp int) +0:9 'ii' (in int) +0:10 Branch: Return with expression +0:10 add (temp 4-component vector of float) +0:10 component-wise multiply (temp 4-component vector of float) +0:10 'input' (in 4-component vector of float) +0:10 'a1' (temp 4-component vector of float) +0:10 Construct vec4 (global 4-component vector of float) +0:10 Convert int to float (temp float) +0:10 add (temp int) +0:10 'i' (temp int) +0:10 'j' (temp int) +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:12 Function Definition: ShaderFunction(vf4;i1; (global 4-component vector of float) +0:4 Function Parameters: +0:4 'input' (in 4-component vector of float) +0:4 'ii' (in int) +0:? Sequence +0:6 Sequence +0:6 move second child to first child (temp 4-component vector of float) +0:6 'a1' (temp 4-component vector of float) +0:6 Constant: +0:6 1.000000 +0:6 1.000000 +0:6 1.000000 +0:6 1.000000 +0:7 Sequence +0:7 move second child to first child (temp int) +0:7 'i' (temp int) +0:7 Constant: +0:7 2 (const int) +0:9 Sequence +0:9 move second child to first child (temp int) +0:9 'j' (temp int) +0:9 'ii' (in int) +0:10 Branch: Return with expression +0:10 add (temp 4-component vector of float) +0:10 component-wise multiply (temp 4-component vector of float) +0:10 'input' (in 4-component vector of float) +0:10 'a1' (temp 4-component vector of float) +0:10 Construct vec4 (global 4-component vector of float) +0:10 Convert int to float (temp float) +0:10 add (temp int) +0:10 'i' (temp int) +0:10 'j' (temp int) +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 34 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "PixelShaderFunction" + Name 14 "ShaderFunction(vf4;i1;" + Name 12 "input" + Name 13 "ii" + Name 16 "a1" + Name 19 "i" + Name 21 "j" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypePointer Function 7(fvec4) + 9: TypeInt 32 1 + 10: TypePointer Function 9(int) + 11: TypeFunction 7(fvec4) 8(ptr) 10(ptr) + 17: 6(float) Constant 1065353216 + 18: 7(fvec4) ConstantComposite 17 17 17 17 + 20: 9(int) Constant 2 +4(PixelShaderFunction): 2 Function None 3 + 5: Label + FunctionEnd +14(ShaderFunction(vf4;i1;): 7(fvec4) Function None 11 + 12(input): 8(ptr) FunctionParameter + 13(ii): 10(ptr) FunctionParameter + 15: Label + 16(a1): 8(ptr) Variable Function + 19(i): 10(ptr) Variable Function + 21(j): 10(ptr) Variable Function + Store 16(a1) 18 + Store 19(i) 20 + 22: 9(int) Load 13(ii) + Store 21(j) 22 + 23: 7(fvec4) Load 12(input) + 24: 7(fvec4) Load 16(a1) + 25: 7(fvec4) FMul 23 24 + 26: 9(int) Load 19(i) + 27: 9(int) Load 21(j) + 28: 9(int) IAdd 26 27 + 29: 6(float) ConvertSToF 28 + 30: 7(fvec4) CompositeConstruct 29 29 29 29 + 31: 7(fvec4) FAdd 25 30 + ReturnValue 31 + FunctionEnd diff --git a/Test/hlsl.typedef.frag b/Test/hlsl.typedef.frag new file mode 100644 index 000000000..b09785e6d --- /dev/null +++ b/Test/hlsl.typedef.frag @@ -0,0 +1,11 @@ +typedef float4 myVec4; + +float4 ShaderFunction(float4 input, int ii) : COLOR0 +{ + typedef int myInt; + myVec4 a1 = myVec4(1.0); + myInt i = 2; + typedef myInt myInt2; + myInt2 j = ii; + return input * a1 + myVec4(i + j); +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 040739fec..a0044190a 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -104,6 +104,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.switch.frag", "PixelShaderFunction"}, {"hlsl.swizzle.frag", "PixelShaderFunction"}, {"hlsl.templatetypes.frag", "PixelShaderFunction"}, + {"hlsl.typedef.frag", "PixelShaderFunction"}, {"hlsl.whileLoop.frag", "PixelShaderFunction"}, {"hlsl.void.frag", "PixelShaderFunction"}, }), diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index d92debd34..ee8ebf3fe 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -108,6 +108,7 @@ bool HlslGrammar::acceptCompilationUnit() // declaration // : fully_specified_type declarator_list SEMICOLON // | fully_specified_type identifier function_parameters post_decls compound_statement // function definition +// | typedef declaration // // declarator_list // : declarator COMMA declarator COMMA declarator... // zero or more declarators @@ -130,6 +131,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) node = nullptr; bool list = false; + // typedef + bool typedefDecl = acceptTokenClass(EHTokTypedef); + // fully_specified_type TType type; if (! acceptFullySpecifiedType(type)) @@ -150,9 +154,14 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) if (peekTokenClass(EHTokLeftBrace)) { if (list) parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", ""); + if (typedefDecl) + parseContext.error(idToken.loc, "function body can't be in a typedef", "{", ""); return acceptFunctionDefinition(*function, node); - } else + } else { + if (typedefDecl) + parseContext.error(idToken.loc, "function typedefs not implemented", "{", ""); parseContext.handleFunctionDeclarator(idToken.loc, *function, true); + } } else { // a variable declaration @@ -166,19 +175,25 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node) // EQUAL assignment_expression TIntermTyped* expressionNode = nullptr; if (acceptTokenClass(EHTokAssign)) { + if (typedefDecl) + parseContext.error(idToken.loc, "can't have an initializer", "typedef", ""); if (! acceptAssignmentExpression(expressionNode)) { expected("initializer"); return false; } } - // Declare the variable and add any initializer code to the AST. - // The top-level node is always made into an aggregate, as that's - // historically how the AST has been. - node = intermediate.growAggregate(node, - parseContext.declareVariable(idToken.loc, *idToken.string, type, - arraySizes, expressionNode), - idToken.loc); + if (typedefDecl) + parseContext.declareTypedef(idToken.loc, *idToken.string, type, arraySizes); + else { + // Declare the variable and add any initializer code to the AST. + // The top-level node is always made into an aggregate, as that's + // historically how the AST has been. + node = intermediate.growAggregate(node, + parseContext.declareVariable(idToken.loc, *idToken.string, type, + arraySizes, expressionNode), + idToken.loc); + } } if (acceptTokenClass(EHTokComma)) { diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 22cd1f43a..43f685ca8 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -3018,6 +3018,27 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu return candidate; } +// +// Do everything necessary to handle a typedef declaration, for a single symbol. +// +// 'parseType' is the type part of the declaration (to the left) +// 'arraySizes' is the arrayness tagged on the identifier (to the right) +// +void HlslParseContext::declareTypedef(const TSourceLoc& loc, TString& identifier, const TType& parseType, TArraySizes* arraySizes) +{ + TType type; + type.deepCopy(parseType); + + // Arrayness is potentially coming both from the type and from the + // variable: "int[] a[];" or just one or the other. + // Merge it all to the type, so all arrayness is part of the type. + arrayDimMerge(type, arraySizes); + + TVariable* typeSymbol = new TVariable(&identifier, type, true); + if (! symbolTable.insert(*typeSymbol)) + error(loc, "name already defined", "typedef", identifier.c_str()); +} + // // Do everything necessary to handle a variable (non-block) declaration. // Either redeclaring a variable, or making a new one, updating the symbol @@ -3026,7 +3047,7 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu // Returns a subtree node that computes an initializer, if needed. // Returns nullptr if there is no code to execute for initialization. // -// 'publicType' is the type part of the declaration (to the left) +// 'parseType' is the type part of the declaration (to the left) // 'arraySizes' is the arrayness tagged on the identifier (to the right) // TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TType& parseType, TArraySizes* arraySizes, TIntermTyped* initializer) @@ -3036,7 +3057,7 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i if (type.isImplicitlySizedArray()) { // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b // of different sizes, for this case sharing the shallow copy of arrayness - // with the publicType oversubscribes it, so get a deep copy of the arrayness. + // with the parseType oversubscribes it, so get a deep copy of the arrayness. type.newArraySizes(*parseType.getArraySizes()); } @@ -3045,7 +3066,7 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i // Check for redeclaration of built-ins and/or attempting to declare a reserved name bool newDeclaration = false; // true if a new entry gets added to the symbol table - TSymbol* symbol = nullptr; // = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers, newDeclaration); + TSymbol* symbol = nullptr; // = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), parseType.shaderQualifiers, newDeclaration); inheritGlobalDefaults(type.getQualifier()); diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 502337112..9b3254dca 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -126,6 +126,7 @@ public: void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&); const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn); + void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0); TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator); TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);