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:
31
stmt.cpp
31
stmt.cpp
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user