Transition type checking to use WalkAST() infrastructure.

This commit is contained in:
Matt Pharr
2011-12-16 11:56:44 -08:00
parent f48a662ed3
commit 701334ccf2
8 changed files with 230 additions and 282 deletions

24
ast.cpp
View File

@@ -249,3 +249,27 @@ Stmt *
Optimize(Stmt *stmt) {
return (Stmt *)Optimize((ASTNode *)stmt);
}
static ASTNode *
lTypeCheckNode(ASTNode *node, void *) {
return node->TypeCheck();
}
ASTNode *
TypeCheck(ASTNode *root) {
return WalkAST(root, NULL, lTypeCheckNode, NULL);
}
Expr *
TypeCheck(Expr *expr) {
return (Expr *)TypeCheck((ASTNode *)expr);
}
Stmt *
TypeCheck(Stmt *stmt) {
return (Stmt *)TypeCheck((ASTNode *)stmt);
}

24
ast.h
View File

@@ -113,8 +113,28 @@ typedef ASTNode * (* ASTPostCallBackFunc)(ASTNode *node, void *data);
extern ASTNode *WalkAST(ASTNode *root, ASTPreCallBackFunc preFunc,
ASTPostCallBackFunc postFunc, void *data);
extern Expr *Optimize(Expr *);
extern Stmt *Optimize(Stmt *);
/** Perform simple optimizations on the AST or portion thereof passed to
this function, returning the resulting AST. */
extern ASTNode *Optimize(ASTNode *root);
/** Convenience version of Optimize() for Expr *s that returns an Expr *
(rather than an ASTNode *, which would require the caller to cast back
to an Expr *). */
extern Expr *Optimize(Expr *);
/** Convenience version of Optimize() for Expr *s that returns an Stmt *
(rather than an ASTNode *, which would require the caller to cast back
to a Stmt *). */
extern Stmt *Optimize(Stmt *);
/* Perform type-checking on the given AST (or portion of one), returning a
pointer to the root of the resulting AST. */
extern ASTNode *TypeCheck(ASTNode *root);
/* Convenience version of TypeCheck() for Expr *s that returns an Expr *. */
extern Expr *TypeCheck(Expr *);
/* Convenience version of TypeCheck() for Stmt *s that returns an Stmt *. */
extern Stmt *TypeCheck(Stmt *);
#endif // ISPC_AST_H

View File

