From d02dc5d05ad1f63db8d37fda9928a4d59e3c132d Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Fri, 1 Jul 2016 00:04:11 -0600 Subject: [PATCH] HLSL: Implement switch/case/default. --- Test/baseResults/hlsl.switch.frag.out | 376 ++++++++++++++++++++++++++ Test/hlsl.switch.frag | 55 ++++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 82 +++++- hlsl/hlslGrammar.h | 1 + hlsl/hlslParseHelper.cpp | 2 - hlsl/hlslParseHelper.h | 4 +- 7 files changed, 514 insertions(+), 7 deletions(-) create mode 100755 Test/baseResults/hlsl.switch.frag.out create mode 100644 Test/hlsl.switch.frag diff --git a/Test/baseResults/hlsl.switch.frag.out b/Test/baseResults/hlsl.switch.frag.out new file mode 100755 index 00000000..7163bc05 --- /dev/null +++ b/Test/baseResults/hlsl.switch.frag.out @@ -0,0 +1,376 @@ +hlsl.switch.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:56 Function Definition: PixelShaderFunction(vf4;i1;i1; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (in 4-component vector of float) +0:2 'c' (in int) +0:2 'd' (in int) +0:? Sequence +0:3 'c' (in int) +0:7 switch +0:7 condition +0:7 'c' (in int) +0:7 body +0:7 Sequence +0:9 default: +0:7 Sequence +0:7 Branch: Break +0:12 switch +0:12 condition +0:12 'c' (in int) +0:12 body +0:12 Sequence +0:13 case: with expression +0:13 Constant: +0:13 1 (const int) +0:? Sequence +0:14 Pre-Increment (temp 4-component vector of float) +0:14 'input' (in 4-component vector of float) +0:15 Branch: Break +0:16 case: with expression +0:16 Constant: +0:16 2 (const int) +0:? Sequence +0:17 Pre-Decrement (temp 4-component vector of float) +0:17 'input' (in 4-component vector of float) +0:18 Branch: Break +0:21 switch +0:21 condition +0:21 'c' (in int) +0:21 body +0:21 Sequence +0:22 case: with expression +0:22 Constant: +0:22 1 (const int) +0:? Sequence +0:23 Pre-Increment (temp 4-component vector of float) +0:23 'input' (in 4-component vector of float) +0:24 Branch: Break +0:25 case: with expression +0:25 Constant: +0:25 2 (const int) +0:? Sequence +0:26 switch +0:26 condition +0:26 'd' (in int) +0:26 body +0:26 Sequence +0:27 case: with expression +0:27 Constant: +0:27 2 (const int) +0:? Sequence +0:28 add second child into first child (temp 4-component vector of float) +0:28 'input' (in 4-component vector of float) +0:28 Constant: +0:28 2.000000 +0:29 Branch: Break +0:30 case: with expression +0:30 Constant: +0:30 3 (const int) +0:? Sequence +0:31 add second child into first child (temp 4-component vector of float) +0:31 'input' (in 4-component vector of float) +0:31 Constant: +0:31 3.000000 +0:32 Branch: Break +0:34 Branch: Break +0:35 default: +0:? Sequence +0:36 add second child into first child (temp 4-component vector of float) +0:36 'input' (in 4-component vector of float) +0:36 Constant: +0:36 4.000000 +0:39 switch +0:39 condition +0:39 'c' (in int) +0:39 body +0:39 Sequence +0:40 case: with expression +0:40 Constant: +0:40 1 (const int) +0:39 Sequence +0:39 Branch: Break +0:43 switch +0:43 condition +0:43 'c' (in int) +0:43 body +0:43 Sequence +0:44 case: with expression +0:44 Constant: +0:44 1 (const int) +0:45 case: with expression +0:45 Constant: +0:45 2 (const int) +0:46 case: with expression +0:46 Constant: +0:46 3 (const int) +0:? Sequence +0:47 Pre-Increment (temp 4-component vector of float) +0:47 'input' (in 4-component vector of float) +0:48 Branch: Break +0:49 case: with expression +0:49 Constant: +0:49 4 (const int) +0:50 case: with expression +0:50 Constant: +0:50 5 (const int) +0:? Sequence +0:51 Pre-Decrement (temp 4-component vector of float) +0:51 'input' (in 4-component vector of float) +0:54 Branch: Return with expression +0:54 'input' (in 4-component vector of float) +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:56 Function Definition: PixelShaderFunction(vf4;i1;i1; (temp 4-component vector of float) +0:2 Function Parameters: +0:2 'input' (in 4-component vector of float) +0:2 'c' (in int) +0:2 'd' (in int) +0:? Sequence +0:3 'c' (in int) +0:7 switch +0:7 condition +0:7 'c' (in int) +0:7 body +0:7 Sequence +0:9 default: +0:7 Sequence +0:7 Branch: Break +0:12 switch +0:12 condition +0:12 'c' (in int) +0:12 body +0:12 Sequence +0:13 case: with expression +0:13 Constant: +0:13 1 (const int) +0:? Sequence +0:14 Pre-Increment (temp 4-component vector of float) +0:14 'input' (in 4-component vector of float) +0:15 Branch: Break +0:16 case: with expression +0:16 Constant: +0:16 2 (const int) +0:? Sequence +0:17 Pre-Decrement (temp 4-component vector of float) +0:17 'input' (in 4-component vector of float) +0:18 Branch: Break +0:21 switch +0:21 condition +0:21 'c' (in int) +0:21 body +0:21 Sequence +0:22 case: with expression +0:22 Constant: +0:22 1 (const int) +0:? Sequence +0:23 Pre-Increment (temp 4-component vector of float) +0:23 'input' (in 4-component vector of float) +0:24 Branch: Break +0:25 case: with expression +0:25 Constant: +0:25 2 (const int) +0:? Sequence +0:26 switch +0:26 condition +0:26 'd' (in int) +0:26 body +0:26 Sequence +0:27 case: with expression +0:27 Constant: +0:27 2 (const int) +0:? Sequence +0:28 add second child into first child (temp 4-component vector of float) +0:28 'input' (in 4-component vector of float) +0:28 Constant: +0:28 2.000000 +0:29 Branch: Break +0:30 case: with expression +0:30 Constant: +0:30 3 (const int) +0:? Sequence +0:31 add second child into first child (temp 4-component vector of float) +0:31 'input' (in 4-component vector of float) +0:31 Constant: +0:31 3.000000 +0:32 Branch: Break +0:34 Branch: Break +0:35 default: +0:? Sequence +0:36 add second child into first child (temp 4-component vector of float) +0:36 'input' (in 4-component vector of float) +0:36 Constant: +0:36 4.000000 +0:39 switch +0:39 condition +0:39 'c' (in int) +0:39 body +0:39 Sequence +0:40 case: with expression +0:40 Constant: +0:40 1 (const int) +0:39 Sequence +0:39 Branch: Break +0:43 switch +0:43 condition +0:43 'c' (in int) +0:43 body +0:43 Sequence +0:44 case: with expression +0:44 Constant: +0:44 1 (const int) +0:45 case: with expression +0:45 Constant: +0:45 2 (const int) +0:46 case: with expression +0:46 Constant: +0:46 3 (const int) +0:? Sequence +0:47 Pre-Increment (temp 4-component vector of float) +0:47 'input' (in 4-component vector of float) +0:48 Branch: Break +0:49 case: with expression +0:49 Constant: +0:49 4 (const int) +0:50 case: with expression +0:50 Constant: +0:50 5 (const int) +0:? Sequence +0:51 Pre-Decrement (temp 4-component vector of float) +0:51 'input' (in 4-component vector of float) +0:54 Branch: Return with expression +0:54 'input' (in 4-component vector of float) +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 82 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" 8 21 41 + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "PixelShaderFunction" + Name 8 "c" + Name 21 "input" + Name 41 "d" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 1 + 7: TypePointer Input 6(int) + 8(c): 7(ptr) Variable Input + 18: TypeFloat 32 + 19: TypeVector 18(float) 4 + 20: TypePointer Input 19(fvec4) + 21(input): 20(ptr) Variable Input + 23: 18(float) Constant 1065353216 + 41(d): 7(ptr) Variable Input + 46: 18(float) Constant 1073741824 + 51: 18(float) Constant 1077936128 + 58: 18(float) Constant 1082130432 +4(PixelShaderFunction): 2 Function None 3 + 5: Label + 9: 6(int) Load 8(c) + SelectionMerge 11 None + Switch 9 10 + 10: Label + Branch 11 + 11: Label + 14: 6(int) Load 8(c) + SelectionMerge 17 None + Switch 14 17 + case 1: 15 + case 2: 16 + 15: Label + 22: 19(fvec4) Load 21(input) + 24: 19(fvec4) CompositeConstruct 23 23 23 23 + 25: 19(fvec4) FAdd 22 24 + Store 21(input) 25 + Branch 17 + 16: Label + 27: 19(fvec4) Load 21(input) + 28: 19(fvec4) CompositeConstruct 23 23 23 23 + 29: 19(fvec4) FSub 27 28 + Store 21(input) 29 + Branch 17 + 17: Label + 32: 6(int) Load 8(c) + SelectionMerge 36 None + Switch 32 35 + case 1: 33 + case 2: 34 + 35: Label + 59: 19(fvec4) Load 21(input) + 60: 19(fvec4) CompositeConstruct 58 58 58 58 + 61: 19(fvec4) FAdd 59 60 + Store 21(input) 61 + Branch 36 + 33: Label + 37: 19(fvec4) Load 21(input) + 38: 19(fvec4) CompositeConstruct 23 23 23 23 + 39: 19(fvec4) FAdd 37 38 + Store 21(input) 39 + Branch 36 + 34: Label + 42: 6(int) Load 41(d) + SelectionMerge 45 None + Switch 42 45 + case 2: 43 + case 3: 44 + 43: Label + 47: 19(fvec4) Load 21(input) + 48: 19(fvec4) CompositeConstruct 46 46 46 46 + 49: 19(fvec4) FAdd 47 48 + Store 21(input) 49 + Branch 45 + 44: Label + 52: 19(fvec4) Load 21(input) + 53: 19(fvec4) CompositeConstruct 51 51 51 51 + 54: 19(fvec4) FAdd 52 53 + Store 21(input) 54 + Branch 45 + 45: Label + Branch 36 + 36: Label + 63: 6(int) Load 8(c) + SelectionMerge 65 None + Switch 63 65 + case 1: 64 + 64: Label + Branch 65 + 65: Label + 68: 6(int) Load 8(c) + SelectionMerge 71 None + Switch 68 71 + case 1: 69 + case 2: 69 + case 3: 69 + case 4: 70 + case 5: 70 + 69: Label + 72: 19(fvec4) Load 21(input) + 73: 19(fvec4) CompositeConstruct 23 23 23 23 + 74: 19(fvec4) FAdd 72 73 + Store 21(input) 74 + Branch 71 + 70: Label + 76: 19(fvec4) Load 21(input) + 77: 19(fvec4) CompositeConstruct 23 23 23 23 + 78: 19(fvec4) FSub 76 77 + Store 21(input) 78 + Branch 71 + 71: Label + 80: 19(fvec4) Load 21(input) + ReturnValue 80 + FunctionEnd diff --git a/Test/hlsl.switch.frag b/Test/hlsl.switch.frag new file mode 100644 index 00000000..88239c2b --- /dev/null +++ b/Test/hlsl.switch.frag @@ -0,0 +1,55 @@ +float4 PixelShaderFunction(float4 input, int c, int d) : COLOR0 +{ + switch(c) + { + } + + switch(c) + { + default: + } + + switch (c) { + case 1: + ++input; + break; + case 2: + --input; + break; + } + + switch (c) { + case 1: + ++input; + break; + case 2: + switch (d) { + case 2: + input += 2.0; + break; + case 3: + input += 3.0; + break; + } + break; + default: + input += 4.0; + } + + switch (c) { + case 1: + } + + switch (c) { + case 1: + case 2: + case 3: + ++input; + break; + case 4: + case 5: + --input; + } + + return input; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index d9218958..fe68a980 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -100,6 +100,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.scope.frag", "PixelShaderFunction"}, {"hlsl.sin.frag", "PixelShaderFunction"}, {"hlsl.struct.frag", "PixelShaderFunction"}, + {"hlsl.switch.frag", "PixelShaderFunction"}, {"hlsl.swizzle.frag", "PixelShaderFunction"}, {"hlsl.whileLoop.frag", "PixelShaderFunction"}, {"hlsl.void.frag", "PixelShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index ae978190..417e4cb4 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -1322,8 +1322,16 @@ bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement) // statement statement ... TIntermNode* statement = nullptr; while (acceptStatement(statement)) { - // hook it up - compoundStatement = intermediate.growAggregate(compoundStatement, statement); + TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr; + if (branch != nullptr && (branch->getFlowOp() == EOpCase || + branch->getFlowOp() == EOpDefault)) { + // hook up individual subsequences within a switch statement + parseContext.wrapupSwitchSubsequence(compoundStatement, statement); + compoundStatement = nullptr; + } else { + // hook it up to the growing compound statement + compoundStatement = intermediate.growAggregate(compoundStatement, statement); + } } if (compoundStatement) compoundStatement->setOperator(EOpSequence); @@ -1397,6 +1405,8 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement) case EHTokCase: return acceptCaseLabel(statement); + case EHTokDefault: + return acceptDefaultLabel(statement); case EHTokSemicolon: return acceptTokenClass(EHTokSemicolon); @@ -1527,9 +1537,34 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement) return true; } +// switch_statement +// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement +// bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement) { - return false; + // SWITCH + TSourceLoc loc = token.loc; + if (! acceptTokenClass(EHTokSwitch)) + return false; + + // LEFT_PAREN expression RIGHT_PAREN + parseContext.pushScope(); + TIntermTyped* switchExpression; + if (! acceptParenExpression(switchExpression)) { + parseContext.popScope(); + return false; + } + + // compound_statement + parseContext.pushSwitchSequence(new TIntermSequence); + bool statementOkay = acceptCompoundStatement(statement); + if (statementOkay) + statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr); + + parseContext.popSwitchSequence(); + parseContext.popScope(); + + return statementOkay; } // iteration_statement @@ -1718,9 +1753,48 @@ bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement) return true; } +// case_label +// : CASE expression COLON +// bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement) { - return false; + TSourceLoc loc = token.loc; + if (! acceptTokenClass(EHTokCase)) + return false; + + TIntermTyped* expression; + if (! acceptExpression(expression)) { + expected("case expression"); + return false; + } + + if (! acceptTokenClass(EHTokColon)) { + expected(":"); + return false; + } + + statement = parseContext.intermediate.addBranch(EOpCase, expression, loc); + + return true; +} + +// default_label +// : DEFAULT COLON +// +bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement) +{ + TSourceLoc loc = token.loc; + if (! acceptTokenClass(EHTokDefault)) + return false; + + if (! acceptTokenClass(EHTokColon)) { + expected(":"); + return false; + } + + statement = parseContext.intermediate.addBranch(EOpDefault, loc); + + return true; } // array_specifier diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h index baeb686e..f00ed4e0 100755 --- a/hlsl/hlslGrammar.h +++ b/hlsl/hlslGrammar.h @@ -88,6 +88,7 @@ namespace glslang { bool acceptIterationStatement(TIntermNode*&); bool acceptJumpStatement(TIntermNode*&); bool acceptCaseLabel(TIntermNode*&); + bool acceptDefaultLabel(TIntermNode*&); void acceptArraySpecifier(TArraySizes*&); void acceptPostDecls(TType&); diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 928021eb..297bfce5 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -3969,8 +3969,6 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn TIntermSequence* switchSequence = switchSequenceStack.back(); if (statements) { - if (switchSequence->size() == 0) - error(statements->getLoc(), "cannot have statements before first case/default label", "switch", ""); statements->setOperator(EOpSequence); switchSequence->push_back(statements); } diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 9b8ff2dd..50233711 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -147,6 +147,9 @@ public: void pushScope() { symbolTable.push(); } void popScope() { symbolTable.pop(0); } + void pushSwitchSequence(TIntermSequence* sequence) { switchSequenceStack.push_back(sequence); } + void popSwitchSequence() { switchSequenceStack.pop_back(); } + protected: void inheritGlobalDefaults(TQualifier& dst) const; TVariable* makeInternalVariable(const char* name, const TType&) const; @@ -166,7 +169,6 @@ protected: int structNestingLevel; // 0 if outside blocks and structures int controlFlowNestingLevel; // 0 if outside all flow control TList switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting - TList switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements bool inEntrypoint; // if inside a function, true if the function is the entry point bool postMainReturn; // if inside a function, true if the function is the entry point and this is after a return statement const TType* currentFunctionType; // the return type of the function that's currently being parsed