diff --git a/ctx.cpp b/ctx.cpp index a2a07fb7..074ad583 100644 --- a/ctx.cpp +++ b/ctx.cpp @@ -741,6 +741,7 @@ FunctionEmitContext::Break(bool doCoherenceCheck) { // that have executed a 'break' statement: // breakLanes = breakLanes | mask AssertPos(currentPos, breakLanesPtr != NULL); + llvm::Value *mask = GetInternalMask(); llvm::Value *breakMask = LoadInst(breakLanesPtr, "break_mask"); @@ -879,7 +880,7 @@ FunctionEmitContext::jumpIfAllLoopLanesAreDone(llvm::BasicBlock *target) { finishedLanes = BinaryOperator(llvm::Instruction::Or, finishedLanes, continued, "returned|breaked|continued"); } - + finishedLanes = BinaryOperator(llvm::Instruction::And, finishedLanes, GetFunctionMask(), "finished&func"); @@ -923,6 +924,16 @@ FunctionEmitContext::RestoreContinuedLanes() { } +void +FunctionEmitContext::ClearBreakLanes() { + if (breakLanesPtr == NULL) + return; + + // breakLanes = 0 + StoreInst(LLVMMaskAllOff, breakLanesPtr); +} + + void FunctionEmitContext::StartSwitch(bool cfIsUniform, llvm::BasicBlock *bbBreak) { llvm::Value *oldMask = GetInternalMask(); diff --git a/ctx.h b/ctx.h index 5df2e23c..0cfe4549 100644 --- a/ctx.h +++ b/ctx.h @@ -195,6 +195,13 @@ public: 'continue' statement when going through the loop body in the previous iteration. */ void RestoreContinuedLanes(); + + /** This method is called by code emitting IR for a loop. It clears + any lanes that contained a break since the mask has been updated to take + them into account. This is necessary as all the bail out checks for + breaks are meant to only deal with lanes breaking on the current iteration. + */ + void ClearBreakLanes(); /** Indicates that code generation for a "switch" statement is about to start. isUniform indicates whether the "switch" value is uniform, diff --git a/stmt.cpp b/stmt.cpp index b741b61e..ac22cff8 100644 --- a/stmt.cpp +++ b/stmt.cpp @@ -532,7 +532,6 @@ IfStmt::emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask, } } - /** 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. */ @@ -902,8 +901,10 @@ void DoStmt::EmitCode(FunctionEmitContext *ctx) const { // the code for the test. This is only necessary for varying loops; // 'uniform' loops just jump when they hit a continue statement and // don't mess with the mask. - if (!uniformTest) + if (!uniformTest) { ctx->RestoreContinuedLanes(); + ctx->ClearBreakLanes(); + } llvm::Value *testValue = testExpr->GetValue(ctx); if (!testValue) return; @@ -1111,6 +1112,8 @@ ForStmt::EmitCode(FunctionEmitContext *ctx) const { // test code. ctx->SetCurrentBasicBlock(bstep); ctx->RestoreContinuedLanes(); + ctx->ClearBreakLanes(); + if (step) step->EmitCode(ctx); ctx->BranchInst(btest);