[IRToProgram] Allow read-only references to be re-used.
Update the `Bind` method to be able to create re-usable bindings. This
allows things like loads of read-only textures/samplers to be re-used
and not require extra loads.
Change-Id: Ib48d7f8ac59c64702930692ecccd6868fbabc738
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/245534
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
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 a941f19..b0a5a7a 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
@@ -158,6 +158,11 @@
Symbol name; // Name of the variable
};
+ /// The structure for a reusable value
+ struct ReusableValue {
+ const core::ir::Value* expr = nullptr;
+ };
+
/// The structure for an inlined value
struct InlinedValue {
const ast::Expression* expr = nullptr;
@@ -168,7 +173,7 @@
/// ICE.
struct ConsumedValue {};
- using ValueBinding = std::variant<VariableValue, InlinedValue, ConsumedValue>;
+ using ValueBinding = std::variant<VariableValue, InlinedValue, ConsumedValue, ReusableValue>;
/// IR values to their representation
Hashmap<const core::ir::Value*, ValueBinding, 32> bindings_;
@@ -755,7 +760,18 @@
TINT_ICE_ON_NO_MATCH);
}
- void Load(const core::ir::Load* l) { Bind(l->Result(), Expr(l->From())); }
+ void Load(const core::ir::Load* l) {
+ bool reusable = false;
+ // Read-only pointer is reusable inline
+ if (auto* ptr = l->From()->Type()->As<core::type::Reference>()) {
+ reusable = ptr->Access() == core::Access::kRead;
+ }
+ if (reusable) {
+ Bind(l->Result(), l->From());
+ } else {
+ Bind(l->Result(), Expr(l->From()));
+ }
+ }
void LoadVectorElement(const core::ir::LoadVectorElement* l) {
auto* vec = Expr(l->From());
@@ -924,6 +940,9 @@
if constexpr (std::is_same_v<T, VariableValue>) {
return b.Expr(got.name);
}
+ if constexpr (std::is_same_v<T, ReusableValue>) {
+ return Expr(got.expr);
+ }
if constexpr (std::is_same_v<T, InlinedValue>) {
auto result = got.expr;
@@ -1231,6 +1250,15 @@
});
}
+ void Bind(const core::ir::Value* value, const core::ir::Value* expr) {
+ TINT_ASSERT(value);
+ if (value->IsUsed()) {
+ bindings_.Replace(value, ReusableValue{expr});
+ } else {
+ Append(b.Assign(b.Phony(), Expr(expr)));
+ }
+ }
+
/// Associates the IR value @p value with the AST expression @p expr if it is used, otherwise
/// creates a phony assignment with @p expr.
void Bind(const core::ir::Value* value, const ast::Expression* expr) {
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 a6b7673..6ce4c2d 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
@@ -34,6 +34,7 @@
#include "src/tint/lang/core/address_space.h"
#include "src/tint/lang/core/ir/disassembler.h"
#include "src/tint/lang/core/texel_format.h"
+#include "src/tint/lang/core/type/sampled_texture.h"
#include "src/tint/lang/core/type/storage_texture.h"
#include "src/tint/lang/core/type/texture_dimension.h"
#include "src/tint/lang/wgsl/ir/builtin_call.h"
@@ -1952,6 +1953,46 @@
}
////////////////////////////////////////////////////////////////////////////////
+// Load
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRToProgramTest, Load_Reused) {
+ auto im = b.Var(
+ "im",
+ ty.ref(handle, ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32()), read));
+ im->SetBindingPoint(0, 0);
+ auto sampler = b.Var("sampler", ty.ref(handle, ty.sampler(), read));
+ sampler->SetBindingPoint(0, 1);
+
+ b.ir.root_block->Append(im);
+ b.ir.root_block->Append(sampler);
+
+ auto* fn = b.Function("f", ty.void_());
+ b.Append(fn->Block(), [&] { //
+ auto* tl = b.Load(im);
+ auto* sl = b.Load(sampler);
+
+ b.Phony(b.Call<wgsl::ir::BuiltinCall>(ty.vec4<f32>(), wgsl::BuiltinFn::kTextureSample, tl,
+ sl, b.Splat(ty.vec2<f32>(), 0_f)));
+ b.Phony(b.Call<wgsl::ir::BuiltinCall>(ty.vec4<f32>(), wgsl::BuiltinFn::kTextureSample, tl,
+ sl, b.Splat(ty.vec2<f32>(), 0_f)));
+ b.Return(fn);
+ });
+
+ EXPECT_WGSL(R"(
+diagnostic(off, derivative_uniformity);
+
+@group(0u) @binding(0u) var im : texture_2d<f32>;
+
+@group(0u) @binding(1u) var v : sampler;
+
+fn f() {
+ _ = textureSample(im, v, vec2<f32>());
+ _ = textureSample(im, v, vec2<f32>());
+}
+)");
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Function-scope var
////////////////////////////////////////////////////////////////////////////////
TEST_F(IRToProgramTest, FunctionScopeVar_i32) {