Support do-while where test is negative.

This commit is contained in:
Hans-Kristian Arntzen 2019-03-06 12:17:38 +01:00
parent 70ff96b03f
commit ef24337849
13 changed files with 312 additions and 8 deletions

View File

@ -0,0 +1,13 @@
#version 450
void main()
{
int j = 0;
int i = 0;
do
{
j = ((j + i) + 1) * j;
i++;
} while (!(i == 20));
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; !(_12 == 16); _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; _12 != 16; _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; !(_12 == 16); _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,13 @@
#version 450
void main()
{
int i = 0;
int j = 0;
while (!(i == 20))
{
j = ((j + i) + 1) * j;
i++;
}
}

View File

@ -0,0 +1,51 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 28
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %i "i"
OpName %j "j"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
%j = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpStore %j %int_0
OpBranch %11
%11 = OpLabel
OpLoopMerge %13 %14 None
OpBranch %12
%12 = OpLabel
%15 = OpLoad %int %j
%16 = OpLoad %int %i
%17 = OpIAdd %int %15 %16
%19 = OpIAdd %int %17 %int_1
%20 = OpLoad %int %j
%21 = OpIMul %int %19 %20
OpStore %j %21
%22 = OpLoad %int %i
%23 = OpIAdd %int %22 %int_1
OpStore %i %23
OpBranch %14
%14 = OpLabel
%24 = OpLoad %int %i
%27 = OpIEqual %bool %24 %int_20
OpBranchConditional %27 %13 %11
%13 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,37 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpIEqual %bool %10 %int_16
OpBranchConditional %16 %18 %19
%18 = OpLabel
OpBranch %6
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,37 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpINotEqual %bool %10 %int_16
OpBranchConditional %16 %19 %18
%18 = OpLabel
OpBranch %6
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,35 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpIEqual %bool %10 %int_16
OpBranchConditional %16 %6 %19
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,53 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 29
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %i "i"
OpName %j "j"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
%j = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpStore %j %int_0
OpBranch %11
%11 = OpLabel
OpLoopMerge %13 %14 None
OpBranch %15
%15 = OpLabel
%16 = OpLoad %int %i
%19 = OpIEqual %bool %16 %int_20
OpBranchConditional %19 %13 %12
%12 = OpLabel
%20 = OpLoad %int %j
%21 = OpLoad %int %i
%22 = OpIAdd %int %20 %21
%24 = OpIAdd %int %22 %int_1
%25 = OpLoad %int %j
%26 = OpIMul %int %24 %25
OpStore %j %26
%27 = OpLoad %int %i
%28 = OpIAdd %int %27 %int_1
OpStore %i %28
OpBranch %14
%14 = OpLabel
OpBranch %11
%13 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -1611,8 +1611,20 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc
return SPIRBlock::ForLoop;
else
{
const auto *false_block = maybe_get<SPIRBlock>(block.false_block);
const auto *true_block = maybe_get<SPIRBlock>(block.true_block);
const auto *merge_block = maybe_get<SPIRBlock>(dominator.merge_block);
bool positive_do_while = block.true_block == dominator.self &&
(block.false_block == dominator.merge_block ||
(false_block && merge_block && execution_is_noop(*false_block, *merge_block)));
bool negative_do_while = block.false_block == dominator.self &&
(block.true_block == dominator.merge_block ||
(true_block && merge_block && execution_is_noop(*true_block, *merge_block)));
if (block.merge == SPIRBlock::MergeNone && block.terminator == SPIRBlock::Select &&
block.true_block == dominator.self && block.false_block == dominator.merge_block)
(positive_do_while || negative_do_while))
{
return SPIRBlock::DoWhileLoop;
}

View File

@ -10205,7 +10205,7 @@ void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
// FIXME: This currently cannot handle complex continue blocks
// as in do-while.
// This should be seen as a "trivial" continue block.
string CompilerGLSL::emit_continue_block(uint32_t continue_block)
string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
{
auto *block = &get<SPIRBlock>(continue_block);
@ -10233,11 +10233,20 @@ string CompilerGLSL::emit_continue_block(uint32_t continue_block)
block = &get<SPIRBlock>(block->next_block);
}
// For do while blocks. The last block will be a select block.
else if (block->true_block)
else if (block->true_block && follow_true_block)
{
flush_phi(continue_block, block->true_block);
block = &get<SPIRBlock>(block->true_block);
}
else if (block->false_block && follow_false_block)
{
flush_phi(continue_block, block->false_block);
block = &get<SPIRBlock>(block->false_block);
}
else
{
SPIRV_CROSS_THROW("Invalid continue block detected!");
}
}
// Restore old pointer.
@ -10400,7 +10409,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
emit_block_hints(block);
if (method != SPIRBlock::MergeToSelectContinueForLoop)
{
auto continue_block = emit_continue_block(block.continue_block);
auto continue_block = emit_continue_block(block.continue_block, false, false);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
}
else
@ -10476,7 +10485,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
target_block = child.false_block;
}
auto continue_block = emit_continue_block(block.continue_block);
auto continue_block = emit_continue_block(block.continue_block, false, false);
emit_block_hints(block);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
break;
@ -10617,6 +10626,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
{
flush_undeclared_variables(block);
emit_while_loop_initializers(block);
emitted_for_loop_header = true;
// We have some temporaries where the loop header is the dominator.
// We risk a case where we have code like:
// for (;;) { create-temporary; break; } consume-temporary;
@ -10908,7 +10918,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// Make sure that we run the continue block to get the expressions set, but this
// should become an empty string.
// We have no fallbacks if we cannot forward everything to temporaries ...
auto statements = emit_continue_block(block.continue_block);
const auto &continue_block = get<SPIRBlock>(block.continue_block);
bool positive_test =
execution_is_noop(get<SPIRBlock>(continue_block.true_block),
get<SPIRBlock>(continue_block.loop_dominator));
auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
if (!statements.empty())
{
// The DoWhile block has side effects, force ComplexLoop pattern next pass.
@ -10916,7 +10931,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
force_recompile = true;
}
end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
// Might have to invert the do-while test here.
auto condition = to_expression(continue_block.condition);
if (!positive_test)
condition = join("!", enclose_expression(condition));
end_scope_decl(join("while (", condition, ")"));
}
else
end_scope();

View File

@ -403,7 +403,7 @@ protected:
std::string constant_value_macro_name(uint32_t id);
void emit_constant(const SPIRConstant &constant);
void emit_specialization_constant_op(const SPIRConstantOp &constant);
std::string emit_continue_block(uint32_t continue_block);
std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block);
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
void propagate_loop_dominators(const SPIRBlock &block);