diff --git a/stmt.cpp b/stmt.cpp index eb626c0b..974af871 100644 --- a/stmt.cpp +++ b/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(falseStmts)) { + return (sl->stmts.size() == 0); + } + else + return false; + } + + if (dynamic_cast(trueStmts)) + return true; + else if (StmtList *sl = dynamic_cast(trueStmts)) + return (sl->stmts.size() == 1 && + dynamic_cast(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); }