Fix bugs with mask-handling for switch/do/for/while statements.

All of these pass the current mask to FunctionEmitContext::SetBlockEntryMask()
so that when a break/continue/return is encountered, it can test to see if all
lanes have followed that path and then return; this in turn ensures that we never
run statements with an all-off execution mask.

These functions were passing the function internal mask, not the full mask, and
thus could end up executing code with the mask all off if some lanes were
disabled by an outer function.  (The new tests test this case.)
This commit is contained in:
Matt Pharr
2012-07-09 15:13:30 -07:00
parent bc7775aef2
commit 926b3b9ee3
4 changed files with 93 additions and 3 deletions

View File

@@ -830,7 +830,7 @@ void DoStmt::EmitCode(FunctionEmitContext *ctx) const {
// And now emit code for the loop body
ctx->SetCurrentBasicBlock(bloop);
ctx->SetBlockEntryMask(ctx->GetInternalMask());
ctx->SetBlockEntryMask(ctx->GetFullMask());
ctx->SetDebugPos(pos);
// FIXME: in the StmtList::EmitCode() method takes starts/stops a new
// scope around the statements in the list. So if the body is just a
@@ -1047,7 +1047,7 @@ ForStmt::EmitCode(FunctionEmitContext *ctx) const {
// On to emitting the code for the loop body.
ctx->SetCurrentBasicBlock(bloop);
ctx->SetBlockEntryMask(ctx->GetInternalMask());
ctx->SetBlockEntryMask(ctx->GetFullMask());
ctx->AddInstrumentationPoint("for loop body");
if (!dynamic_cast<StmtList *>(stmts))
ctx->StartScope();
@@ -2555,7 +2555,7 @@ SwitchStmt::EmitCode(FunctionEmitContext *ctx) const {
bool isUniformCF = (type->IsUniformType() &&
lHasVaryingBreakOrContinue(stmts) == false);
ctx->StartSwitch(isUniformCF, bbDone);
ctx->SetBlockEntryMask(ctx->GetInternalMask());
ctx->SetBlockEntryMask(ctx->GetFullMask());
ctx->SwitchInst(exprValue, svi.defaultBlock ? svi.defaultBlock : bbDone,
svi.caseBlocks, svi.nextBlock);

30
tests/entry-mask-do.ispc Normal file
View File

@@ -0,0 +1,30 @@
export uniform int width() { return programCount; }
int * uniform ptr = NULL;
int func(int v) {
int ret;
// print("%\n", v);
do {
if (v == 0) {
ret = 1;
break;
}
*ptr = 1;
} while(true);
return ret;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
int count = 10;
if (programIndex & 1)
count = 0x7ffffff;
RET[programIndex] = 0;
if (!(programIndex & 1))
RET[programIndex] = func(programIndex & 1);
}
export void result(uniform float RET[]) {
RET[programIndex] = !(programIndex & 1);
}

30
tests/entry-mask-for.ispc Normal file
View File

@@ -0,0 +1,30 @@
export uniform int width() { return programCount; }
int * uniform ptr = NULL;
int func(int v) {
int ret;
// print("%\n", v);
for (;;) {
if (v == 0) {
ret = 1;
break;
}
*ptr = 1;
}
return ret;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
int count = 10;
if (programIndex & 1)
count = 0x7ffffff;
RET[programIndex] = 0;
if (!(programIndex & 1))
RET[programIndex] = func(programIndex & 1);
}
export void result(uniform float RET[]) {
RET[programIndex] = !(programIndex & 1);
}

View File

@@ -0,0 +1,30 @@
export uniform int width() { return programCount; }
int * uniform ptr = NULL;
int func(int v) {
int ret;
// print("%\n", v);
switch (v) {
case 0:
ret = 1;
break;
case 1:
*ptr = 1;
}
return ret;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {
int count = 10;
if (programIndex & 1)
count = 0x7ffffff;
RET[programIndex] = 0;
if (!(programIndex & 1))
RET[programIndex] = func(programIndex & 1);
}
export void result(uniform float RET[]) {
RET[programIndex] = !(programIndex & 1);
}