[ir] When raising to a program handle unreachable as function terminator.
If an unreachable is the terminator of a function, and the function is
non-void, we swap the terminator out for a `return` of the function
return types zero value. This works around an issue where WGSL requires
a terminator, but does not have the behaviour analysis to determine if
the end of function is actually reachable or not.
Bug: 42250952
Change-Id: I5ef07147632d3ac54fdcc911cc844b959861626b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/246075
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/wgsl/ir_roundtrip_test.cc b/src/tint/lang/wgsl/ir_roundtrip_test.cc
index a829ee7..9a38177 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_test.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_test.cc
@@ -2318,6 +2318,17 @@
return 2.0f;
}
}
+)",
+ R"(
+fn f() -> f32 {
+ var cond : bool = true;
+ if (cond) {
+ return 1.0f;
+ } else {
+ return 2.0f;
+ }
+ return f32();
+}
)");
}
@@ -2639,6 +2650,7 @@
}
}
}
+ return i32();
}
)");
}
@@ -3351,6 +3363,24 @@
}
}
}
+)",
+ R"(
+fn f() -> i32 {
+ var i : i32;
+ switch(i) {
+ case 0i: {
+ return i;
+ }
+ case 1i: {
+ var i_1 : i32 = (i + 1i);
+ return i_1;
+ }
+ default: {
+ return i;
+ }
+ }
+ return i32();
+}
)");
}
@@ -3371,6 +3401,24 @@
}
}
}
+)",
+ R"(
+fn f() -> i32 {
+ var i : i32;
+ switch(i) {
+ case 0i: {
+ return i;
+ }
+ case 1i: {
+ let i_1 = (i + 1i);
+ return i_1;
+ }
+ default: {
+ return i;
+ }
+ }
+ return i32();
+}
)");
}
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 333781c..05e0edf 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -179,6 +179,9 @@
/// Map of struct to output program name.
Hashmap<const core::type::Struct*, Symbol, 8> structs_;
+ /// The current function being emitted.
+ const core::ir::Function* current_function_ = nullptr;
+
/// True if 'diagnostic(off, derivative_uniformity)' has been emitted
bool disabled_derivative_uniformity_ = false;
@@ -194,6 +197,7 @@
}
const ast::Function* Fn(const core::ir::Function* fn) {
TINT_SCOPED_ASSIGNMENT(nesting_depth_, nesting_depth_ + 1);
+ TINT_SCOPED_ASSIGNMENT(current_function_, fn);
// Emit parameters.
static constexpr size_t N = decltype(ast::Function::params)::static_length;
@@ -368,11 +372,26 @@
[&](const core::ir::Switch* i) { Switch(i); }, //
[&](const core::ir::Swizzle* i) { Swizzle(i); }, //
[&](const core::ir::Unary* i) { Unary(i); }, //
- [&](const core::ir::Unreachable*) {}, //
+ [&](const core::ir::Unreachable* u) { Unreachable(u); }, //
[&](const core::ir::Var* i) { Var(i); }, //
TINT_ICE_ON_NO_MATCH);
}
+ // In the case of an `unreachable` as the last statement in a non-void function, swap it to a
+ // `return` of the zero value for the return type. This is to satisfy the requirement for WGSL
+ // to always end in a `return` but `unreachable` really only meaning undefined behaviour if you
+ // get here.
+ void Unreachable(const core::ir::Unreachable* u) {
+ if (current_function_->ReturnType()->Is<core::type::Void>()) {
+ return;
+ }
+ if (u != current_function_->Block()->Terminator()) {
+ return;
+ }
+
+ Append(b.Return(b.Call(Type(current_function_->ReturnType()))));
+ }
+
void If(const core::ir::If* if_) {
TINT_SCOPED_ASSIGNMENT(nesting_depth_, nesting_depth_ + 1);
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index 6ce4c2d..9673652 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -95,6 +95,18 @@
)");
}
+TEST_F(IRToProgramTest, SingleFunction_Unreachable) {
+ auto* fn = b.Function("f", ty.u32());
+
+ fn->Block()->Append(b.Unreachable());
+
+ EXPECT_WGSL(R"(
+fn f() -> u32 {
+ return u32();
+}
+)");
+}
+
TEST_F(IRToProgramTest, SingleFunction_Return_i32) {
auto* fn = b.Function("f", ty.i32());
@@ -2187,6 +2199,7 @@
} else {
return 2.0f;
}
+ return f32();
}
)");
}