Support do-while where test is negative.
This commit is contained in:
parent
70ff96b03f
commit
ef24337849
@ -0,0 +1,13 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
int i = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
j = ((j + i) + 1) * j;
|
||||||
|
i++;
|
||||||
|
} while (!(i == 20));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int _13;
|
||||||
|
for (int _12 = 0; !(_12 == 16); _12 = _13)
|
||||||
|
{
|
||||||
|
_13 = _12 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int _13;
|
||||||
|
for (int _12 = 0; _12 != 16; _12 = _13)
|
||||||
|
{
|
||||||
|
_13 = _12 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int _13;
|
||||||
|
for (int _12 = 0; !(_12 == 16); _12 = _13)
|
||||||
|
{
|
||||||
|
_13 = _12 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
while (!(i == 20))
|
||||||
|
{
|
||||||
|
j = ((j + i) + 1) * j;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
51
shaders-no-opt/asm/frag/do-while-loop-inverted-test.asm.frag
Normal file
51
shaders-no-opt/asm/frag/do-while-loop-inverted-test.asm.frag
Normal 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
|
@ -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
|
@ -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
|
35
shaders-no-opt/asm/frag/for-loop-inverted-test.asm.frag
Normal file
35
shaders-no-opt/asm/frag/for-loop-inverted-test.asm.frag
Normal 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
|
53
shaders-no-opt/asm/frag/while-loop-inverted-test.asm.frag
Normal file
53
shaders-no-opt/asm/frag/while-loop-inverted-test.asm.frag
Normal 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
|
@ -1611,8 +1611,20 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc
|
|||||||
return SPIRBlock::ForLoop;
|
return SPIRBlock::ForLoop;
|
||||||
else
|
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 &&
|
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;
|
return SPIRBlock::DoWhileLoop;
|
||||||
}
|
}
|
||||||
|
@ -10205,7 +10205,7 @@ void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
|
|||||||
// FIXME: This currently cannot handle complex continue blocks
|
// FIXME: This currently cannot handle complex continue blocks
|
||||||
// as in do-while.
|
// as in do-while.
|
||||||
// This should be seen as a "trivial" continue block.
|
// 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);
|
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);
|
block = &get<SPIRBlock>(block->next_block);
|
||||||
}
|
}
|
||||||
// For do while blocks. The last block will be a select 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);
|
flush_phi(continue_block, block->true_block);
|
||||||
block = &get<SPIRBlock>(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.
|
// Restore old pointer.
|
||||||
@ -10400,7 +10409,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
|||||||
emit_block_hints(block);
|
emit_block_hints(block);
|
||||||
if (method != SPIRBlock::MergeToSelectContinueForLoop)
|
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, ")");
|
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -10476,7 +10485,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
|||||||
target_block = child.false_block;
|
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);
|
emit_block_hints(block);
|
||||||
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
|
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
|
||||||
break;
|
break;
|
||||||
@ -10617,6 +10626,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|||||||
{
|
{
|
||||||
flush_undeclared_variables(block);
|
flush_undeclared_variables(block);
|
||||||
emit_while_loop_initializers(block);
|
emit_while_loop_initializers(block);
|
||||||
|
emitted_for_loop_header = true;
|
||||||
// We have some temporaries where the loop header is the dominator.
|
// We have some temporaries where the loop header is the dominator.
|
||||||
// We risk a case where we have code like:
|
// We risk a case where we have code like:
|
||||||
// for (;;) { create-temporary; break; } consume-temporary;
|
// 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
|
// Make sure that we run the continue block to get the expressions set, but this
|
||||||
// should become an empty string.
|
// should become an empty string.
|
||||||
// We have no fallbacks if we cannot forward everything to temporaries ...
|
// 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())
|
if (!statements.empty())
|
||||||
{
|
{
|
||||||
// The DoWhile block has side effects, force ComplexLoop pattern next pass.
|
// 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;
|
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
|
else
|
||||||
end_scope();
|
end_scope();
|
||||||
|
@ -403,7 +403,7 @@ protected:
|
|||||||
std::string constant_value_macro_name(uint32_t id);
|
std::string constant_value_macro_name(uint32_t id);
|
||||||
void emit_constant(const SPIRConstant &constant);
|
void emit_constant(const SPIRConstant &constant);
|
||||||
void emit_specialization_constant_op(const SPIRConstantOp &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);
|
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
|
||||||
void propagate_loop_dominators(const SPIRBlock &block);
|
void propagate_loop_dominators(const SPIRBlock &block);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user