[spirv-writer] Fix atomics after discard
Run DemoteToHelper before any SPIR-V transforms, as core transforms
are not aware of the potential side effects of non-core instructions.
Added an assertion in DemoteToHelper to capture this ordering
requirement with a TODO to use the validator to catch it instead.
Fixed: tint:2093
Change-Id: I1be205d2737831ba6bddc0e67d4763e2c963696c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/161142
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper.cc b/src/tint/lang/core/ir/transform/demote_to_helper.cc
index e8aed9b..dc77727 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper.cc
@@ -204,6 +204,10 @@
[&](ControlInstruction* ctrl) {
// Recurse into control instructions.
ctrl->ForeachBlock([&](Block* blk) { ProcessBlock(blk); });
+ },
+ [&](BuiltinCall*) {
+ // TODO(crbug.com/tint/2102): Catch this with the validator instead.
+ TINT_UNREACHABLE() << "unexpected non-core instruction";
});
}
}
diff --git a/src/tint/lang/spirv/writer/discard_test.cc b/src/tint/lang/spirv/writer/discard_test.cc
index 5398726..5e9ccf9 100644
--- a/src/tint/lang/spirv/writer/discard_test.cc
+++ b/src/tint/lang/spirv/writer/discard_test.cc
@@ -85,5 +85,61 @@
)");
}
+TEST_F(SpirvWriterTest, DiscardBeforeAtomic) {
+ auto* buffer = b.Var("buffer", ty.ptr(storage, ty.atomic<i32>()));
+ buffer->SetBindingPoint(0, 0);
+ mod.root_block->Append(buffer);
+
+ auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
+ front_facing->SetBuiltin(core::ir::FunctionParam::Builtin::kFrontFacing);
+ auto* ep = b.Function("ep", ty.f32(), core::ir::Function::PipelineStage::kFragment);
+ ep->SetParams({front_facing});
+ ep->SetReturnLocation(0_u, {});
+
+ b.Append(ep->Block(), [&] {
+ auto* ifelse = b.If(front_facing);
+ b.Append(ifelse->True(), [&] { //
+ b.Discard();
+ b.ExitIf(ifelse);
+ });
+ b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, buffer, 1_i);
+ b.Return(ep, 0.5_f);
+ });
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST(R"(
+ ; Function ep_inner
+ %ep_inner = OpFunction %float None %16
+%front_facing = OpFunctionParameter %bool
+ %17 = OpLabel
+ OpSelectionMerge %18 None
+ OpBranchConditional %front_facing %19 %18
+ %19 = OpLabel
+ OpStore %continue_execution %false
+ OpBranch %18
+ %18 = OpLabel
+ %21 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+ %25 = OpLoad %bool %continue_execution
+ OpSelectionMerge %26 None
+ OpBranchConditional %25 %27 %28
+ %27 = OpLabel
+ %29 = OpAtomicIAdd %int %21 %uint_1 %uint_0 %int_1
+ OpBranch %26
+ %28 = OpLabel
+ OpBranch %26
+ %26 = OpLabel
+ %32 = OpPhi %int %29 %27 %33 %28
+ %34 = OpLoad %bool %continue_execution
+ %35 = OpLogicalEqual %bool %34 %false
+ OpSelectionMerge %36 None
+ OpBranchConditional %35 %37 %36
+ %37 = OpLabel
+ OpKill
+ %36 = OpLabel
+ OpReturnValue %float_0_5
+ OpFunctionEnd
+)");
+}
+
} // namespace
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/spirv/writer/raise/raise.cc b/src/tint/lang/spirv/writer/raise/raise.cc
index 8160fe6..fad09b4 100644
--- a/src/tint/lang/spirv/writer/raise/raise.cc
+++ b/src/tint/lang/spirv/writer/raise/raise.cc
@@ -133,8 +133,10 @@
// produce pointers to matrices.
RUN_TRANSFORM(core::ir::transform::CombineAccessInstructions, module);
- RUN_TRANSFORM(BuiltinPolyfill, module);
+ // DemoteToHelper must come before any transform that introduces non-core instructions.
RUN_TRANSFORM(core::ir::transform::DemoteToHelper, module);
+
+ RUN_TRANSFORM(BuiltinPolyfill, module);
RUN_TRANSFORM(ExpandImplicitSplats, module);
RUN_TRANSFORM(HandleMatrixArithmetic, module);
RUN_TRANSFORM(MergeReturn, module);