Commit 76a343af by Alexis Hetu Committed by Alexis Hétu

Adding switch case default keywords

This adds switch/case keywords to glsl. This makes the shaders that include these keywords compile, but they don't run properly yet, partly because the "break" statement only handles loops currently. Change-Id: I1f52b445e1124ed3931843c46e27ecc1d9ce3d11 Reviewed-on: https://swiftshader-review.googlesource.com/3400Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com>
parent a35d8232
......@@ -40,6 +40,7 @@ LOCAL_SRC_FILES += \
TranslatorASM.cpp \
util.cpp \
ValidateLimitations.cpp \
ValidateSwitch.cpp \
LOCAL_CFLAGS += -DLOG_TAG=\"swiftshader_compiler\" -Wno-unused-parameter
......
......@@ -216,6 +216,7 @@
<ClCompile Include="ValidateLimitations.cpp" />
<ClCompile Include="glslang_lex.cpp" />
<ClCompile Include="glslang_tab.cpp" />
<ClCompile Include="ValidateSwitch.cpp" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="glslang.l">
......@@ -318,6 +319,7 @@
<ClInclude Include="util.h" />
<ClInclude Include="ValidateLimitations.h" />
<ClInclude Include="glslang_tab.h" />
<ClInclude Include="ValidateSwitch.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="preprocessor\preprocessor.vcxproj">
......
......@@ -83,6 +83,9 @@
<ClCompile Include="AnalyzeCallDepth.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ValidateSwitch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BaseTypes.h">
......@@ -169,6 +172,9 @@
<ClInclude Include="glslang.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ValidateSwitch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="glslang.l">
......
......@@ -53,7 +53,7 @@ void TIntermBinary::traverse(TIntermTraverser* it)
//
if(visit)
{
it->incrementDepth();
it->incrementDepth(this);
if(it->rightToLeft)
{
......@@ -114,7 +114,7 @@ void TIntermUnary::traverse(TIntermTraverser* it)
visit = it->visitUnary(PreVisit, this);
if (visit) {
it->incrementDepth();
it->incrementDepth(this);
operand->traverse(it);
it->decrementDepth();
}
......@@ -137,7 +137,7 @@ void TIntermAggregate::traverse(TIntermTraverser* it)
if(visit)
{
it->incrementDepth();
it->incrementDepth(this);
if(it->rightToLeft)
{
......@@ -190,7 +190,7 @@ void TIntermSelection::traverse(TIntermTraverser* it)
visit = it->visitSelection(PreVisit, this);
if (visit) {
it->incrementDepth();
it->incrementDepth(this);
if (it->rightToLeft) {
if (falseBlock)
falseBlock->traverse(it);
......@@ -212,6 +212,60 @@ void TIntermSelection::traverse(TIntermTraverser* it)
}
//
// Traverse a switch node. Same comments in binary node apply here.
//
void TIntermSwitch::traverse(TIntermTraverser *it)
{
bool visit = true;
if(it->preVisit)
visit = it->visitSwitch(PreVisit, this);
if(visit)
{
it->incrementDepth(this);
if(it->rightToLeft)
{
if(mStatementList)
mStatementList->traverse(it);
if(it->inVisit)
visit = it->visitSwitch(InVisit, this);
if(visit)
mInit->traverse(it);
}
else
{
mInit->traverse(it);
if(it->inVisit)
visit = it->visitSwitch(InVisit, this);
if(visit && mStatementList)
mStatementList->traverse(it);
}
it->decrementDepth();
}
if(visit && it->postVisit)
it->visitSwitch(PostVisit, this);
}
//
// Traverse a switch node. Same comments in binary node apply here.
//
void TIntermCase::traverse(TIntermTraverser *it)
{
bool visit = true;
if(it->preVisit)
visit = it->visitCase(PreVisit, this);
if(visit && mCondition)
mCondition->traverse(it);
if(visit && it->postVisit)
it->visitCase(PostVisit, this);
}
//
// Traverse a loop node. Same comments in binary node apply here.
//
void TIntermLoop::traverse(TIntermTraverser* it)
......@@ -225,7 +279,7 @@ void TIntermLoop::traverse(TIntermTraverser* it)
if(visit)
{
it->incrementDepth();
it->incrementDepth(this);
if(it->rightToLeft)
{
......@@ -282,7 +336,7 @@ void TIntermBranch::traverse(TIntermTraverser* it)
visit = it->visitBranch(PreVisit, this);
if (visit && expression) {
it->incrementDepth();
it->incrementDepth(this);
expression->traverse(it);
it->decrementDepth();
}
......
......@@ -552,6 +552,22 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
return node;
}
TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
{
TIntermSwitch *node = new TIntermSwitch(init, statementList);
node->setLine(line);
return node;
}
TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line)
{
TIntermCase *node = new TIntermCase(condition);
node->setLine(line);
return node;
}
//
// Constant terminal nodes. Has a union that contains bool, float or int constants
//
......
......@@ -11,6 +11,7 @@
#include "glslang.h"
#include "preprocessor/SourceLocation.h"
#include "ValidateSwitch.h"
///////////////////////////////////////////////////////////////////////
//
......@@ -2966,6 +2967,143 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
return true;
}
TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
if((switchType != EbtInt && switchType != EbtUInt) ||
init->isMatrix() ||
init->isArray() ||
init->isVector())
{
error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
recover();
return nullptr;
}
if(statementList)
{
if(!ValidateSwitch::validate(switchType, this, statementList, loc))
{
recover();
return nullptr;
}
}
TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
if(node == nullptr)
{
error(loc, "erroneous switch statement", "switch");
recover();
return nullptr;
}
return node;
}
TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
{
if(switchNestingLevel == 0)
{
error(loc, "case labels need to be inside switch statements", "case");
recover();
return nullptr;
}
if(condition == nullptr)
{
error(loc, "case label must have a condition", "case");
recover();
return nullptr;
}
if((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
condition->isMatrix() ||
condition->isArray() ||
condition->isVector())
{
error(condition->getLine(), "case label must be a scalar integer", "case");
recover();
}
TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
if(conditionConst == nullptr)
{
error(condition->getLine(), "case label must be constant", "case");
recover();
}
TIntermCase *node = intermediate.addCase(condition, loc);
if(node == nullptr)
{
error(loc, "erroneous case statement", "case");
recover();
return nullptr;
}
return node;
}
TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
{
if(switchNestingLevel == 0)
{
error(loc, "default labels need to be inside switch statements", "default");
recover();
return nullptr;
}
TIntermCase *node = intermediate.addCase(nullptr, loc);
if(node == nullptr)
{
error(loc, "erroneous default statement", "default");
recover();
return nullptr;
}
return node;
}
TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
{
switch(op)
{
case EOpContinue:
if(loopNestingLevel <= 0)
{
error(loc, "continue statement only allowed in loops", "");
recover();
}
break;
case EOpBreak:
if(loopNestingLevel <= 0 && switchNestingLevel <= 0)
{
error(loc, "break statement only allowed in loops and switch statements", "");
recover();
}
break;
case EOpReturn:
if(currentFunctionType->getBasicType() != EbtVoid)
{
error(loc, "non-void function must return a value", "return");
recover();
}
break;
default:
// No checks for discard
break;
}
return intermediate.addBranch(op, loc);
}
TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
{
ASSERT(op == EOpReturn);
functionReturnsValue = true;
if(currentFunctionType->getBasicType() == EbtVoid)
{
error(loc, "void function cannot return a value", "return");
recover();
}
else if(*currentFunctionType != returnValue->getType())
{
error(loc, "function return is not matching type:", "return");
recover();
}
return intermediate.addBranch(op, returnValue, loc);
}
//
// Parse an array of strings using yyparse.
//
......
......@@ -34,6 +34,7 @@ struct TParseContext {
treeRoot(0),
lexAfterType(false),
loopNestingLevel(0),
switchNestingLevel(0),
structNestingLevel(0),
inTypeParen(false),
currentFunctionType(NULL),
......@@ -58,6 +59,7 @@ struct TParseContext {
TIntermNode* treeRoot; // root of parse tree being created
bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier
int loopNestingLevel; // 0 if outside all loops
int switchNestingLevel; // 0 if outside all switch statements
int structNestingLevel; // incremented while parsing a struct declaration
bool inTypeParen; // true if in parentheses, looking only for an identifier
const TType* currentFunctionType; // the return type of the function that's currently being parsed
......@@ -82,6 +84,9 @@ struct TParseContext {
void trace(const char* str);
void recover();
void incrSwitchNestingLevel() { ++switchNestingLevel; }
void decrSwitchNestingLevel() { --switchNestingLevel; }
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
......@@ -189,9 +194,16 @@ struct TParseContext {
bool structNestingErrorCheck(const TSourceLoc &line, const TField &field);
TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
TIntermCase *addDefault(const TSourceLoc &loc);
TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
private:
bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
......
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "ValidateSwitch.h"
#include "ParseHelper.h"
bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context,
TIntermAggregate *statementList, const TSourceLoc &loc)
{
ValidateSwitch validate(switchType, context);
ASSERT(statementList);
statementList->traverse(&validate);
return validate.validateInternal(loc);
}
ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context)
: TIntermTraverser(true, false, true),
mSwitchType(switchType),
mContext(context),
mCaseTypeMismatch(false),
mFirstCaseFound(false),
mStatementBeforeCase(false),
mLastStatementWasCase(false),
mControlFlowDepth(0),
mCaseInsideControlFlow(false),
mDefaultCount(0),
mDuplicateCases(false)
{}
void ValidateSwitch::visitSymbol(TIntermSymbol *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *)
{
// Conditions of case labels are not traversed, so this is some other constant
// Could be just a statement like "0;"
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *)
{
if (visit == PreVisit)
++mControlFlowDepth;
if (visit == PostVisit)
--mControlFlowDepth;
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
// Don't go into nested switch statements
return false;
}
bool ValidateSwitch::visitCase(Visit, TIntermCase *node)
{
const char *nodeStr = node->hasCondition() ? "case" : "default";
if (mControlFlowDepth > 0)
{
mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr);
mCaseInsideControlFlow = true;
}
mFirstCaseFound = true;
mLastStatementWasCase = true;
if (!node->hasCondition())
{
++mDefaultCount;
if (mDefaultCount > 1)
{
mContext->error(node->getLine(), "duplicate default label", nodeStr);
}
}
else
{
TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion();
if (condition == nullptr)
{
// This can happen in error cases.
return false;
}
TBasicType conditionType = condition->getBasicType();
if (conditionType != mSwitchType)
{
mContext->error(condition->getLine(),
"case label type does not match switch init-expression type", nodeStr);
mCaseTypeMismatch = true;
}
if (conditionType == EbtInt)
{
int iConst = condition->getIConst(0);
if (mCasesSigned.find(iConst) != mCasesSigned.end())
{
mContext->error(condition->getLine(), "duplicate case label", nodeStr);
mDuplicateCases = true;
}
else
{
mCasesSigned.insert(iConst);
}
}
else if (conditionType == EbtUInt)
{
unsigned int uConst = condition->getUConst(0);
if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end())
{
mContext->error(condition->getLine(), "duplicate case label", nodeStr);
mDuplicateCases = true;
}
else
{
mCasesUnsigned.insert(uConst);
}
}
// Other types are possible only in error cases, where the error has already been generated
// when parsing the case statement.
}
// Don't traverse the condition of the case statement
return false;
}
bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *)
{
if (getParentNode() != nullptr)
{
// This is not the statementList node, but some other node.
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
}
return true;
}
bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *)
{
if (visit == PreVisit)
++mControlFlowDepth;
if (visit == PostVisit)
--mControlFlowDepth;
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
{
if (!mFirstCaseFound)
mStatementBeforeCase = true;
mLastStatementWasCase = false;
return true;
}
bool ValidateSwitch::validateInternal(const TSourceLoc &loc)
{
if (mStatementBeforeCase)
{
mContext->error(loc,
"statement before the first label", "switch");
}
if (mLastStatementWasCase)
{
mContext->error(loc,
"no statement between the last label and the end of the switch statement", "switch");
}
return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
!mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases;
}
//
// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_VALIDATESWITCH_H_
#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_
#include "intermediate.h"
#include <set>
struct TParseContext;
class ValidateSwitch : public TIntermTraverser
{
public:
// Check for errors and output messages any remaining errors on the context.
// Returns true if there are no errors.
static bool validate(TBasicType switchType, TParseContext *context,
TIntermAggregate *statementList, const TSourceLoc &loc);
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitBinary(Visit, TIntermBinary *) override;
bool visitUnary(Visit, TIntermUnary *) override;
bool visitSelection(Visit visit, TIntermSelection *) override;
bool visitSwitch(Visit, TIntermSwitch *) override;
bool visitCase(Visit, TIntermCase *) override;
bool visitAggregate(Visit, TIntermAggregate *) override;
bool visitLoop(Visit visit, TIntermLoop *) override;
bool visitBranch(Visit, TIntermBranch *) override;
private:
ValidateSwitch(TBasicType switchType, TParseContext *context);
bool validateInternal(const TSourceLoc &loc);
TBasicType mSwitchType;
TParseContext *mContext;
bool mCaseTypeMismatch;
bool mFirstCaseFound;
bool mStatementBeforeCase;
bool mLastStatementWasCase;
int mControlFlowDepth;
bool mCaseInsideControlFlow;
int mDefaultCount;
std::set<int> mCasesSigned;
std::set<unsigned int> mCasesUnsigned;
bool mDuplicateCases;
};
#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_
......@@ -67,6 +67,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
TIntermNodePair nodePair;
TIntermTyped* intermTypedNode;
TIntermAggregate* intermAggregate;
TIntermSwitch* intermSwitch;
TIntermCase* intermCase;
};
union {
TPublicType type;
......@@ -165,6 +167,8 @@ extern void yyerror(TParseContext* context, const char* reason);
%type <interm.intermNode> declaration external_declaration
%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
%type <interm.nodePair> selection_rest_statement for_rest_statement
%type <interm.intermSwitch> switch_statement
%type <interm.intermCase> case_label
%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
%type <interm> single_declaration init_declarator_list
......@@ -357,7 +361,7 @@ function_call
$$->getAsAggregate()->setName(fnCandidate->getMangledName());
TQualifier qual;
for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
qual = fnCandidate->getParam(i).type->getQualifier();
if (qual == EvqOut || qual == EvqInOut) {
if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
......@@ -906,7 +910,7 @@ declaration
prototype->setType(function.getReturnType());
prototype->setName(function.getName());
for (int i = 0; i < function.getParamCount(); i++)
for (size_t i = 0; i < function.getParamCount(); i++)
{
const TParameter &param = function.getParam(i);
if (param.name != 0)
......@@ -973,7 +977,7 @@ function_prototype
context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
context->recover();
}
for (int i = 0; i < prevDec->getParamCount(); ++i) {
for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
context->recover();
......@@ -1802,6 +1806,8 @@ simple_statement
: declaration_statement { $$ = $1; }
| expression_statement { $$ = $1; }
| selection_statement { $$ = $1; }
| switch_statement { $$ = $1; }
| case_label { $$ = $1; }
| iteration_statement { $$ = $1; }
| jump_statement { $$ = $1; }
;
......@@ -1874,7 +1880,23 @@ selection_rest_statement
}
;
// Grammar Note: No 'switch'. Switch statements not supported.
switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
$$ = context->addSwitch($3, $6, $1.line);
context->decrSwitchNestingLevel();
}
;
case_label
: CASE constant_expression COLON {
$$ = context->addCase($2, $1.line);
}
| DEFAULT COLON {
$$ = context->addDefault($1.line);
}
;
// Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported.
condition
// In 1996 c++ draft, conditions can include single declarations
......@@ -1950,40 +1972,20 @@ for_rest_statement
jump_statement
: CONTINUE SEMICOLON {
if (context->loopNestingLevel <= 0) {
context->error($1.line, "continue statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpContinue, $1.line);
$$ = context->addBranch(EOpContinue, $1.line);
}
| BREAK SEMICOLON {
if (context->loopNestingLevel <= 0) {
context->error($1.line, "break statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpBreak, $1.line);
$$ = context->addBranch(EOpBreak, $1.line);
}
| RETURN SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, $1.line);
if (context->currentFunctionType->getBasicType() != EbtVoid) {
context->error($1.line, "non-void function must return a value", "return");
context->recover();
}
$$ = context->addBranch(EOpReturn, $1.line);
}
| RETURN expression SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, $2, $1.line);
context->functionReturnsValue = true;
if (context->currentFunctionType->getBasicType() == EbtVoid) {
context->error($1.line, "void function cannot return a value", "return");
context->recover();
} else if (*(context->currentFunctionType) != $2->getType()) {
context->error($1.line, "function return is not matching type:", "return");
context->recover();
}
$$ = context->addBranch(EOpReturn, $2, $1.line);
}
| DISCARD SEMICOLON {
FRAG_ONLY("discard", $1.line);
$$ = context->intermediate.addBranch(EOpKill, $1.line);
$$ = context->addBranch(EOpKill, $1.line);
}
;
......@@ -2065,7 +2067,7 @@ function_definition
// knows where to find parameters.
//
TIntermAggregate* paramNodes = new TIntermAggregate;
for (int i = 0; i < function->getParamCount(); i++) {
for (size_t i = 0; i < function->getParamCount(); i++) {
const TParameter& param = function->getParam(i);
if (param.name != 0) {
TVariable *variable = new TVariable(param.name, *param.type);
......
......@@ -193,6 +193,8 @@ typedef union YYSTYPE
TIntermNodePair nodePair;
TIntermTyped* intermTypedNode;
TIntermAggregate* intermAggregate;
TIntermSwitch* intermSwitch;
TIntermCase* intermCase;
};
union {
TPublicType type;
......
......@@ -78,7 +78,7 @@ void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
void TOutputTraverser::visitSymbol(TIntermSymbol* node)
{
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
sink << "'" << node->getSymbol() << "' ";
sink << "(" << node->getCompleteString() << ")\n";
......@@ -88,7 +88,7 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
{
TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
switch (node->getOp()) {
case EOpAssign: out << "move second child to first child"; break;
......@@ -152,7 +152,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
{
TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
switch (node->getOp()) {
case EOpNegative: out << "Negate value"; break;
......@@ -243,7 +243,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
return true;
}
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
switch (node->getOp()) {
case EOpSequence: out << "Sequence\n"; return true;
......@@ -316,18 +316,18 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
{
TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
out << "Test condition and select";
out << " (" << node->getCompleteString() << ")\n";
++depth;
++mDepth;
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
out << "Condition\n";
node->getCondition()->traverse(this);
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
if (node->getTrueBlock()) {
out << "true case\n";
node->getTrueBlock()->traverse(this);
......@@ -335,12 +335,12 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
out << "true case is null\n";
if (node->getFalseBlock()) {
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
out << "false case\n";
node->getFalseBlock()->traverse(this);
}
--depth;
--mDepth;
return false;
}
......@@ -352,7 +352,7 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
int size = node->getType().getObjectSize();
for (int i = 0; i < size; i++) {
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
switch (node->getUnionArrayPointer()[i].getType()) {
case EbtBool:
if (node->getUnionArrayPointer()[i].getBConst())
......@@ -386,23 +386,23 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
{
TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
out << "Loop with condition ";
if (node->getType() == ELoopDoWhile)
out << "not ";
out << "tested first\n";
++depth;
++mDepth;
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
if (node->getCondition()) {
out << "Loop Condition\n";
node->getCondition()->traverse(this);
} else
out << "No loop condition\n";
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
if (node->getBody()) {
out << "Loop Body\n";
node->getBody()->traverse(this);
......@@ -410,12 +410,12 @@ bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
out << "No loop body\n";
if (node->getExpression()) {
OutputTreeText(sink, node, depth);
OutputTreeText(sink, node, mDepth);
out << "Loop Terminal Expression\n";
node->getExpression()->traverse(this);
}
--depth;
--mDepth;
return false;
}
......@@ -424,7 +424,7 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
{
TInfoSinkBase& out = sink;
OutputTreeText(out, node, depth);
OutputTreeText(out, node, mDepth);
switch (node->getFlowOp()) {
case EOpKill: out << "Branch: Kill"; break;
......@@ -436,9 +436,9 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
if (node->getExpression()) {
out << " with expression\n";
++depth;
++mDepth;
node->getExpression()->traverse(this);
--depth;
--mDepth;
} else
out << "\n";
......
......@@ -242,6 +242,8 @@ class TIntermSymbol;
class TIntermLoop;
class TIntermBranch;
class TInfoSink;
class TIntermSwitch;
class TIntermCase;
//
// Base class for the tree nodes
......@@ -265,6 +267,8 @@ public:
virtual TIntermSymbol* getAsSymbolNode() { return 0; }
virtual TIntermLoop* getAsLoopNode() { return 0; }
virtual TIntermBranch* getAsBranchNode() { return 0; }
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
virtual TIntermCase *getAsCaseNode() { return 0; }
virtual ~TIntermNode() { }
protected:
......@@ -554,6 +558,49 @@ protected:
TIntermNode* falseBlock;
};
//
// Switch statement.
//
class TIntermSwitch : public TIntermNode
{
public:
TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList)
: TIntermNode(), mInit(init), mStatementList(statementList)
{}
void traverse(TIntermTraverser *it);
TIntermSwitch *getAsSwitchNode() { return this; }
TIntermAggregate *getStatementList() { return mStatementList; }
void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
protected:
TIntermTyped *mInit;
TIntermAggregate *mStatementList;
};
//
// Case label.
//
class TIntermCase : public TIntermNode
{
public:
TIntermCase(TIntermTyped *condition)
: TIntermNode(), mCondition(condition)
{}
void traverse(TIntermTraverser *it);
TIntermCase *getAsCaseNode() { return this; }
bool hasCondition() const { return mCondition != nullptr; }
TIntermTyped *getCondition() const { return mCondition; }
protected:
TIntermTyped *mCondition;
};
enum Visit
{
PreVisit,
......@@ -578,7 +625,7 @@ public:
inVisit(inVisit),
postVisit(postVisit),
rightToLeft(rightToLeft),
depth(0) {}
mDepth(0) {}
virtual ~TIntermTraverser() {};
virtual void visitSymbol(TIntermSymbol*) {}
......@@ -589,9 +636,25 @@ public:
virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
virtual bool visitSwitch(Visit, TIntermSwitch*) { return true; }
virtual bool visitCase(Visit, TIntermCase*) { return true; }
void incrementDepth(TIntermNode *current)
{
mDepth++;
mPath.push_back(current);
}
void incrementDepth() {depth++;}
void decrementDepth() {depth--;}
void decrementDepth()
{
mDepth--;
mPath.pop_back();
}
TIntermNode *getParentNode()
{
return mPath.size() == 0 ? NULL : mPath.back();
}
const bool preVisit;
const bool inVisit;
......@@ -599,7 +662,23 @@ public:
const bool rightToLeft;
protected:
int depth;
int mDepth;
// All the nodes from root to the current node's parent during traversing.
TVector<TIntermNode *> mPath;
private:
struct ParentBlock
{
ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn), pos(posIn)
{}
TIntermAggregate *node;
TIntermSequence::size_type pos;
};
// All the code blocks from the root to the current node's parent during traversal.
std::vector<ParentBlock> mParentBlockStack;
};
#endif // __INTERMEDIATE_H
......@@ -33,6 +33,8 @@ public:
TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc);
TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &line);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc);
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*);
......
......@@ -297,6 +297,8 @@
<Unit filename="../compiler/Types.h" />
<Unit filename="../compiler/ValidateLimitations.cpp" />
<Unit filename="../compiler/ValidateLimitations.h" />
<Unit filename="../compiler/ValidateSwitch.cpp" />
<Unit filename="../compiler/ValidateSwitch.h" />
<Unit filename="../compiler/debug.cpp" />
<Unit filename="../compiler/debug.h" />
<Unit filename="../compiler/glslang.h" />
......
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