Commit d02dc5d0 by John Kessenich

HLSL: Implement switch/case/default.

parent 2f47bc97
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;
}
......@@ -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"},
......
......@@ -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
......
......@@ -88,6 +88,7 @@ namespace glslang {
bool acceptIterationStatement(TIntermNode*&);
bool acceptJumpStatement(TIntermNode*&);
bool acceptCaseLabel(TIntermNode*&);
bool acceptDefaultLabel(TIntermNode*&);
void acceptArraySpecifier(TArraySizes*&);
void acceptPostDecls(TType&);
......
......@@ -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);
}
......
......@@ -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<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
TList<int> 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment