Add initial support for 'goto' statements.

ispc now supports goto, but only under uniform control flow--i.e.
it must be possible for the compiler to statically determine that
all program instances will follow the goto.  An error is issued at
compile time if a goto is used when this is not the case.
This commit is contained in:
Matt Pharr
2012-01-05 12:20:44 -08:00
parent 48e9d4af39
commit 78c6d3c02f
20 changed files with 408 additions and 15 deletions

127
stmt.cpp
View File

@@ -494,6 +494,7 @@ lEmitIfStatements(FunctionEmitContext *ctx, Stmt *stmts, const char *trueOrFalse
ctx->EndScope();
}
void
IfStmt::EmitCode(FunctionEmitContext *ctx) const {
// First check all of the things that might happen due to errors
@@ -1915,6 +1916,132 @@ ReturnStmt::Print(int indent) const {
}
///////////////////////////////////////////////////////////////////////////
// GotoStmt
GotoStmt::GotoStmt(const char *l, SourcePos gotoPos, SourcePos ip)
: Stmt(gotoPos) {
label = l;
identifierPos = ip;
}
void
GotoStmt::EmitCode(FunctionEmitContext *ctx) const {
if (ctx->VaryingCFDepth() > 0) {
Error(pos, "\"goto\" statements are only legal under \"uniform\" "
"control flow.");
return;
}
if (ctx->InForeachLoop()) {
Error(pos, "\"goto\" statements are currently illegal inside "
"\"foreach\" loops.");
return;
}
llvm::BasicBlock *bb = ctx->GetLabeledBasicBlock(label);
if (bb == NULL) {
// TODO: use the string distance stuff to suggest alternatives if
// there are some with names close to the label name we have here..
Error(identifierPos, "No label named \"%s\" found in current function.",
label.c_str());
return;
}
ctx->BranchInst(bb);
ctx->SetCurrentBasicBlock(NULL);
}
void
GotoStmt::Print(int indent) const {
printf("%*cGoto label \"%s\"\n", indent, ' ', label.c_str());
}
Stmt *
GotoStmt::Optimize() {
return this;
}
Stmt *
GotoStmt::TypeCheck() {
return this;
}
int
GotoStmt::EstimateCost() const {
return COST_GOTO;
}
///////////////////////////////////////////////////////////////////////////
// LabeledStmt
LabeledStmt::LabeledStmt(const char *n, Stmt *s, SourcePos p)
: Stmt(p) {
name = n;
stmt = s;
}
void
LabeledStmt::EmitCode(FunctionEmitContext *ctx) const {
llvm::BasicBlock *bblock = ctx->GetLabeledBasicBlock(name);
assert(bblock != NULL);
// End the current basic block with a jump to our basic block and then
// set things up for emission to continue there. Note that the current
// basic block may validly be NULL going into this statement due to an
// earlier goto that NULLed it out; that doesn't stop us from
// re-establishing a current basic block starting at the label..
if (ctx->GetCurrentBasicBlock() != NULL)
ctx->BranchInst(bblock);
ctx->SetCurrentBasicBlock(bblock);
if (stmt != NULL)
stmt->EmitCode(ctx);
}
void
LabeledStmt::Print(int indent) const {
printf("%*cLabel \"%s\"\n", indent, ' ', name.c_str());
if (stmt != NULL)
stmt->Print(indent);
}
Stmt *
LabeledStmt::Optimize() {
return this;
}
Stmt *
LabeledStmt::TypeCheck() {
if (!isalpha(name[0]) || name[0] == '_') {
Error(pos, "Label must start with either alphabetic character or '_'.");
return NULL;
}
for (unsigned int i = 1; i < name.size(); ++i) {
if (!isalnum(name[i]) && name[i] != '_') {
Error(pos, "Character \"%c\" is illegal in labels.", name[i]);
return NULL;
}
}
return this;
}
int
LabeledStmt::EstimateCost() const {
return 0;
}
///////////////////////////////////////////////////////////////////////////
// StmtList