Implement barrier() control-flow rules: in flow control, non-main, and post-return.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@29347 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2015-01-07 06:14:06 +00:00
parent cbc7dd979a
commit 05a62bf528
8 changed files with 426 additions and 181 deletions

View file

@ -51,7 +51,8 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
bool fc, EShMessages m) :
intermediate(interm), symbolTable(symt), infoSink(is), language(L),
version(v), profile(p), forwardCompatible(fc), messages(m),
contextPragma(true, false), loopNestingLevel(0), controlFlowNestingLevel(0), structNestingLevel(0),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
postMainReturn(false),
tokensBeforeEOF(false), limits(resources.limits), currentScanner(0),
numErrors(0), parsingBuiltins(pb), afterEOF(false),
atomicUintOffsets(0), anyIndexLimits(false)
@ -915,7 +916,9 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
if (function.getType().getBasicType() != EbtVoid)
error(loc, "", function.getType().getBasicTypeString().c_str(), "main function cannot return a value");
intermediate.addMainCount();
}
inMain = true;
} else
inMain = false;
//
// New symbol table scope for body of function plus its arguments
@ -953,7 +956,9 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
}
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
loopNestingLevel = 0;
statementNestingLevel = 0;
controlFlowNestingLevel = 0;
postMainReturn = false;
return paramNodes;
}
@ -1045,6 +1050,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct
op = fnCandidate->getBuiltInOp();
if (builtIn && op != EOpNull) {
// A function call mapped to a built-in operation.
checkLocation(loc, op);
result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType());
if (result == 0) {
error(arguments->getLoc(), " wrong operand type", "Internal Error",
@ -1091,6 +1097,25 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct
return result;
}
// See if the operation is being done in an illegal location.
void TParseContext::checkLocation(TSourceLoc loc, TOperator op)
{
switch (op) {
case EOpBarrier:
if (language == EShLangTessControl) {
if (controlFlowNestingLevel > 0)
error(loc, "tessellation control barrier() cannot be placed within flow control", "", "");
if (! inMain)
error(loc, "tessellation control barrier() must be in main()", "", "");
else if (postMainReturn)
error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", "");
}
break;
default:
break;
}
}
// Finish processing object.length(). This started earlier in handleDotDereference(), where
// the ".length" part was recognized and semantically checked, and finished here where the
// function syntax "()" is recognized.

View file

@ -101,6 +101,7 @@ public:
TFunction* handleFunctionDeclarator(TSourceLoc loc, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(TSourceLoc, TFunction&);
TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*);
void checkLocation(TSourceLoc, TOperator);
TIntermTyped* handleLengthMethod(TSourceLoc, TFunction*, TIntermNode*);
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
@ -245,9 +246,12 @@ public:
struct TPragma contextPragma;
int loopNestingLevel; // 0 if outside all loops
int structNestingLevel; // 0 if outside blocks and structures
int controlFlowNestingLevel; // 0 if outside all flow control or compound statements; also counts compound statements
int controlFlowNestingLevel; // 0 if outside all flow control
int statementNestingLevel; // 0 if outside all flow control or compound statements
TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
TList<int> switchLevel; // the controlFlowNestingLevel the current switch statement is at, which must match the level of its case statements
TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements
bool inMain; // if inside a function, true if the function is main
bool postMainReturn; // if inside a function, true if the function is main and this is after a return statement
const TType* currentFunctionType; // the return type of the function that's currently being parsed
bool functionReturnsValue; // true if a non-void function has a return
const TString* blockName;

View file

@ -2065,11 +2065,11 @@ compound_statement
: LEFT_BRACE RIGHT_BRACE { $$ = 0; }
| LEFT_BRACE {
parseContext.symbolTable.push();
++parseContext.controlFlowNestingLevel;
++parseContext.statementNestingLevel;
}
statement_list {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
--parseContext.controlFlowNestingLevel;
--parseContext.statementNestingLevel;
}
RIGHT_BRACE {
if ($3 && $3->getAsAggregate())
@ -2084,13 +2084,21 @@ statement_no_new_scope
;
statement_scoped
: compound_statement { $$ = $1; }
: {
++parseContext.controlFlowNestingLevel;
}
compound_statement {
--parseContext.controlFlowNestingLevel;
$$ = $2;
}
| {
parseContext.symbolTable.push();
++parseContext.statementNestingLevel;
++parseContext.controlFlowNestingLevel;
}
simple_statement {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
$$ = $2;
}
@ -2171,8 +2179,9 @@ switch_statement
: SWITCH LEFT_PAREN expression RIGHT_PAREN {
// start new switch sequence on the switch stack
++parseContext.controlFlowNestingLevel;
++parseContext.statementNestingLevel;
parseContext.switchSequenceStack.push_back(new TIntermSequence);
parseContext.switchLevel.push_back(parseContext.controlFlowNestingLevel);
parseContext.switchLevel.push_back(parseContext.statementNestingLevel);
parseContext.symbolTable.push();
}
LEFT_BRACE switch_statement_list RIGHT_BRACE {
@ -2181,6 +2190,7 @@ switch_statement
parseContext.switchSequenceStack.pop_back();
parseContext.switchLevel.pop_back();
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
}
;
@ -2199,7 +2209,7 @@ case_label
$$ = 0;
if (parseContext.switchLevel.size() == 0)
parseContext.error($1.loc, "cannot appear outside switch statement", "case", "");
else if (parseContext.switchLevel.back() != parseContext.controlFlowNestingLevel)
else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel)
parseContext.error($1.loc, "cannot be nested inside control flow", "case", "");
else {
parseContext.constantValueCheck($2, "case");
@ -2211,7 +2221,7 @@ case_label
$$ = 0;
if (parseContext.switchLevel.size() == 0)
parseContext.error($1.loc, "cannot appear outside switch statement", "default", "");
else if (parseContext.switchLevel.back() != parseContext.controlFlowNestingLevel)
else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel)
parseContext.error($1.loc, "cannot be nested inside control flow", "default", "");
else
$$ = parseContext.intermediate.addBranch(EOpDefault, $1.loc);
@ -2224,16 +2234,19 @@ iteration_statement
parseContext.error($1.loc, "while loops not available", "limitation", "");
parseContext.symbolTable.push();
++parseContext.loopNestingLevel;
++parseContext.statementNestingLevel;
++parseContext.controlFlowNestingLevel;
}
condition RIGHT_PAREN statement_no_new_scope {
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
$$ = parseContext.intermediate.addLoop($6, $4, 0, true, $1.loc);
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
}
| DO {
++parseContext.loopNestingLevel;
++parseContext.statementNestingLevel;
++parseContext.controlFlowNestingLevel;
}
statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
@ -2244,11 +2257,13 @@ iteration_statement
$$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.loc);
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
}
| FOR LEFT_PAREN {
parseContext.symbolTable.push();
++parseContext.loopNestingLevel;
++parseContext.statementNestingLevel;
++parseContext.controlFlowNestingLevel;
}
for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
@ -2260,6 +2275,7 @@ iteration_statement
$$ = parseContext.intermediate.growAggregate($$, forLoop, $1.loc);
$$->getAsAggregate()->setOperator(EOpSequence);
--parseContext.loopNestingLevel;
--parseContext.statementNestingLevel;
--parseContext.controlFlowNestingLevel;
}
;
@ -2308,6 +2324,8 @@ jump_statement
$$ = parseContext.intermediate.addBranch(EOpReturn, $1.loc);
if (parseContext.currentFunctionType->getBasicType() != EbtVoid)
parseContext.error($1.loc, "non-void function must return a value", "return", "");
if (parseContext.inMain)
parseContext.postMainReturn = true;
}
| RETURN expression SEMICOLON {
parseContext.functionReturnsValue = true;