[ir] Handle array types in substitute overrides
This CL adds support to Substitute Overrides to handle array types which
use an override as the array count.
Bug: 374971092
Change-Id: Icb64955d44d6733423cb60a5b4af201e7c26d076
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/213916
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/BUILD.bazel b/src/tint/lang/core/ir/BUILD.bazel
index 74c159a..5f6dbd9 100644
--- a/src/tint/lang/core/ir/BUILD.bazel
+++ b/src/tint/lang/core/ir/BUILD.bazel
@@ -159,6 +159,7 @@
"//src/tint/lang/core",
"//src/tint/lang/core/constant",
"//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir/type",
"//src/tint/lang/core/type",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
diff --git a/src/tint/lang/core/ir/BUILD.cmake b/src/tint/lang/core/ir/BUILD.cmake
index 3af8189..ae3de43 100644
--- a/src/tint/lang/core/ir/BUILD.cmake
+++ b/src/tint/lang/core/ir/BUILD.cmake
@@ -36,6 +36,7 @@
include(lang/core/ir/binary/BUILD.cmake)
include(lang/core/ir/transform/BUILD.cmake)
+include(lang/core/ir/type/BUILD.cmake)
################################################################################
# Target: tint_lang_core_ir
@@ -161,6 +162,7 @@
tint_lang_core
tint_lang_core_constant
tint_lang_core_intrinsic
+ tint_lang_core_ir_type
tint_lang_core_type
tint_utils_containers
tint_utils_diagnostic
diff --git a/src/tint/lang/core/ir/BUILD.gn b/src/tint/lang/core/ir/BUILD.gn
index 15a78d0..1fa9bdd 100644
--- a/src/tint/lang/core/ir/BUILD.gn
+++ b/src/tint/lang/core/ir/BUILD.gn
@@ -164,6 +164,7 @@
"${tint_src_dir}/lang/core",
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir/type",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 4d9091a..59c6cb1 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -32,7 +32,6 @@
#include <optional>
#include <string_view>
-#include "src//tint/lang/core/ir/unary.h"
#include "src/tint/lang/core/binary_op.h"
#include "src/tint/lang/core/constant/composite.h"
#include "src/tint/lang/core/constant/scalar.h"
@@ -60,10 +59,14 @@
#include "src/tint/lang/core/ir/switch.h"
#include "src/tint/lang/core/ir/swizzle.h"
#include "src/tint/lang/core/ir/terminate_invocation.h"
+#include "src/tint/lang/core/ir/type/array_count.h"
+#include "src/tint/lang/core/ir/unary.h"
#include "src/tint/lang/core/ir/unreachable.h"
#include "src/tint/lang/core/ir/unused.h"
#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/var.h"
+#include "src/tint/lang/core/type/array.h"
+#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/struct.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/ice/ice.h"
@@ -961,11 +964,37 @@
EmitLine();
}
-StyledText Disassembler::NameOf(const type::Type* ty) {
+StyledText Disassembler::NameOf(const core::type::Type* ty) {
if (!ty) {
return StyledText{} << StyleError("undef");
}
+ auto ary_emit = [&](StyledText& out, const core::type::Array* ary,
+ const core::ir::type::ValueArrayCount* cnt) -> void {
+ out << "array<" << ary->ElemType()->FriendlyName() << ", " << NameOf(cnt->value) << ">";
+ };
+
+ if (auto* ptr = ty->As<core::type::Pointer>()) {
+ if (auto* ary = ty->UnwrapPtr()->As<core::type::Array>()) {
+ if (auto* cnt = ary->Count()->As<core::ir::type::ValueArrayCount>()) {
+ auto out = StyledText{} << "ptr<";
+ if (ptr->AddressSpace() != core::AddressSpace::kUndefined) {
+ out << ptr->AddressSpace() << ", ";
+ }
+ ary_emit(out, ary, cnt);
+ out << ", " << ptr->Access() << ">";
+
+ return out;
+ }
+ }
+ } else if (auto* ary = ty->UnwrapPtr()->As<core::type::Array>()) {
+ if (auto* cnt = ary->Count()->As<core::ir::type::ValueArrayCount>()) {
+ auto out = StyledText{};
+ ary_emit(out, ary, cnt);
+ return out;
+ }
+ }
+
return StyledText{} << StyleType(ty->FriendlyName());
}
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 450fc75..b0ede84 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -99,6 +99,7 @@
"//src/tint/lang/core/constant",
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir/type",
"//src/tint/lang/core/type",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -165,6 +166,7 @@
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
"//src/tint/lang/core/ir/transform",
+ "//src/tint/lang/core/ir/type",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index 9fa86ab..2a72ef5 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -98,6 +98,7 @@
tint_lang_core_constant
tint_lang_core_intrinsic
tint_lang_core_ir
+ tint_lang_core_ir_type
tint_lang_core_type
tint_utils_containers
tint_utils_diagnostic
@@ -158,6 +159,7 @@
tint_lang_core_intrinsic
tint_lang_core_ir
tint_lang_core_ir_transform
+ tint_lang_core_ir_type
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 945ce31..412163b 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -104,6 +104,7 @@
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir/type",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -159,6 +160,7 @@
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/ir/transform",
+ "${tint_src_dir}/lang/core/ir/type",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/core/ir/transform/substitute_overrides.cc b/src/tint/lang/core/ir/transform/substitute_overrides.cc
index 943fdaa..c4b17c9 100644
--- a/src/tint/lang/core/ir/transform/substitute_overrides.cc
+++ b/src/tint/lang/core/ir/transform/substitute_overrides.cc
@@ -31,7 +31,9 @@
#include "src/tint/lang/core/ir/builder.h"
#include "src/tint/lang/core/ir/evaluator.h"
+#include "src/tint/lang/core/ir/type/array_count.h"
#include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/lang/core/ir/value.h"
#include "src/tint/utils/result/result.h"
using namespace tint::core::fluent_types; // NOLINT
@@ -55,12 +57,13 @@
core::type::Manager& ty{ir.Types()};
/// Map of override id to value
- Hashmap<OverrideId, Value*, 8> override_id_to_value_{};
+ Hashmap<OverrideId, Constant*, 8> override_id_to_value_{};
/// Process the module.
Result<SuccessType> Process() {
Vector<Instruction*, 8> to_remove;
- Vector<Value*, 8> values_to_propagate;
+ Vector<Constant*, 8> values_to_propagate;
+ Vector<core::ir::Var*, 4> vars_with_value_array_count;
// Note, we don't `Destroy` the overrides when we substitute them. We need them to stay
// alive because the `workgroup_size` and `array` usages aren't in the `Usages` list so
@@ -70,8 +73,14 @@
for (auto* inst : *ir.root_block) {
auto* override = inst->As<core::ir::Override>();
if (!override) {
- // Gather all the non-var instructions which we'll remove
- if (!inst->Is<core::ir::Var>()) {
+ if (auto* var = inst->As<core::ir::Var>()) {
+ if (auto* ary = var->Result(0)->Type()->UnwrapPtr()->As<core::type::Array>()) {
+ if (ary->Count()->Is<core::ir::type::ValueArrayCount>()) {
+ vars_with_value_array_count.Push(var);
+ }
+ }
+ } else {
+ // Gather all the non-var instructions which we'll remove
to_remove.Push(inst);
}
continue;
@@ -80,7 +89,7 @@
// Check if the user provided an override for the given ID.
auto iter = cfg.map.find(override->OverrideId());
if (iter != cfg.map.end()) {
- auto* replacement = CreateValue(override->Result(0)->Type(), iter->second);
+ auto* replacement = CreateConstant(override->Result(0)->Type(), iter->second);
ReplaceOverride(override, replacement);
values_to_propagate.Push(replacement);
to_remove.Push(override);
@@ -96,9 +105,8 @@
return Failure(error);
}
- core::ir::Value* replacement = nullptr;
- if (override->Initializer()->Is<core::ir::Constant>()) {
- replacement = override->Initializer();
+ core::ir::Constant* replacement = override->Initializer()->As<core::ir::Constant>();
+ if (replacement) {
// Remove the initializer such that we don't find the override as a usage when we
// try to propagate the replacement.
override->SetInitializer(nullptr);
@@ -131,28 +139,56 @@
new_wg[i] = val;
continue;
}
- auto* res = val->As<core::ir::InstructionResult>();
- TINT_ASSERT(res);
- core::ir::Value* new_value = nullptr;
- if (auto* override = res->Instruction()->As<core::ir::Override>()) {
- auto replacement = override_id_to_value_.Get(override->OverrideId());
- TINT_ASSERT(replacement);
- new_value = *replacement;
- } else {
- auto r = eval::Eval(b, val);
- if (r != Success) {
- return r.Failure();
- }
- new_value = r.Get();
+ auto new_value = CalculateOverride(val);
+ if (!new_value.Get()) {
+ return new_value.Failure();
}
-
- new_wg[i] = new_value;
+ new_wg[i] = new_value.Get();
}
func->SetWorkgroupSize(new_wg);
}
- // TODO(dsinclair): Replace array type
+ // Replace array types using overrides
+ for (auto var : vars_with_value_array_count) {
+ auto* old_ptr = var->Result(0)->Type()->As<core::type::Pointer>();
+ TINT_ASSERT(old_ptr);
+
+ auto* old_ty = old_ptr->UnwrapPtr()->As<core::type::Array>();
+ auto* cnt = old_ty->Count()->As<core::ir::type::ValueArrayCount>();
+ TINT_ASSERT(cnt);
+
+ auto new_value = CalculateOverride(cnt->value);
+ if (!new_value.Get()) {
+ return new_value.Failure();
+ }
+
+ uint32_t num_elements = new_value.Get()->Value()->ValueAs<uint32_t>();
+ auto* new_cnt = ty.Get<core::type::ConstantArrayCount>(num_elements);
+ auto* new_ty = ty.Get<core::type::Array>(old_ty->ElemType(), new_cnt, old_ty->Align(),
+ num_elements * old_ty->Stride(),
+ old_ty->Stride(), old_ty->ImplicitStride());
+
+ auto* new_ptr = ty.ptr(old_ptr->AddressSpace(), new_ty, old_ptr->Access());
+ var->Result(0)->SetType(new_ptr);
+
+ // The `Var` type needs to propagate to certain usages.
+ Vector<core::ir::Instruction*, 2> to_replace;
+ to_replace.Push(var);
+
+ while (!to_replace.IsEmpty()) {
+ auto* inst = to_replace.Pop();
+
+ for (auto usage : inst->Result(0)->UsagesUnsorted()) {
+ if (!usage->instruction->Is<core::ir::Let>()) {
+ continue;
+ }
+
+ usage->instruction->Result(0)->SetType(new_ptr);
+ to_replace.Push(usage->instruction);
+ }
+ }
+ }
// Remove any non-var instruction in the root block
for (auto* inst : to_remove) {
@@ -170,12 +206,31 @@
return Success;
}
- void ReplaceOverride(core::ir::Override* override, core::ir::Value* replacement) {
+ Result<core::ir::Constant*> CalculateOverride(core::ir::Value* val) {
+ auto* count_value = val->As<core::ir::InstructionResult>();
+ TINT_ASSERT(count_value);
+
+ if (auto* override = count_value->Instruction()->As<core::ir::Override>()) {
+ auto replacement = override_id_to_value_.Get(override->OverrideId());
+ TINT_ASSERT(replacement);
+ return *replacement;
+ }
+ auto r = eval::Eval(b, count_value);
+ if (r != Success) {
+ return r.Failure();
+ }
+ // Must be able to evaluate the constant.
+ TINT_ASSERT(r.Get());
+
+ return r;
+ }
+
+ void ReplaceOverride(core::ir::Override* override, core::ir::Constant* replacement) {
override_id_to_value_.Add(override->OverrideId(), replacement);
override->Result(0)->ReplaceAllUsesWith(replacement);
}
- Result<SuccessType> Propagate(Vector<core::ir::Value*, 8>& values_to_propagate) {
+ Result<SuccessType> Propagate(Vector<core::ir::Constant*, 8>& values_to_propagate) {
while (!values_to_propagate.IsEmpty()) {
auto* value = values_to_propagate.Pop();
for (auto usage : value->UsagesSorted()) {
@@ -224,7 +279,7 @@
[&](Default) { return false; });
}
- Value* CreateValue(const core::type::Type* type, double val) {
+ Constant* CreateConstant(const core::type::Type* type, double val) {
return tint::Switch(
type,
[&](const core::type::Bool*) { return b.Constant(!std::equal_to<double>()(val, 0.0)); },
diff --git a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
index db0c5ce..e93841a 100644
--- a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
+++ b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
@@ -32,6 +32,7 @@
#include "gtest/gtest.h"
#include "src/tint/lang/core/ir/transform/helper_test.h"
+#include "src/tint/lang/core/ir/type/array_count.h"
namespace tint::core::ir::transform {
namespace {
@@ -770,9 +771,156 @@
EXPECT_EQ(expect, str());
}
-// TODO(dsinclair): Support array type overrides
-TEST_F(IR_SubstituteOverridesTest, DISABLED_OverrideArraySize) {
- FAIL();
+TEST_F(IR_SubstituteOverridesTest, OverrideArraySize) {
+ b.Append(mod.root_block, [&] {
+ auto* x = b.Override("x", ty.u32());
+ x->SetOverrideId({2});
+
+ auto* cnt = ty.Get<core::ir::type::ValueArrayCount>(x->Result(0));
+ auto* ary = ty.Get<core::type::Array>(ty.i32(), cnt, 4_u, 4_u, 4_u, 4_u);
+ b.Var("v", ty.ptr(core::AddressSpace::kWorkgroup, ary, core::Access::kReadWrite));
+ });
+
+ auto* func = b.ComputeFunction("foo");
+ b.Append(func->Block(), [&] { b.Return(func); });
+
+ auto* src = R"(
+$B1: { # root
+ %x:u32 = override @id(2)
+ %v:ptr<workgroup, array<i32, %x>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ ret
+ }
+}
+)";
+
+ auto* expect = R"(
+$B1: { # root
+ %v:ptr<workgroup, array<i32, 5>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ ret
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ SubstituteOverridesConfig cfg{};
+ cfg.map[OverrideId{2}] = 5;
+ Run(SubstituteOverrides, cfg);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_SubstituteOverridesTest, OverrideArraySizeExpression) {
+ b.Append(mod.root_block, [&] {
+ auto* x = b.Override("x", ty.u32());
+ x->SetOverrideId({2});
+
+ auto* inst = b.Multiply(ty.u32(), x, 2_u);
+ auto* cnt = ty.Get<core::ir::type::ValueArrayCount>(inst->Result(0));
+ auto* ary = ty.Get<core::type::Array>(ty.i32(), cnt, 4_u, 4_u, 4_u, 4_u);
+ b.Var("v", ty.ptr(core::AddressSpace::kWorkgroup, ary, core::Access::kReadWrite));
+ });
+
+ auto* func = b.ComputeFunction("foo");
+ b.Append(func->Block(), [&] { b.Return(func); });
+
+ auto* src = R"(
+$B1: { # root
+ %x:u32 = override @id(2)
+ %2:u32 = mul %x, 2u
+ %v:ptr<workgroup, array<i32, %2>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ ret
+ }
+}
+)";
+
+ auto* expect = R"(
+$B1: { # root
+ %v:ptr<workgroup, array<i32, 10>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ ret
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ SubstituteOverridesConfig cfg{};
+ cfg.map[OverrideId{2}] = 5;
+ Run(SubstituteOverrides, cfg);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_SubstituteOverridesTest, OverrideArraySizeIntoLet) {
+ core::ir::Var* v = nullptr;
+ b.Append(mod.root_block, [&] {
+ auto* x = b.Override("x", ty.u32());
+ x->SetOverrideId({2});
+
+ auto* cnt = ty.Get<core::ir::type::ValueArrayCount>(x->Result(0));
+ auto* ary = ty.Get<core::type::Array>(ty.i32(), cnt, 4_u, 4_u, 4_u, 4_u);
+ v = b.Var("v", ty.ptr(core::AddressSpace::kWorkgroup, ary, core::Access::kReadWrite));
+ });
+
+ auto* func = b.ComputeFunction("foo");
+ b.Append(func->Block(), [&] {
+ auto* y = b.Let("y", v);
+ b.Let("z", y);
+ b.Return(func);
+ });
+
+ auto* src = R"(
+$B1: { # root
+ %x:u32 = override @id(2)
+ %v:ptr<workgroup, array<i32, %x>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ %y:ptr<workgroup, array<i32, %x>, read_write> = let %v
+ %z:ptr<workgroup, array<i32, %x>, read_write> = let %y
+ ret
+ }
+}
+)";
+
+ auto* expect = R"(
+$B1: { # root
+ %v:ptr<workgroup, array<i32, 5>, read_write> = var
+}
+
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B2: {
+ %y:ptr<workgroup, array<i32, 5>, read_write> = let %v
+ %z:ptr<workgroup, array<i32, 5>, read_write> = let %y
+ ret
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ SubstituteOverridesConfig cfg{};
+ cfg.map[OverrideId{2}] = 5;
+ Run(SubstituteOverrides, cfg);
+
+ EXPECT_EQ(expect, str());
}
} // namespace
diff --git a/src/tint/lang/core/ir/type/BUILD.bazel b/src/tint/lang/core/ir/type/BUILD.bazel
new file mode 100644
index 0000000..b107203
--- /dev/null
+++ b/src/tint/lang/core/ir/type/BUILD.bazel
@@ -0,0 +1,64 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "type",
+ srcs = [
+ "array_count.cc",
+ ],
+ hdrs = [
+ "array_count.h",
+ ],
+ deps = [
+ "//src/tint/lang/core/type",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "//src/utils",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/core/ir/type/BUILD.cmake b/src/tint/lang/core/ir/type/BUILD.cmake
new file mode 100644
index 0000000..4178a14
--- /dev/null
+++ b/src/tint/lang/core/ir/type/BUILD.cmake
@@ -0,0 +1,62 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_core_ir_type
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_core_ir_type lib
+ lang/core/ir/type/array_count.cc
+ lang/core/ir/type/array_count.h
+)
+
+tint_target_add_dependencies(tint_lang_core_ir_type lib
+ tint_lang_core_type
+ tint_utils_containers
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_core_ir_type lib
+ "src_utils"
+)
diff --git a/src/tint/lang/core/ir/type/BUILD.gn b/src/tint/lang/core/ir/type/BUILD.gn
new file mode 100644
index 0000000..f9aa2c7
--- /dev/null
+++ b/src/tint/lang/core/ir/type/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../../scripts/dawn_overrides_with_defaults.gni")
+import("../../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+libtint_source_set("type") {
+ sources = [
+ "array_count.cc",
+ "array_count.h",
+ ]
+ deps = [
+ "${dawn_root}/src/utils:utils",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+}
diff --git a/src/tint/lang/core/ir/type/array_count.cc b/src/tint/lang/core/ir/type/array_count.cc
new file mode 100644
index 0000000..d82925b
--- /dev/null
+++ b/src/tint/lang/core/ir/type/array_count.cc
@@ -0,0 +1,54 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/type/array_count.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::core::ir::type::ValueArrayCount);
+
+namespace tint::core::ir::type {
+
+ValueArrayCount::ValueArrayCount(Value* val)
+ : Base(static_cast<size_t>(tint::TypeCode::Of<ValueArrayCount>().bits)), value(val) {}
+
+ValueArrayCount::~ValueArrayCount() = default;
+
+bool ValueArrayCount::Equals(const UniqueNode& other) const {
+ if (auto* v = other.As<ValueArrayCount>()) {
+ return value == v->value;
+ }
+ return false;
+}
+
+std::string ValueArrayCount::FriendlyName() const {
+ return "<value>";
+}
+
+core::type::ArrayCount* ValueArrayCount::Clone(core::type::CloneContext&) const {
+ TINT_UNREACHABLE() << "Value array count clone not available";
+}
+
+} // namespace tint::core::ir::type
diff --git a/src/tint/lang/core/ir/type/array_count.h b/src/tint/lang/core/ir/type/array_count.h
new file mode 100644
index 0000000..4f2a650
--- /dev/null
+++ b/src/tint/lang/core/ir/type/array_count.h
@@ -0,0 +1,67 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_CORE_IR_TYPE_ARRAY_COUNT_H_
+#define SRC_TINT_LANG_CORE_IR_TYPE_ARRAY_COUNT_H_
+
+#include <string>
+
+#include "src/tint/lang/core/type/array_count.h"
+
+// Predeclarations
+namespace tint::core::ir {
+class Value;
+}
+
+namespace tint::core::ir::type {
+
+/// The variant of an ArrayCount when the count is an ir `Value`.
+class ValueArrayCount final : public Castable<ValueArrayCount, core::type::ArrayCount> {
+ public:
+ /// Constructor
+ /// @param val the value
+ explicit ValueArrayCount(Value* val);
+ ~ValueArrayCount() override;
+
+ /// @param other the other node
+ /// @returns true if this array count is equal @p other
+ bool Equals(const core::type::UniqueNode& other) const override;
+
+ /// @returns the friendly name for this array count
+ std::string FriendlyName() const override;
+
+ /// @param ctx the clone context
+ /// @returns a clone of this type
+ core::type::ArrayCount* Clone(core::type::CloneContext& ctx) const override;
+
+ /// The value
+ Value* value;
+};
+
+} // namespace tint::core::ir::type
+
+#endif // SRC_TINT_LANG_CORE_IR_TYPE_ARRAY_COUNT_H_
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
index 456ac24..17f5563 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
@@ -50,6 +50,7 @@
"//src/tint/lang/core/constant",
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir/type",
"//src/tint/lang/core/type",
"//src/tint/lang/wgsl",
"//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
index a8161ee..783dc58 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
@@ -51,6 +51,7 @@
tint_lang_core_constant
tint_lang_core_intrinsic
tint_lang_core_ir
+ tint_lang_core_ir_type
tint_lang_core_type
tint_lang_wgsl
tint_lang_wgsl_ast
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
index a6c64f9..6d5b319 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
@@ -55,6 +55,7 @@
"${tint_src_dir}/lang/core/constant",
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir/type",
"${tint_src_dir}/lang/core/type",
"${tint_src_dir}/lang/wgsl",
"${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/ir_program_test.h b/src/tint/lang/wgsl/reader/program_to_ir/ir_program_test.h
index 2ce447c..0761c34 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/ir_program_test.h
+++ b/src/tint/lang/wgsl/reader/program_to_ir/ir_program_test.h
@@ -66,8 +66,7 @@
return lower.Failure();
}
- auto validate = core::ir::Validate(
- result.Get(), core::ir::Capabilities{core::ir::Capability::kAllowOverrides});
+ auto validate = core::ir::Validate(result.Get(), kCapabilities);
if (validate != Success) {
return validate.Failure();
}
@@ -81,13 +80,16 @@
Source::File file("test.wgsl", std::move(wgsl));
auto result = wgsl::reader::WgslToIR(&file);
if (result == Success) {
- auto validated = core::ir::Validate(result.Get());
+ auto validated = core::ir::Validate(result.Get(), kCapabilities);
if (validated != Success) {
return validated.Failure();
}
}
return result;
}
+
+ core::ir::Capabilities kCapabilities =
+ core::ir::Capabilities{core::ir::Capability::kAllowOverrides};
};
using IRProgramTest = IRProgramTestBase<testing::Test>;
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 66ae2d4..83ed512 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -40,6 +40,7 @@
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/switch.h"
+#include "src/tint/lang/core/ir/type/array_count.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/reference.h"
@@ -87,6 +88,7 @@
#include "src/tint/lang/wgsl/ast/while_statement.h"
#include "src/tint/lang/wgsl/ir/builtin_call.h"
#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/lang/wgsl/sem/array_count.h"
#include "src/tint/lang/wgsl/sem/builtin_enum_expression.h"
#include "src/tint/lang/wgsl/sem/builtin_fn.h"
#include "src/tint/lang/wgsl/sem/call.h"
@@ -914,9 +916,8 @@
if (!val) {
return;
}
- auto* sem = impl.program_.Sem().Get(expr);
- auto* ty = sem->Type()->Clone(impl.clone_ctx_.type_ctx);
core::ir::Instruction* inst = nullptr;
+ auto* sem = impl.program_.Sem().Get(expr);
switch (expr->op) {
case core::UnaryOp::kAddressOf:
case core::UnaryOp::kIndirection:
@@ -924,15 +925,21 @@
// pointer.
Bind(expr, val);
return;
- case core::UnaryOp::kComplement:
+ case core::UnaryOp::kComplement: {
+ auto* ty = sem->Type()->Clone(impl.clone_ctx_.type_ctx);
inst = impl.builder_.Complement(ty, val);
break;
- case core::UnaryOp::kNegation:
+ }
+ case core::UnaryOp::kNegation: {
+ auto* ty = sem->Type()->Clone(impl.clone_ctx_.type_ctx);
inst = impl.builder_.Negation(ty, val);
break;
- case core::UnaryOp::kNot:
+ }
+ case core::UnaryOp::kNot: {
+ auto* ty = sem->Type()->Clone(impl.clone_ctx_.type_ctx);
inst = impl.builder_.Not(ty, val);
break;
+ }
}
impl.current_block_->Append(inst);
Bind(expr, inst->Result(0));
@@ -1173,9 +1180,38 @@
var,
[&](const ast::Var* v) {
auto* ref = sem->Type()->As<core::type::Reference>();
- auto* ty = builder_.ir.Types().Get<core::type::Pointer>(
- ref->AddressSpace(), ref->StoreType()->Clone(clone_ctx_.type_ctx),
- ref->Access());
+ const core::type::Type* store_ty = nullptr;
+
+ const auto* ary = ref->StoreType()->As<core::type::Array>();
+ // If the array has an override count
+ if (ary && !ary->Count()
+ ->IsAnyOf<core::type::RuntimeArrayCount,
+ core::type::ConstantArrayCount>()) {
+ core::ir::Value* count = tint::Switch(
+ ary->Count(), //
+ [&](const sem::UnnamedOverrideArrayCount* u) {
+ return EmitValueExpression(u->expr->Declaration());
+ },
+ [&](const sem::NamedOverrideArrayCount* n) {
+ return scopes_.Get(n->variable->Declaration()->name->symbol);
+ },
+ TINT_ICE_ON_NO_MATCH);
+
+ if (!count) {
+ return;
+ }
+
+ auto* ary_count =
+ builder_.ir.Types().Get<core::ir::type::ValueArrayCount>(count);
+ store_ty = builder_.ir.Types().Get<core::type::Array>(
+ ary->ElemType()->Clone(clone_ctx_.type_ctx), ary_count, ary->Align(),
+ ary->Size(), ary->Stride(), ary->ImplicitStride());
+ } else {
+ store_ty = ref->StoreType()->Clone(clone_ctx_.type_ctx);
+ }
+
+ auto* ty = builder_.ir.Types().Get<core::type::Pointer>(ref->AddressSpace(),
+ store_ty, ref->Access());
auto* val = builder_.Var(ty);
if (v->initializer) {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
index 60722d7..07af5e2 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
@@ -1264,5 +1264,32 @@
)");
}
+TEST_F(IR_FromProgramTest, OverrideWithLetAddressOf) {
+ auto* src = R"(
+override x = 1;
+var<workgroup> arr : array<u32, x>;
+
+fn a() {
+ let y = &arr;
+}
+)";
+ auto res = Build(src);
+ ASSERT_EQ(res, Success);
+
+ auto m = res.Move();
+ EXPECT_EQ(core::ir::Disassembler(m).Plain(), R"($B1: { # root
+ %x:i32 = override, 1i @id(0)
+ %arr:ptr<workgroup, array<u32, %x>, read_write> = var
+}
+
+%a = func():void {
+ $B2: {
+ %y:ptr<workgroup, array<u32, %x>, read_write> = let %arr
+ ret
+ }
+}
+)");
+}
+
} // namespace
} // namespace tint::wgsl::reader