[spirv-reader] Uses in phis count as uses
This is required so we actually emit values that are only used
in phis.
Bug: tint:3, tint:215
Change-Id: I9d957a697839b8d09246905c3f28064f0bc01731
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27701
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 724ff47..f4ae488 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3244,27 +3244,25 @@
const auto* block_info = GetBlockInfo(block_id);
const auto block_pos = block_info->pos;
for (const auto& inst : *(block_info->basic_block)) {
- // Update the usage span for IDs used by this instruction.
- // But skip uses in OpPhi because they are handled differently.
- if (inst.opcode() != SpvOpPhi) {
- inst.ForEachInId([this, block_pos, block_info](const uint32_t* id_ptr) {
- auto* def_info = GetDefInfo(*id_ptr);
- if (def_info) {
- def_info->num_uses++;
- def_info->last_use_pos =
- std::max(def_info->last_use_pos, block_pos);
+ // Update bookkeeping for locally-defined IDs used by this instruction.
+ inst.ForEachInId([this, block_pos, block_info](const uint32_t* id_ptr) {
+ auto* def_info = GetDefInfo(*id_ptr);
+ if (def_info) {
+ // Update usage count.
+ def_info->num_uses++;
+ // Update usage span.
+ def_info->last_use_pos = std::max(def_info->last_use_pos, block_pos);
- // Determine whether this ID is defined in a different construct
- // from this use.
- const auto defining_block = block_order_[def_info->block_pos];
- const auto* def_in_construct =
- GetBlockInfo(defining_block)->construct;
- if (def_in_construct != block_info->construct) {
- def_info->used_in_another_construct = true;
- }
+ // Determine whether this ID is defined in a different construct
+ // from this use.
+ const auto defining_block = block_order_[def_info->block_pos];
+ const auto* def_in_construct =
+ GetBlockInfo(defining_block)->construct;
+ if (def_in_construct != block_info->construct) {
+ def_info->used_in_another_construct = true;
}
- });
- }
+ }
+ });
if (inst.opcode() == SpvOpPhi) {
// Declare a name for the variable used to carry values to a phi.
diff --git a/src/reader/spirv/function_var_test.cc b/src/reader/spirv/function_var_test.cc
index ebbac3d..d4a4601 100644
--- a/src/reader/spirv/function_var_test.cc
+++ b/src/reader/spirv/function_var_test.cc
@@ -1363,23 +1363,13 @@
}
}
}
- VariableDeclStatement{
- Variable{
- x_4
- none
- __u32
- {
- Binary{
- Identifier{x_2}
- add
- ScalarConstructor{1}
- }
- }
- }
- }
Assignment{
Identifier{x_2_phi}
- Identifier{x_4}
+ Binary{
+ Identifier{x_2}
+ add
+ ScalarConstructor{1}
+ }
}
Assignment{
Identifier{x_3_phi}
@@ -1497,6 +1487,13 @@
Loop{
VariableDeclStatement{
Variable{
+ x_4
+ function
+ __u32
+ }
+ }
+ VariableDeclStatement{
+ Variable{
x_2
none
__u32
@@ -1524,18 +1521,12 @@
}
}
continuing {
- VariableDeclStatement{
- Variable{
- x_4
- none
- __u32
- {
- Binary{
- Identifier{x_2}
- add
- ScalarConstructor{1}
- }
- }
+ Assignment{
+ Identifier{x_4}
+ Binary{
+ Identifier{x_2}
+ add
+ ScalarConstructor{1}
}
}
Assignment{
@@ -1634,6 +1625,13 @@
Loop{
VariableDeclStatement{
Variable{
+ x_7
+ function
+ __u32
+ }
+ }
+ VariableDeclStatement{
+ Variable{
x_2
none
__u32
@@ -1689,18 +1687,12 @@
}
}
continuing {
- VariableDeclStatement{
- Variable{
- x_7
- none
- __u32
- {
- Binary{
- Identifier{x_4}
- add
- Identifier{x_6}
- }
- }
+ Assignment{
+ Identifier{x_7}
+ Binary{
+ Identifier{x_4}
+ add
+ Identifier{x_6}
}
}
Assignment{
@@ -1957,6 +1949,103 @@
)")) << ToString(fe.ast_body());
}
+TEST_F(SpvParserTest, EmitStatement_UseInPhiCountsAsUse) {
+ // From crbug.com/215
+ // If the only use of a combinatorially computed ID is as the value
+ // in an OpPhi, then we still have to emit it. The algorithm fix
+ // is to always count uses in Phis.
+ // This is the reduced case from the bug report.
+ //
+ // The only use of %12 is in the phi.
+ // The only use of %11 is in %12.
+ // Both definintions need to be emitted to the output.
+ auto assembly = Preamble() + R"(
+ %100 = OpFunction %void None %voidfn
+
+ %10 = OpLabel
+ %11 = OpLogicalAnd %bool %true %true
+ %12 = OpLogicalNot %bool %11 ;
+ OpSelectionMerge %99 None
+ OpBranchConditional %true %20 %99
+
+ %20 = OpLabel
+ OpBranch %99
+
+ %99 = OpLabel
+ %101 = OpPhi %bool %11 %10 %12 %20
+ OpReturn
+
+ OpFunctionEnd
+
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+
+ EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(VariableDeclStatement{
+ Variable{
+ x_101_phi
+ function
+ __bool
+ }
+}
+VariableDeclStatement{
+ Variable{
+ x_11
+ none
+ __bool
+ {
+ Binary{
+ ScalarConstructor{true}
+ logical_and
+ ScalarConstructor{true}
+ }
+ }
+ }
+}
+VariableDeclStatement{
+ Variable{
+ x_12
+ none
+ __bool
+ {
+ UnaryOp{
+ not
+ Identifier{x_11}
+ }
+ }
+ }
+}
+Assignment{
+ Identifier{x_101_phi}
+ Identifier{x_11}
+}
+If{
+ (
+ ScalarConstructor{true}
+ )
+ {
+ Assignment{
+ Identifier{x_101_phi}
+ Identifier{x_12}
+ }
+ }
+}
+VariableDeclStatement{
+ Variable{
+ x_101
+ none
+ __bool
+ {
+ Identifier{x_101_phi}
+ }
+ }
+}
+Return{}
+)")) << ToString(fe.ast_body());
+}
+
} // namespace
} // namespace spirv
} // namespace reader