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:
96
stmt.cpp
96
stmt.cpp
@@ -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
6
stmt.h
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user