Actually make all 'if' statements check for 'all off' mask.

Contrary to claims in 0c2048385, that checkin didn't include the changes
to not run if/else blocks if none of the program instances wanted to be
running them.  This checkin fixes that and thus actually fixes issue #74.
This commit is contained in:
Matt Pharr
2011-09-13 19:48:04 -07:00
parent e2a88d491f
commit 0848c2cc19
2 changed files with 48 additions and 54 deletions

View File

@@ -404,10 +404,10 @@ DeclStmt::Print(int indent) const {
IfStmt::IfStmt(Expr *t, Stmt *ts, Stmt *fs, bool checkCoherence, SourcePos p) IfStmt::IfStmt(Expr *t, Stmt *ts, Stmt *fs, bool checkCoherence, SourcePos p)
: Stmt(p), test(t), trueStmts(ts), falseStmts(fs), : Stmt(p), test(t), trueStmts(ts), falseStmts(fs),
doCoherentCheck(checkCoherence && doAllCheck(checkCoherence &&
(test->GetType() != NULL) && (test->GetType() != NULL) &&
test->GetType()->IsVaryingType() && test->GetType()->IsVaryingType() &&
!g->opt.disableCoherentControlFlow) { !g->opt.disableCoherentControlFlow) {
} }
@@ -439,62 +439,46 @@ IfStmt::EmitCode(FunctionEmitContext *ctx) const {
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
bool isUniform = testType->IsUniformType(); bool isUniform = testType->IsUniformType();
llvm::Value *testValue = test->GetValue(ctx);
if (testValue == NULL)
return;
if (isUniform) { if (isUniform) {
ctx->StartUniformIf(ctx->GetMask()); ctx->StartUniformIf(ctx->GetMask());
if (doCoherentCheck) if (doAllCheck)
Warning(test->pos, "Uniform condition supplied to \"cif\" statement."); Warning(test->pos, "Uniform condition supplied to \"cif\" statement.");
// 'If' statements with uniform conditions are relatively // 'If' statements with uniform conditions are relatively
// straightforward. We evaluate the condition and then jump to // straightforward. We evaluate the condition and then jump to
// either the 'then' or 'else' clause depending on its value. // either the 'then' or 'else' clause depending on its value.
llvm::Value *vtest = test->GetValue(ctx); llvm::BasicBlock *bthen = ctx->CreateBasicBlock("if_then");
if (vtest != NULL) { llvm::BasicBlock *belse = ctx->CreateBasicBlock("if_else");
llvm::BasicBlock *bthen = ctx->CreateBasicBlock("if_then"); llvm::BasicBlock *bexit = ctx->CreateBasicBlock("if_exit");
llvm::BasicBlock *belse = ctx->CreateBasicBlock("if_else");
llvm::BasicBlock *bexit = ctx->CreateBasicBlock("if_exit");
// Jump to the appropriate basic block based on the value of // Jump to the appropriate basic block based on the value of
// the 'if' test // the 'if' test
ctx->BranchInst(bthen, belse, vtest); ctx->BranchInst(bthen, belse, testValue);
// Emit code for the 'true' case // Emit code for the 'true' case
ctx->SetCurrentBasicBlock(bthen); ctx->SetCurrentBasicBlock(bthen);
lEmitIfStatements(ctx, trueStmts, "true"); lEmitIfStatements(ctx, trueStmts, "true");
if (ctx->GetCurrentBasicBlock()) if (ctx->GetCurrentBasicBlock())
ctx->BranchInst(bexit); ctx->BranchInst(bexit);
// Emit code for the 'false' case // Emit code for the 'false' case
ctx->SetCurrentBasicBlock(belse); ctx->SetCurrentBasicBlock(belse);
lEmitIfStatements(ctx, falseStmts, "false"); lEmitIfStatements(ctx, falseStmts, "false");
if (ctx->GetCurrentBasicBlock()) if (ctx->GetCurrentBasicBlock())
ctx->BranchInst(bexit); ctx->BranchInst(bexit);
// Set the active basic block to the newly-created exit block // Set the active basic block to the newly-created exit block
// so that subsequent emitted code starts there. // so that subsequent emitted code starts there.
ctx->SetCurrentBasicBlock(bexit); ctx->SetCurrentBasicBlock(bexit);
}
ctx->EndIf(); ctx->EndIf();
} }
else { else
// Code for 'If' statemnts with 'varying' conditions can be emitVaryingIf(ctx, testValue);
// generated in two ways; one takes some care to see if all of the
// active program instances want to follow only the 'true' or
// 'false' cases, and the other always runs both cases but sets the
// mask appropriately. The first case is handled by the
// IfStmt::emitCoherentTests() call, and the second is handled by
// IfStmt::emitMaskedTrueAndFalse().
llvm::Value *testValue = test->GetValue(ctx);
if (testValue) {
if (doCoherentCheck)
emitCoherentTests(ctx, testValue);
else {
llvm::Value *oldMask = ctx->GetMask();
ctx->StartVaryingIf(oldMask);
emitMaskedTrueAndFalse(ctx, oldMask, testValue);
ctx->EndIf();
}
}
}
} }
@@ -540,7 +524,7 @@ Stmt *IfStmt::TypeCheck() {
void void
IfStmt::Print(int indent) const { IfStmt::Print(int indent) const {
printf("%*cIf Stmt %s", indent, ' ', doCoherentCheck ? "DO COHERENT CHECK" : ""); printf("%*cIf Stmt %s", indent, ' ', doAllCheck ? "DO ALL CHECK" : "");
pos.Print(); pos.Print();
printf("\n%*cTest: ", indent+4, ' '); printf("\n%*cTest: ", indent+4, ' ');
test->Print(); test->Print();
@@ -581,7 +565,7 @@ IfStmt::emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask,
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.
*/ */
void void
IfStmt::emitCoherentTests(FunctionEmitContext *ctx, llvm::Value *ltest) const { IfStmt::emitVaryingIf(FunctionEmitContext *ctx, llvm::Value *ltest) const {
llvm::Value *oldMask = ctx->GetMask(); llvm::Value *oldMask = ctx->GetMask();
if (oldMask == LLVMMaskAllOn) { if (oldMask == LLVMMaskAllOn) {
// We can tell that the mask is on statically at compile time; just // We can tell that the mask is on statically at compile time; just
@@ -590,7 +574,7 @@ IfStmt::emitCoherentTests(FunctionEmitContext *ctx, llvm::Value *ltest) const {
emitMaskAllOn(ctx, ltest, bDone); emitMaskAllOn(ctx, ltest, bDone);
ctx->SetCurrentBasicBlock(bDone); ctx->SetCurrentBasicBlock(bDone);
} }
else { else if (doAllCheck) {
// We can't tell if the mask going into the if is all on at the // We can't tell if the mask going into the if is all on at the
// compile time. Emit code to check for this and then either run // compile time. Emit code to check for this and then either run
// the code for the 'all on' or the 'mixed' case depending on the // the code for the 'all on' or the 'mixed' case depending on the
@@ -618,6 +602,16 @@ IfStmt::emitCoherentTests(FunctionEmitContext *ctx, llvm::Value *ltest) const {
ctx->SetCurrentBasicBlock(bMixedOn); ctx->SetCurrentBasicBlock(bMixedOn);
emitMaskMixed(ctx, oldMask, ltest, bDone); emitMaskMixed(ctx, oldMask, ltest, bDone);
// When done, set the current basic block to the block that the two
// paths above jump to when they're done.
ctx->SetCurrentBasicBlock(bDone);
}
else {
llvm::BasicBlock *bDone = ctx->CreateBasicBlock("cif_done");
// Emit emit code for the mixed mask case
emitMaskMixed(ctx, oldMask, ltest, bDone);
// When done, set the current basic block to the block that the two // When done, set the current basic block to the block that the two
// paths above jump to when they're done. // paths above jump to when they're done.
ctx->SetCurrentBasicBlock(bDone); ctx->SetCurrentBasicBlock(bDone);
@@ -701,7 +695,7 @@ IfStmt::emitMaskMixed(FunctionEmitContext *ctx, llvm::Value *oldMask,
// value of the test is on. (i.e. (test&mask) == mask). In this case, // value of the test is on. (i.e. (test&mask) == mask). In this case,
// we only need to run the 'true' case code, since the lanes where the // we only need to run the 'true' case code, since the lanes where the
// test was false aren't supposed to be running here anyway. // test was false aren't supposed to be running here anyway.
llvm::Value *testAllEqual = lTestMatchesMask(ctx, ltest, oldMask); llvm::Value *testAllEqual = lTestMatchesMask(ctx, ltest, oldMask);
llvm::BasicBlock *bTestAll = ctx->CreateBasicBlock("cif_mixed_test_all"); llvm::BasicBlock *bTestAll = ctx->CreateBasicBlock("cif_mixed_test_all");
llvm::BasicBlock *bTestAnyCheck = ctx->CreateBasicBlock("cif_mixed_test_any_check"); llvm::BasicBlock *bTestAnyCheck = ctx->CreateBasicBlock("cif_mixed_test_any_check");
ctx->BranchInst(bTestAll, bTestAnyCheck, testAllEqual); ctx->BranchInst(bTestAll, bTestAnyCheck, testAllEqual);

6
stmt.h
View File

@@ -103,7 +103,7 @@ private:
class IfStmt : public Stmt { class IfStmt : public Stmt {
public: public:
IfStmt(Expr *testExpr, Stmt *trueStmts, Stmt *falseStmts, IfStmt(Expr *testExpr, Stmt *trueStmts, Stmt *falseStmts,
bool doCoherentCheck, SourcePos pos); bool doAllCheck, SourcePos pos);
void EmitCode(FunctionEmitContext *ctx) const; void EmitCode(FunctionEmitContext *ctx) const;
void Print(int indent) const; void Print(int indent) const;
@@ -125,11 +125,11 @@ private:
source and thus, if the emitted code should check to see if all source and thus, if the emitted code should check to see if all
active program instances want to follow just one of the 'true' or active program instances want to follow just one of the 'true' or
'false' blocks. */ 'false' blocks. */
const bool doCoherentCheck; const bool doAllCheck;
void emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask, void emitMaskedTrueAndFalse(FunctionEmitContext *ctx, llvm::Value *oldMask,
llvm::Value *test) const; llvm::Value *test) const;
void emitCoherentTests(FunctionEmitContext *ctx, llvm::Value *test) const; void emitVaryingIf(FunctionEmitContext *ctx, llvm::Value *test) const;
void emitMaskAllOn(FunctionEmitContext *ctx, void emitMaskAllOn(FunctionEmitContext *ctx,
llvm::Value *test, llvm::BasicBlock *bDone) const; llvm::Value *test, llvm::BasicBlock *bDone) const;
void emitMaskMixed(FunctionEmitContext *ctx, llvm::Value *oldMask, void emitMaskMixed(FunctionEmitContext *ctx, llvm::Value *oldMask,