diff --git a/Test/baseResults/hlsl.attribute.frag.out b/Test/baseResults/hlsl.attribute.frag.out new file mode 100755 index 0000000000000000000000000000000000000000..6ee4a24659c35415d4721032c0c6516dd4fd1a39 --- /dev/null +++ b/Test/baseResults/hlsl.attribute.frag.out @@ -0,0 +1,57 @@ +hlsl.attribute.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:14 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (temp 4-component vector of float) +0:? Sequence +0:11 Test condition and select (temp void) +0:11 Condition +0:11 Constant: +0:11 0 (const int) +0:11 true case is null +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:14 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (temp 4-component vector of float) +0:? Sequence +0:11 Test condition and select (temp void) +0:11 Condition +0:11 Constant: +0:11 0 (const int) +0:11 true case is null +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 10 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "PixelShaderFunction" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 1 + 7: 6(int) Constant 0 +4(PixelShaderFunction): 2 Function None 3 + 5: Label + SelectionMerge 9 None + BranchConditional 7 8 9 + 8: Label + Branch 9 + 9: Label + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.if.frag.out b/Test/baseResults/hlsl.if.frag.out new file mode 100755 index 0000000000000000000000000000000000000000..8908279bac7c7971254f8122afa1944f02e8fe0a --- /dev/null +++ b/Test/baseResults/hlsl.if.frag.out @@ -0,0 +1,223 @@ +hlsl.if.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:29 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (temp 4-component vector of float) +0:? Sequence +0:3 Test condition and select (temp void) +0:3 Condition +0:3 Compare Equal (temp bool) +0:3 'input' (temp 4-component vector of float) +0:3 'input' (temp 4-component vector of float) +0:3 true case +0:4 Branch: Return with expression +0:4 'input' (temp 4-component vector of float) +0:6 Test condition and select (temp void) +0:6 Condition +0:6 Compare Equal (temp bool) +0:6 'input' (temp 4-component vector of float) +0:6 'input' (temp 4-component vector of float) +0:6 true case +0:7 Branch: Return with expression +0:7 'input' (temp 4-component vector of float) +0:6 false case +0:9 Branch: Return with expression +0:9 Negate value (temp 4-component vector of float) +0:9 'input' (temp 4-component vector of float) +0:11 Test condition and select (temp void) +0:11 Condition +0:11 Compare Equal (temp bool) +0:11 'input' (temp 4-component vector of float) +0:11 'input' (temp 4-component vector of float) +0:11 true case is null +0:14 Test condition and select (temp void) +0:14 Condition +0:14 Compare Equal (temp bool) +0:14 'input' (temp 4-component vector of float) +0:14 'input' (temp 4-component vector of float) +0:14 true case is null +0:19 Test condition and select (temp void) +0:19 Condition +0:19 Compare Equal (temp bool) +0:19 'input' (temp 4-component vector of float) +0:19 'input' (temp 4-component vector of float) +0:19 true case +0:? Sequence +0:20 Branch: Return with expression +0:20 'input' (temp 4-component vector of float) +0:23 Test condition and select (temp void) +0:23 Condition +0:23 Compare Equal (temp bool) +0:23 'input' (temp 4-component vector of float) +0:23 'input' (temp 4-component vector of float) +0:23 true case +0:? Sequence +0:24 Branch: Return with expression +0:24 'input' (temp 4-component vector of float) +0:23 false case +0:? Sequence +0:26 Branch: Return with expression +0:26 Negate value (temp 4-component vector of float) +0:26 'input' (temp 4-component vector of float) +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:29 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (temp 4-component vector of float) +0:? Sequence +0:3 Test condition and select (temp void) +0:3 Condition +0:3 Compare Equal (temp bool) +0:3 'input' (temp 4-component vector of float) +0:3 'input' (temp 4-component vector of float) +0:3 true case +0:4 Branch: Return with expression +0:4 'input' (temp 4-component vector of float) +0:6 Test condition and select (temp void) +0:6 Condition +0:6 Compare Equal (temp bool) +0:6 'input' (temp 4-component vector of float) +0:6 'input' (temp 4-component vector of float) +0:6 true case +0:7 Branch: Return with expression +0:7 'input' (temp 4-component vector of float) +0:6 false case +0:9 Branch: Return with expression +0:9 Negate value (temp 4-component vector of float) +0:9 'input' (temp 4-component vector of float) +0:11 Test condition and select (temp void) +0:11 Condition +0:11 Compare Equal (temp bool) +0:11 'input' (temp 4-component vector of float) +0:11 'input' (temp 4-component vector of float) +0:11 true case is null +0:14 Test condition and select (temp void) +0:14 Condition +0:14 Compare Equal (temp bool) +0:14 'input' (temp 4-component vector of float) +0:14 'input' (temp 4-component vector of float) +0:14 true case is null +0:19 Test condition and select (temp void) +0:19 Condition +0:19 Compare Equal (temp bool) +0:19 'input' (temp 4-component vector of float) +0:19 'input' (temp 4-component vector of float) +0:19 true case +0:? Sequence +0:20 Branch: Return with expression +0:20 'input' (temp 4-component vector of float) +0:23 Test condition and select (temp void) +0:23 Condition +0:23 Compare Equal (temp bool) +0:23 'input' (temp 4-component vector of float) +0:23 'input' (temp 4-component vector of float) +0:23 true case +0:? Sequence +0:24 Branch: Return with expression +0:24 'input' (temp 4-component vector of float) +0:23 false case +0:? Sequence +0:26 Branch: Return with expression +0:26 Negate value (temp 4-component vector of float) +0:26 'input' (temp 4-component vector of float) +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 64 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "PixelShaderFunction" + Name 9 "input" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypePointer Function 7(fvec4) + 12: TypeBool + 13: TypeVector 12(bool) 4 +4(PixelShaderFunction): 2 Function None 3 + 5: Label + 9(input): 8(ptr) Variable Function + 10: 7(fvec4) Load 9(input) + 11: 7(fvec4) Load 9(input) + 14: 13(bvec4) FOrdEqual 10 11 + 15: 12(bool) All 14 + SelectionMerge 17 None + BranchConditional 15 16 17 + 16: Label + 18: 7(fvec4) Load 9(input) + ReturnValue 18 + 17: Label + 20: 7(fvec4) Load 9(input) + 21: 7(fvec4) Load 9(input) + 22: 13(bvec4) FOrdEqual 20 21 + 23: 12(bool) All 22 + SelectionMerge 25 None + BranchConditional 23 24 28 + 24: Label + 26: 7(fvec4) Load 9(input) + ReturnValue 26 + 28: Label + 29: 7(fvec4) Load 9(input) + 30: 7(fvec4) FNegate 29 + ReturnValue 30 + 25: Label + 32: 7(fvec4) Load 9(input) + 33: 7(fvec4) Load 9(input) + 34: 13(bvec4) FOrdEqual 32 33 + 35: 12(bool) All 34 + SelectionMerge 37 None + BranchConditional 35 36 37 + 36: Label + Branch 37 + 37: Label + 38: 7(fvec4) Load 9(input) + 39: 7(fvec4) Load 9(input) + 40: 13(bvec4) FOrdEqual 38 39 + 41: 12(bool) All 40 + SelectionMerge 43 None + BranchConditional 41 42 43 + 42: Label + Branch 43 + 43: Label + 44: 7(fvec4) Load 9(input) + 45: 7(fvec4) Load 9(input) + 46: 13(bvec4) FOrdEqual 44 45 + 47: 12(bool) All 46 + SelectionMerge 49 None + BranchConditional 47 48 49 + 48: Label + 50: 7(fvec4) Load 9(input) + ReturnValue 50 + 49: Label + 52: 7(fvec4) Load 9(input) + 53: 7(fvec4) Load 9(input) + 54: 13(bvec4) FOrdEqual 52 53 + 55: 12(bool) All 54 + SelectionMerge 57 None + BranchConditional 55 56 60 + 56: Label + 58: 7(fvec4) Load 9(input) + ReturnValue 58 + 60: Label + 61: 7(fvec4) Load 9(input) + 62: 7(fvec4) FNegate 61 + ReturnValue 62 + 57: Label + Return + FunctionEnd diff --git a/Test/hlsl.attribute.frag b/Test/hlsl.attribute.frag new file mode 100644 index 0000000000000000000000000000000000000000..25c72d46efd90cb07c8f639381e8afd2ea1a6da3 --- /dev/null +++ b/Test/hlsl.attribute.frag @@ -0,0 +1,13 @@ +float4 PixelShaderFunction(float4 input) : COLOR0 +{ + [unroll]; + []; + [][][]; + [unroll(4)]; + [allow_uav_condition]; + [unroll(4)] [allow_uav_condition]; + [ loop ]; + [fastopt]; + [branch] if (0); + [flatten]; +} diff --git a/Test/hlsl.if.frag b/Test/hlsl.if.frag new file mode 100644 index 0000000000000000000000000000000000000000..1f0dde713e1f362a2b1e7560dc80f9f2eef10675 --- /dev/null +++ b/Test/hlsl.if.frag @@ -0,0 +1,28 @@ +float4 PixelShaderFunction(float4 input) : COLOR0 +{ + if (input == input) + return input; + + if (input == input) + return input; + else + return -input; + + if (input == input) + ; + + if (input == input) + ; + else + ; + + [flatten] if (input == input) { + return input; + } + + if (input == input) { + return input; + } else { + return -input; + } +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 9c0061ed296e9a25781bb3beb4a62a3a3665ef11..123dd6085d29e911ca5728804b096f6ae9399a57 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -73,9 +73,11 @@ INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, ::testing::ValuesIn(std::vector<FileNameEntryPointPair>{ {"hlsl.assoc.frag", "PixelShaderFunction"}, + {"hlsl.attribute.frag", "PixelShaderFunction"}, {"hlsl.cast.frag", "PixelShaderFunction"}, {"hlsl.float1.frag", "PixelShaderFunction"}, {"hlsl.float4.frag", "PixelShaderFunction"}, + {"hlsl.if.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.negative.frag", "PixelShaderFunction"}, {"hlsl.intrinsics.negative.vert", "VertexShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 31e67d3607713aa2ab785ba93891697a31ba004f..a75fee6dcff6524b018d4d9ac00677350bf645b4 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -434,7 +434,7 @@ bool HlslGrammar::acceptFunctionParameters(TFunction& function) // RIGHT_PAREN if (! acceptTokenClass(EHTokRightParen)) { - expected("right parenthesis"); + expected(")"); return false; } @@ -485,6 +485,31 @@ bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& no return false; } +// Accept an expression with parenthesis around it, where +// the parenthesis ARE NOT expression parenthesis, but the +// syntactically required ones like in "if ( expression )" +// +// Note this one is not set up to be speculative; as it gives +// errors if not found. +// +bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression) +{ + // LEFT_PAREN + if (! acceptTokenClass(EHTokLeftParen)) + expected("("); + + if (! acceptExpression(expression)) { + expected("expression"); + return false; + } + + // RIGHT_PAREN + if (! acceptTokenClass(EHTokRightParen)) + expected(")"); + + return true; +} + // The top-level full expression recognizer. // // expression @@ -620,7 +645,7 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) TType castType; if (acceptType(castType)) { if (! acceptTokenClass(EHTokRightParen)) { - expected("right parenthesis"); + expected(")"); return false; } @@ -699,7 +724,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) return false; } if (! acceptTokenClass(EHTokRightParen)) { - expected("right parenthesis"); + expected(")"); return false; } } else if (acceptLiteral(node)) { @@ -838,7 +863,7 @@ bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments) // RIGHT_PAREN if (! acceptTokenClass(EHTokRightParen)) { - expected("right parenthesis"); + expected(")"); return false; } @@ -896,6 +921,24 @@ bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement) return acceptTokenClass(EHTokRightBrace); } +bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement) +{ + parseContext.pushScope(); + bool result = acceptNestedStatement(statement); + parseContext.popScope(); + + return result; +} + +bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement) +{ + parseContext.nestStatement(); + bool result = acceptStatement(statement); + parseContext.unnestStatement(); + + return result; +} + // statement // : attributes attributed_statement // @@ -965,7 +1008,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) // SEMICOLON (following an expression) if (! acceptTokenClass(EHTokSemicolon)) { - expected("semicolon"); + expected(";"); return false; } } @@ -989,12 +1032,86 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) // void HlslGrammar::acceptAttributes() { - // TODO + // For now, accept the [ XXX(X) ] syntax, but drop. + // TODO: subset to correct set? Pass on? + do { + // LEFT_BRACKET? + if (! acceptTokenClass(EHTokLeftBracket)) + return; + + // attribute + if (peekTokenClass(EHTokIdentifier)) { + // 'token.string' is the attribute + advanceToken(); + } else if (! peekTokenClass(EHTokRightBracket)) { + expected("identifier"); + advanceToken(); + } + + // (x) + if (acceptTokenClass(EHTokLeftParen)) { + TIntermTyped* node; + if (! acceptLiteral(node)) + expected("literal"); + // 'node' has the literal in it + if (! acceptTokenClass(EHTokRightParen)) + expected(")"); + } + + // RIGHT_BRACKET + if (acceptTokenClass(EHTokRightBracket)) + continue; + + expected("]"); + return; + + } while (true); } +// selection_statement +// : IF LEFT_PAREN expression RIGHT_PAREN statement +// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement +// bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) { - return false; + TSourceLoc loc = token.loc; + + // IF + if (! acceptTokenClass(EHTokIf)) + return false; + + // so that something declared in the condition is scoped to the lifetimes + // of the then-else statements + parseContext.pushScope(); + + // LEFT_PAREN expression RIGHT_PAREN + TIntermTyped* condition; + if (! acceptParenExpression(condition)) + return false; + + // create the child statements + TIntermNodePair thenElse = { nullptr, nullptr }; + + // then statement + if (! acceptScopedStatement(thenElse.node1)) { + expected("then statement"); + return false; + } + + // ELSE + if (acceptTokenClass(EHTokElse)) { + // else statement + if (! acceptScopedStatement(thenElse.node2)) { + expected("else statement"); + return false; + } + } + + // Put the pieces together + statement = intermediate.addSelection(condition, thenElse, loc); + parseContext.popScope(); + + return true; } bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) @@ -1036,7 +1153,7 @@ bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) // SEMICOLON if (! acceptTokenClass(EHTokSemicolon)) { - expected("semicolon"); + expected(";"); return false; } diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h index 7d337fde9d2f0df2d5921d726e1b25f1fa4b0c84..69535f30b9fcae4865eed06713fd6a4467451fdb 100755 --- a/hlsl/hlslGrammar.h +++ b/hlsl/hlslGrammar.h @@ -64,6 +64,7 @@ namespace glslang { bool acceptFunctionParameters(TFunction&); bool acceptParameterDeclaration(TFunction&); bool acceptFunctionDefinition(TFunction&, TIntermNode*&); + bool acceptParenExpression(TIntermTyped*&); bool acceptExpression(TIntermTyped*&); bool acceptAssignmentExpression(TIntermTyped*&); bool acceptBinaryExpression(TIntermTyped*&, PrecedenceLevel); @@ -75,6 +76,8 @@ namespace glslang { bool acceptLiteral(TIntermTyped*&); bool acceptCompoundStatement(TIntermNode*&); bool acceptStatement(TIntermNode*&); + bool acceptScopedStatement(TIntermNode*&); + bool acceptNestedStatement(TIntermNode*&); void acceptAttributes(); bool acceptSelectionStatement(TIntermNode*&); bool acceptSwitchStatement(TIntermNode*&); diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 7fa267ff91d7f2314941662992c2f454617789fd..a6c59a32ae22a84eb0efb23860da4e83bb2025f5 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -139,6 +139,11 @@ public: void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); + void nestStatement() { ++statementNestingLevel; } + void unnestStatement() { --statementNestingLevel; } + void pushScope() { symbolTable.push(); } + void popScope() { symbolTable.pop(0); } + protected: void inheritGlobalDefaults(TQualifier& dst) const; TVariable* makeInternalVariable(const char* name, const TType&) const;