tint: Add implicit CF_return->{last cf} edge
If the function has no return statements, we need to do this to
capture the potential non-uniformity coming from nested function
calls.
This also removes the need to add explicit edges for discard
statements, so remove them.
Bug: tint:880
Change-Id: I88b1132faf35a6d36460ef353912f77a15f8abaa
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89861
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 33def3b..770e6ee 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -314,7 +314,8 @@
// Process function body.
if (func->body) {
- ProcessStatement(current_function_->cf_start, func->body);
+ auto* cf = ProcessStatement(current_function_->cf_start, func->body);
+ current_function_->cf_return->AddEdge(cf);
}
#if TINT_DUMP_UNIFORMITY_GRAPH
@@ -556,10 +557,7 @@
return cf;
},
- [&](const ast::DiscardStatement*) {
- current_function_->cf_return->AddEdge(cf);
- return cf;
- },
+ [&](const ast::DiscardStatement*) { return cf; },
[&](const ast::FallthroughStatement*) { return cf; },
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index 77a9dfe..037f573 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -401,6 +401,47 @@
)");
}
+TEST_F(UniformityAnalysisTest, SubsequentControlFlowMayBeNonUniform_Nested_Fail) {
+ // Indirectly call a function that causes subsequent control flow to be non-uniform, and then
+ // call another function that requires uniformity.
+ // The lack of return statement in `foo()` requires that we implicitly add an edge from
+ // CF_return to that last control flow node of the function.
+ auto src = R"(
+@group(0) @binding(0) var<storage, read_write> rw : i32;
+
+var<private> p : i32;
+
+fn bar() {
+ if (rw == 0) {
+ p = 42;
+ return;
+ }
+ p = 5;
+ return;
+}
+
+fn foo() {
+ bar();
+}
+
+fn main() {
+ foo();
+ workgroupBarrier();
+}
+)";
+
+ RunTest(src, false);
+ EXPECT_EQ(error_,
+ R"(test:21:3 warning: 'workgroupBarrier' must only be called from uniform control flow
+ workgroupBarrier();
+ ^^^^^^^^^^^^^^^^
+
+test:20:3 note: calling 'foo' may cause subsequent control flow to be non-uniform
+ foo();
+ ^^^
+)");
+}
+
TEST_F(UniformityAnalysisTest, ParameterNoRestriction_Pass) {
// Pass a non-uniform value as an argument, and then try to use the return value for
// control-flow guarding a barrier.