@@ -381,7 +381,7 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
}
if (decl->initExpr != NULL &&
(decl->initExpr = decl->initExpr->TypeCheck()) != NULL &&
(decl->initExpr = TypeCheck(decl->initExpr)) != NULL &&
(decl->initExpr = Optimize(decl->initExpr)) != NULL &&
(init = dynamic_cast<ConstExpr *>(decl->initExpr)) == NULL) {
Error(decl->initExpr->pos, "Default value for parameter "

View File

@@ -142,7 +142,7 @@ lArrayToPointer(Expr *expr) {
Expr *zero = new ConstExpr(AtomicType::UniformInt32, 0, expr->pos);
Expr *index = new IndexExpr(expr, zero, expr->pos);
Expr *addr = new AddressOfExpr(index, expr->pos);
addr = addr->TypeCheck();
addr = TypeCheck(addr);
Assert(addr != NULL);
addr = Optimize(addr);
Assert(addr != NULL);
@@ -927,16 +927,11 @@ UnaryExpr::Optimize() {
Expr *
UnaryExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
if (expr == NULL)
const Type *type;
if (expr == NULL || (type = expr->GetType()) == NULL)
// something went wrong in type checking...
return NULL;
const Type *type = expr->GetType();
if (type == NULL)
return NULL;
if (op == PreInc || op == PreDec || op == PostInc || op == PostDec) {
if (type->IsConstType()) {
Error(pos, "Can't assign to type \"%s\" on left-hand side of "
@@ -1506,7 +1501,7 @@ BinaryExpr::Optimize() {
inv[i] = 1.f / inv[i];
Expr *einv = new ConstExpr(type1, inv, constArg1->pos);
Expr *e = new BinaryExpr(Mul, arg0, einv, pos);
e = e->TypeCheck();
e = ::TypeCheck(e);
if (e == NULL)
return NULL;
return ::Optimize(e);
@@ -1529,7 +1524,7 @@ BinaryExpr::Optimize() {
ExprList *args = new ExprList(arg1, arg1->pos);
Expr *rcpCall = new FunctionCallExpr(rcpSymExpr, args,
arg1->pos);
rcpCall = rcpCall->TypeCheck();
rcpCall = ::TypeCheck(rcpCall);
if (rcpCall == NULL)
return NULL;
rcpCall = ::Optimize(rcpCall);
@@ -1537,7 +1532,7 @@ BinaryExpr::Optimize() {
return NULL;
Expr *ret = new BinaryExpr(Mul, arg0, rcpCall, pos);
ret = ret->TypeCheck();
ret = ::TypeCheck(ret);
if (ret == NULL)
return NULL;
return ::Optimize(ret);
@@ -1628,11 +1623,6 @@ BinaryExpr::Optimize() {
Expr *
BinaryExpr::TypeCheck() {
if (arg0 != NULL)
arg0 = arg0->TypeCheck();
if (arg1 != NULL)
arg1 = arg1->TypeCheck();
if (arg0 == NULL || arg1 == NULL)
return NULL;
@@ -2124,10 +2114,6 @@ lCheckForConstStructMember(SourcePos pos, const StructType *structType,
Expr *
AssignExpr::TypeCheck() {
if (lvalue != NULL)
lvalue = lvalue->TypeCheck();
if (rvalue != NULL)
rvalue = rvalue->TypeCheck();
if (lvalue == NULL || rvalue == NULL)
return NULL;
@@ -2405,13 +2391,6 @@ SelectExpr::Optimize() {
Expr *
SelectExpr::TypeCheck() {
if (test)
test = test->TypeCheck();
if (expr1)
expr1 = expr1->TypeCheck();
if (expr2)
expr2 = expr2->TypeCheck();
if (test == NULL || expr1 == NULL || expr2 == NULL)
return NULL;
@@ -2636,14 +2615,9 @@ FunctionCallExpr::Optimize() {
Expr *
FunctionCallExpr::TypeCheck() {
if (func != NULL)
func = func->TypeCheck();
if (args != NULL)
args = args->TypeCheck();
if (launchCountExpr != NULL)
launchCountExpr = launchCountExpr->TypeCheck();
if (func == NULL || args == NULL)
return NULL;
if (args != NULL && func != NULL) {
std::vector<const Type *> argTypes;
std::vector<bool> argCouldBeNULL;
for (unsigned int i = 0; i < args->exprs.size(); ++i) {
@@ -2759,7 +2733,6 @@ FunctionCallExpr::TypeCheck() {
return NULL;
}
}
}
if (func == NULL || args == NULL)
return NULL;
@@ -2834,9 +2807,6 @@ ExprList::Optimize() {
ExprList *
ExprList::TypeCheck() {
for (unsigned int i = 0; i < exprs.size(); ++i)
if (exprs[i])
exprs[i] = exprs[i]->TypeCheck();
return this;
}
@@ -3199,16 +3169,11 @@ IndexExpr::Optimize() {
Expr *
IndexExpr::TypeCheck() {
if (baseExpr)
baseExpr = baseExpr->TypeCheck();
if (index)
index = index->TypeCheck();
if (!baseExpr || !index || !index->GetType())
if (baseExpr == NULL || index == NULL || index->GetType() == NULL)
return NULL;
const Type *baseExprType = baseExpr->GetType();
if (!baseExprType)
if (baseExprType == NULL)
return NULL;
if (!dynamic_cast<const SequentialType *>(baseExprType->GetReferenceTarget()) &&
@@ -3741,8 +3706,6 @@ MemberExpr::GetLValueType() const {
Expr *
MemberExpr::TypeCheck() {
if (expr)
expr = expr->TypeCheck();
return expr ? this : NULL;
}
@@ -5268,7 +5231,7 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
Assert(Type::EqualIgnoringConst(arrayAsPtr->GetType()->GetAsVaryingType(),
toPointerType) == true);
arrayAsPtr = new TypeCastExpr(toPointerType, arrayAsPtr, false, pos);
arrayAsPtr = arrayAsPtr->TypeCheck();
arrayAsPtr = ::TypeCheck(arrayAsPtr);
Assert(arrayAsPtr != NULL);
arrayAsPtr = ::Optimize(arrayAsPtr);
Assert(arrayAsPtr != NULL);
@@ -5435,8 +5398,6 @@ lDeconstifyType(const Type *t) {
Expr *
TypeCastExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
if (expr == NULL)
return NULL;
@@ -5448,7 +5409,7 @@ TypeCastExpr::TypeCheck() {
toType->IsVaryingType()) {
TypeCastExpr *tce = new TypeCastExpr(toType->GetAsUniformType(),
expr, false, pos);
return tce->TypeCheck();
return ::TypeCheck(tce);
}
fromType = lDeconstifyType(fromType);
@@ -5699,8 +5660,6 @@ ReferenceExpr::Optimize() {
Expr *
ReferenceExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
if (expr == NULL)
return NULL;
return this;
@@ -5797,8 +5756,6 @@ DereferenceExpr::GetType() const {
Expr *
DereferenceExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
if (expr == NULL)
return NULL;
return this;
@@ -5896,8 +5853,6 @@ AddressOfExpr::Print() const {
Expr *
AddressOfExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
return this;
}
@@ -5964,8 +5919,6 @@ SizeOfExpr::Print() const {
Expr *
SizeOfExpr::TypeCheck() {
if (expr != NULL)
expr = expr->TypeCheck();
return this;
}

View File

@@ -82,7 +82,7 @@ Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) {
fprintf(stderr, "---------------------\n");
}
code = code->TypeCheck();
code = TypeCheck(code);
if (code != NULL && g->debugPrint) {
fprintf(stderr, "After typechecking function \"%s\":\n",

View File

@@ -263,7 +263,7 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
"global variable \"%s\".", sym->name.c_str());
}
else if (initExpr != NULL) {
initExpr = initExpr->TypeCheck();
initExpr = TypeCheck(initExpr);
if (initExpr != NULL) {
// We need to make sure the initializer expression is
// the same type as the global. (But not if it's an

View File

@@ -1674,7 +1674,7 @@ static bool
lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage) {
if (expr == NULL)
return false;
expr = expr->TypeCheck();
expr = TypeCheck(expr);
if (expr == NULL)
return false;
expr = Optimize(expr);

105
stmt.cpp
View File

@@ -88,8 +88,6 @@ ExprStmt::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
ExprStmt::TypeCheck() {
if (expr)
expr = expr->TypeCheck();
return this;
}
@@ -420,18 +418,13 @@ Stmt *
DeclStmt::TypeCheck() {
bool encounteredError = false;
for (unsigned int i = 0; i < vars.size(); ++i) {
if (!vars[i].sym) {
if (vars[i].sym == NULL) {
encounteredError = true;
continue;
}
if (vars[i].init == NULL)
continue;
vars[i].init = vars[i].init->TypeCheck();
if (vars[i].init == NULL) {
encounteredError = true;
continue;
}
// get the right type for stuff like const float foo = 2; so that
// the int->float type conversion is in there and we don't return
@@ -565,8 +558,6 @@ IfStmt::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
IfStmt::TypeCheck() {
if (test != NULL) {
test = test->TypeCheck();
if (test != NULL) {
const Type *testType = test->GetType();
if (testType != NULL) {
@@ -579,11 +570,6 @@ IfStmt::TypeCheck() {
return NULL;
}
}
}
if (trueStmts != NULL)
trueStmts = trueStmts->TypeCheck();
if (falseStmts != NULL)
falseStmts = falseStmts->TypeCheck();
return this;
}
@@ -1122,31 +1108,30 @@ void DoStmt::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
DoStmt::TypeCheck() {
if (testExpr) {
testExpr = testExpr->TypeCheck();
if (testExpr) {
const Type *testType = testExpr->GetType();
if (testType) {
const Type *testType;
if (testExpr != NULL && (testType = testExpr->GetType()) != NULL) {
if (!testType->IsNumericType() && !testType->IsBoolType()) {
Error(testExpr->pos, "Type \"%s\" can't be converted to boolean for \"while\" "
"test in \"do\" loop.", testExpr->GetType()->GetString().c_str());
return NULL;
}
// Should the test condition for the loop be uniform or
// varying? It can be uniform only if three conditions are
// met. First and foremost, the type of the test condition
// must be uniform. Second, the user must not have set the
// dis-optimization option that disables uniform flow
// control.
// Should the test condition for the loop be uniform or varying?
// It can be uniform only if three conditions are met:
//
// - First and foremost, the type of the test condition must be
// uniform.
//
// - Second, the user must not have set the dis-optimization option
// that disables uniform flow control.
//
// - Thirdly, and most subtlely, there must not be any break or
// continue statements inside the loop that are within the scope
// of a 'varying' if statement. If there are, then we type cast
// the test to be 'varying', so that the code generated for the
// loop includes masking stuff, so that we can track which lanes
// actually want to be running, accounting for breaks/continues.
//
// Thirdly, and most subtlely, there must not be any break
// or continue statements inside the loop that are within
// the scope of a 'varying' if statement. If there are,
// then we type cast the test to be 'varying', so that the
// code generated for the loop includes masking stuff, so
// that we can track which lanes actually want to be
// running, accounting for breaks/continues.
bool uniformTest = (testType->IsUniformType() &&
!g->opt.disableUniformControlFlow &&
!lHasVaryingBreakOrContinue(bodyStmts));
@@ -1154,11 +1139,7 @@ DoStmt::TypeCheck() {
AtomicType::VaryingBool,
testExpr, false, testExpr->pos);
}
}
}
if (bodyStmts)
bodyStmts = bodyStmts->TypeCheck();
return this;
}
@@ -1324,14 +1305,11 @@ ForStmt::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
ForStmt::TypeCheck() {
if (test) {
test = test->TypeCheck();
if (test) {
const Type *testType = test->GetType();
if (testType) {
const Type *testType;
if (test && (testType = test->GetType()) != NULL) {
if (!testType->IsNumericType() && !testType->IsBoolType()) {
Error(test->pos, "Type \"%s\" can't be converted to boolean for for loop test.",
test->GetType()->GetString().c_str());
Error(test->pos, "Type \"%s\" can't be converted to boolean for \"for\" "
"loop test.", test->GetType()->GetString().c_str());
return NULL;
}
@@ -1343,16 +1321,11 @@ ForStmt::TypeCheck() {
test = new TypeCastExpr(uniformTest ? AtomicType::UniformBool :
AtomicType::VaryingBool,
test, false, test->pos);
}
}
test = ::TypeCheck(test);
if (test == NULL)
return NULL;
}
if (init)
init = init->TypeCheck();
if (step)
step = step->TypeCheck();
if (stmts)
stmts = stmts->TypeCheck();
return this;
}
@@ -1813,9 +1786,6 @@ Stmt *
ForeachStmt::TypeCheck() {
bool anyErrors = false;
for (unsigned int i = 0; i < startExprs.size(); ++i) {
// Typecheck first, to resolve function overloads
if (startExprs[i] != NULL)
startExprs[i] = startExprs[i]->TypeCheck();
if (startExprs[i] != NULL)
startExprs[i] = TypeConvertExpr(startExprs[i],
AtomicType::UniformInt32,
@@ -1823,18 +1793,12 @@ ForeachStmt::TypeCheck() {
anyErrors |= (startExprs[i] == NULL);
}
for (unsigned int i = 0; i < endExprs.size(); ++i) {
if (endExprs[i] != NULL)
endExprs[i] = endExprs[i]->TypeCheck();
if (endExprs[i] != NULL)
endExprs[i] = TypeConvertExpr(endExprs[i], AtomicType::UniformInt32,
"foreach ending value");
anyErrors |= (endExprs[i] == NULL);
}
if (stmts != NULL)
stmts = stmts->TypeCheck();
anyErrors |= (stmts == NULL);
if (startExprs.size() < dimVariables.size()) {
Error(pos, "Not enough initial values provided for \"foreach\" loop; "
"got %d, expected %d\n", (int)startExprs.size(), (int)dimVariables.size());
@@ -1938,11 +1902,6 @@ ReturnStmt::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
ReturnStmt::TypeCheck() {
// FIXME: We don't have ctx->functionType available here; should we?
// We ned up needing to type conversion stuff in EmitCode() method via
// FunctionEmitContext::SetReturnValue as a result, which is kind of ugly...
if (val)
val = val->TypeCheck();
return this;
}
@@ -1982,9 +1941,6 @@ StmtList::EmitCode(FunctionEmitContext *ctx) const {
Stmt *
StmtList::TypeCheck() {
for (unsigned int i = 0; i < stmts.size(); ++i)
if (stmts[i])
stmts[i] = stmts[i]->TypeCheck();
return this;
}
@@ -2194,8 +2150,6 @@ PrintStmt::Print(int indent) const {
Stmt *
PrintStmt::TypeCheck() {
if (values)
values = values->TypeCheck();
return this;
}
@@ -2270,11 +2224,8 @@ AssertStmt::Print(int indent) const {
Stmt *
AssertStmt::TypeCheck() {
if (expr)
expr = expr->TypeCheck();
if (expr) {
const Type *type = expr->GetType();
if (type) {
const Type *type;
if (expr && (type = expr->GetType()) != NULL) {
bool isUniform = type->IsUniformType();
if (!type->IsNumericType() && !type->IsBoolType()) {
Error(expr->pos, "Type \"%s\" can't be converted to boolean for \"assert\".",
@@ -2284,7 +2235,7 @@ AssertStmt::TypeCheck() {
expr = new TypeCastExpr(isUniform ? AtomicType::UniformBool :
AtomicType::VaryingBool,
expr, false, expr->pos);
}
expr = ::TypeCheck(expr);
}
return this;
}