Remove no longer needed lSafeToRunWithAllLanesOff utility functions.
This commit is contained in:
212
stmt.cpp
212
stmt.cpp
@@ -655,7 +655,8 @@ IfStmt::emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Given an AST node, check to see if it's safe if we happen to run the
|
||||||
|
code for that node with the execution mask all off. */
|
||||||
static void
|
static void
|
||||||
lCheckAllOffSafety(ASTNode *node, void *data) {
|
lCheckAllOffSafety(ASTNode *node, void *data) {
|
||||||
bool *okPtr = (bool *)data;
|
bool *okPtr = (bool *)data;
|
||||||
@@ -721,213 +722,6 @@ lCheckAllOffSafety(ASTNode *node, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Similar to the Stmt variant of this function, this conservatively
|
|
||||||
checks to see if it's safe to run the code for the given Expr even if
|
|
||||||
the mask is 'all off'.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
lSafeToRunWithAllLanesOff(Expr *expr) {
|
|
||||||
if (expr == NULL)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
UnaryExpr *ue;
|
|
||||||
if ((ue = dynamic_cast<UnaryExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(ue->expr);
|
|
||||||
|
|
||||||
BinaryExpr *be;
|
|
||||||
if ((be = dynamic_cast<BinaryExpr *>(expr)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(be->arg0) &&
|
|
||||||
lSafeToRunWithAllLanesOff(be->arg1));
|
|
||||||
|
|
||||||
AssignExpr *ae;
|
|
||||||
if ((ae = dynamic_cast<AssignExpr *>(expr)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(ae->lvalue) &&
|
|
||||||
lSafeToRunWithAllLanesOff(ae->rvalue));
|
|
||||||
|
|
||||||
SelectExpr *se;
|
|
||||||
if ((se = dynamic_cast<SelectExpr *>(expr)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(se->test) &&
|
|
||||||
lSafeToRunWithAllLanesOff(se->expr1) &&
|
|
||||||
lSafeToRunWithAllLanesOff(se->expr2));
|
|
||||||
|
|
||||||
ExprList *el;
|
|
||||||
if ((el = dynamic_cast<ExprList *>(expr)) != NULL) {
|
|
||||||
for (unsigned int i = 0; i < el->exprs.size(); ++i)
|
|
||||||
if (!lSafeToRunWithAllLanesOff(el->exprs[i]))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionCallExpr *fce;
|
|
||||||
if ((fce = dynamic_cast<FunctionCallExpr *>(expr)) != NULL)
|
|
||||||
// FIXME: If we could somehow determine that the function being
|
|
||||||
// called was safe (and all of the args Exprs were safe, then it'd
|
|
||||||
// be nice to be able to return true here. (Consider a call to
|
|
||||||
// e.g. floatbits() in the stdlib.) Unfortunately for now we just
|
|
||||||
// have to be conservative.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
IndexExpr *ie;
|
|
||||||
if ((ie = dynamic_cast<IndexExpr *>(expr)) != NULL) {
|
|
||||||
// If we can determine at compile time the size of the array/vector
|
|
||||||
// and if the indices are compile-time constants, then we may be
|
|
||||||
// able to safely run this under a predicated if statement..
|
|
||||||
if (ie->baseExpr == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Type *type = ie->baseExpr->GetType();
|
|
||||||
ConstExpr *ce = dynamic_cast<ConstExpr *>(ie->index);
|
|
||||||
if (type == NULL || ce == NULL)
|
|
||||||
return false;
|
|
||||||
if (dynamic_cast<const ReferenceType *>(type) != NULL)
|
|
||||||
type = type->GetReferenceTarget();
|
|
||||||
|
|
||||||
const PointerType *pointerType =
|
|
||||||
dynamic_cast<const PointerType *>(type);
|
|
||||||
if (pointerType != NULL)
|
|
||||||
// pointer[offset] -> can't be sure
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const SequentialType *seqType =
|
|
||||||
dynamic_cast<const SequentialType *>(type);
|
|
||||||
Assert(seqType != NULL);
|
|
||||||
int nElements = seqType->GetElementCount();
|
|
||||||
if (nElements == 0)
|
|
||||||
// Unsized array, so we can't be sure
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int32_t indices[ISPC_MAX_NVEC];
|
|
||||||
int count = ce->AsInt32(indices);
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
if (indices[i] < 0 || indices[i] >= nElements)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// All indices are in-bounds
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MemberExpr *me;
|
|
||||||
if ((me = dynamic_cast<MemberExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(me->expr);
|
|
||||||
|
|
||||||
if (dynamic_cast<ConstExpr *>(expr) != NULL)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
TypeCastExpr *tce;
|
|
||||||
if ((tce = dynamic_cast<TypeCastExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(tce->expr);
|
|
||||||
|
|
||||||
ReferenceExpr *re;
|
|
||||||
if ((re = dynamic_cast<ReferenceExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(re->expr);
|
|
||||||
|
|
||||||
DereferenceExpr *dre;
|
|
||||||
if ((dre = dynamic_cast<DereferenceExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(dre->expr);
|
|
||||||
|
|
||||||
SizeOfExpr *soe;
|
|
||||||
if ((soe = dynamic_cast<SizeOfExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(soe->expr);
|
|
||||||
|
|
||||||
AddressOfExpr *aoe;
|
|
||||||
if ((aoe = dynamic_cast<AddressOfExpr *>(expr)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(aoe->expr);
|
|
||||||
|
|
||||||
if (dynamic_cast<SymbolExpr *>(expr) != NULL ||
|
|
||||||
dynamic_cast<FunctionSymbolExpr *>(expr) != NULL ||
|
|
||||||
dynamic_cast<SyncExpr *>(expr) != NULL ||
|
|
||||||
dynamic_cast<NullPointerExpr *>(expr) != NULL)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
FATAL("Unknown Expr type in lSafeToRunWithAllLanesOff()");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Given an arbitrary statement, this function conservatively tests to see
|
|
||||||
if it's safe to run the code for the statement even if the mask is all
|
|
||||||
off. Here we just need to determine which kind of statement we have
|
|
||||||
and recursively traverse it and/or the expressions inside of it.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
lSafeToRunWithAllLanesOff(Stmt *stmt) {
|
|
||||||
if (stmt == NULL)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ExprStmt *es;
|
|
||||||
if ((es = dynamic_cast<ExprStmt *>(stmt)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(es->expr);
|
|
||||||
|
|
||||||
DeclStmt *ds;
|
|
||||||
if ((ds = dynamic_cast<DeclStmt *>(stmt)) != NULL) {
|
|
||||||
for (unsigned int i = 0; i < ds->vars.size(); ++i)
|
|
||||||
if (!lSafeToRunWithAllLanesOff(ds->vars[i].init))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IfStmt *is;
|
|
||||||
if ((is = dynamic_cast<IfStmt *>(stmt)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(is->test) &&
|
|
||||||
lSafeToRunWithAllLanesOff(is->trueStmts) &&
|
|
||||||
lSafeToRunWithAllLanesOff(is->falseStmts));
|
|
||||||
|
|
||||||
DoStmt *dos;
|
|
||||||
if ((dos = dynamic_cast<DoStmt *>(stmt)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(dos->testExpr) &&
|
|
||||||
lSafeToRunWithAllLanesOff(dos->bodyStmts));
|
|
||||||
|
|
||||||
ForStmt *fs;
|
|
||||||
if ((fs = dynamic_cast<ForStmt *>(stmt)) != NULL)
|
|
||||||
return (lSafeToRunWithAllLanesOff(fs->init) &&
|
|
||||||
lSafeToRunWithAllLanesOff(fs->test) &&
|
|
||||||
lSafeToRunWithAllLanesOff(fs->step) &&
|
|
||||||
lSafeToRunWithAllLanesOff(fs->stmts));
|
|
||||||
|
|
||||||
ForeachStmt *fes;
|
|
||||||
if ((fes = dynamic_cast<ForeachStmt *>(stmt)) != NULL) {
|
|
||||||
for (unsigned int i = 0; i < fes->startExprs.size(); ++i)
|
|
||||||
if (!lSafeToRunWithAllLanesOff(fes->startExprs[i]))
|
|
||||||
return false;
|
|
||||||
for (unsigned int i = 0; i < fes->endExprs.size(); ++i)
|
|
||||||
if (!lSafeToRunWithAllLanesOff(fes->endExprs[i]))
|
|
||||||
return false;
|
|
||||||
return lSafeToRunWithAllLanesOff(fes->stmts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dynamic_cast<BreakStmt *>(stmt) != NULL ||
|
|
||||||
dynamic_cast<ContinueStmt *>(stmt) != NULL)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ReturnStmt *rs;
|
|
||||||
if ((rs = dynamic_cast<ReturnStmt *>(stmt)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(rs->val);
|
|
||||||
|
|
||||||
StmtList *sl;
|
|
||||||
if ((sl = dynamic_cast<StmtList *>(stmt)) != NULL) {
|
|
||||||
const std::vector<Stmt *> &sls = sl->GetStatements();
|
|
||||||
for (unsigned int i = 0; i < sls.size(); ++i)
|
|
||||||
if (!lSafeToRunWithAllLanesOff(sls[i]))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintStmt *ps;
|
|
||||||
if ((ps = dynamic_cast<PrintStmt *>(stmt)) != NULL)
|
|
||||||
return lSafeToRunWithAllLanesOff(ps->values);
|
|
||||||
|
|
||||||
AssertStmt *as;
|
|
||||||
if ((as = dynamic_cast<AssertStmt *>(stmt)) != NULL)
|
|
||||||
// While this is fine for varying tests, it's not going to be
|
|
||||||
// desirable to check an assert on a uniform variable if all of the
|
|
||||||
// lanes are off.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FATAL("Unexpected stmt type in lSafeToRunWithAllLanesOff()");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Emit code for an if test that checks the mask and the test values and
|
/** Emit code for an if test that checks the mask and the test values and
|
||||||
tries to be smart about jumping over code that doesn't need to be run.
|
tries to be smart about jumping over code that doesn't need to be run.
|
||||||
*/
|
*/
|
||||||
@@ -995,8 +789,6 @@ IfStmt::emitVaryingIf(FunctionEmitContext *ctx, llvm::Value *ltest) const {
|
|||||||
bool safeToRunWithAllLanesOff = true;
|
bool safeToRunWithAllLanesOff = true;
|
||||||
WalkAST(trueStmts, lCheckAllOffSafety, NULL, &safeToRunWithAllLanesOff);
|
WalkAST(trueStmts, lCheckAllOffSafety, NULL, &safeToRunWithAllLanesOff);
|
||||||
WalkAST(falseStmts, lCheckAllOffSafety, NULL, &safeToRunWithAllLanesOff);
|
WalkAST(falseStmts, lCheckAllOffSafety, NULL, &safeToRunWithAllLanesOff);
|
||||||
assert(safe == (lSafeToRunWithAllLanesOff(trueStmts) &
|
|
||||||
lSafeToRunWithAllLanesOff(falseStmts)));
|
|
||||||
|
|
||||||
if (safeToRunWithAllLanesOff &&
|
if (safeToRunWithAllLanesOff &&
|
||||||
(costIsAcceptable || g->opt.disableCoherentControlFlow)) {
|
(costIsAcceptable || g->opt.disableCoherentControlFlow)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user