Generate better code for break statements in varying loops (sometimes).

If we have a simple varying 'if' statement where the only code in the body is
a single 'break', then emit special case code that just updates the execution
mask directly.

Surprisingly, this leads to better generated code (e.g. Mandelbrot 7.1x on AVX
vs 5.8x before).  It's not clear why the general code generation path for
break doesn't generate the equivalent code; this topic should be investigated
further.  (Issue #277).
This commit is contained in:
Matt Pharr
2012-06-06 11:04:09 -07:00
parent 3c869802fb
commit f06caabb07

View File

@@ -362,6 +362,28 @@ lEmitIfStatements(FunctionEmitContext *ctx, Stmt *stmts, const char *trueOrFalse
}
/** Returns true if the "true" block for the if statement consists of a
single 'break' statement, and the "false" block is empty. */
static bool
lCanApplyBreakOptimization(Stmt *trueStmts, Stmt *falseStmts) {
if (falseStmts != NULL) {
if (StmtList *sl = dynamic_cast<StmtList *>(falseStmts)) {
return (sl->stmts.size() == 0);
}
else
return false;
}
if (dynamic_cast<BreakStmt *>(trueStmts))
return true;
else if (StmtList *sl = dynamic_cast<StmtList *>(trueStmts))
return (sl->stmts.size() == 1 &&
dynamic_cast<BreakStmt *>(sl->stmts[0]) != NULL);
else
return false;
}
void
IfStmt::EmitCode(FunctionEmitContext *ctx) const {
// First check all of the things that might happen due to errors
@@ -415,6 +437,15 @@ IfStmt::EmitCode(FunctionEmitContext *ctx) const {
ctx->SetCurrentBasicBlock(bexit);
ctx->EndIf();
}
else if (lCanApplyBreakOptimization(trueStmts, falseStmts)) {
// If we have a simple break statement inside the 'if' and are
// under varying control flow, just update the execution mask
// directly and don't emit code for the statements. This leads to
// better code for this case--this is surprising and should be
// root-caused further, but for now this gives us performance
// benefit in this case.
ctx->SetInternalMaskAndNot(ctx->GetInternalMask(), testValue);
}
else
emitVaryingIf(ctx, testValue);
}