Skip to content

Commit 839eadc

Browse files
dj2Dawn LUCI CQ
authored andcommitted
[ir] Update SingleEntryPoint for Overrides.
This CL updates the `SingleEntryPoint` transform to allow overrides. It is also updated to filter out overrides which are not used in the requested entry point. Bug: 374971092 Change-Id: Ib66e569ec362d54f94394e4cfcd13f7a86bea1b0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/214295 Reviewed-by: James Price <[email protected]> Commit-Queue: dan sinclair <[email protected]>
1 parent 21109b4 commit 839eadc

File tree

11 files changed

+1255
-53
lines changed

11 files changed

+1255
-53
lines changed

src/tint/lang/core/ir/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ cc_library(
137137
"operand_instruction.h",
138138
"override.h",
139139
"referenced_functions.h",
140+
"referenced_module_decls.h",
140141
"referenced_module_vars.h",
141142
"return.h",
142143
"store.h",
@@ -217,6 +218,7 @@ cc_library(
217218
"operand_instruction_test.cc",
218219
"override_test.cc",
219220
"referenced_functions_test.cc",
221+
"referenced_module_decls_test.cc",
220222
"referenced_module_vars_test.cc",
221223
"return_test.cc",
222224
"store_test.cc",
@@ -237,6 +239,7 @@ cc_library(
237239
"//src/tint/lang/core/constant",
238240
"//src/tint/lang/core/intrinsic",
239241
"//src/tint/lang/core/ir",
242+
"//src/tint/lang/core/ir/type",
240243
"//src/tint/lang/core/type",
241244
"//src/tint/utils/containers",
242245
"//src/tint/utils/diagnostic",

src/tint/lang/core/ir/BUILD.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ tint_add_target(tint_lang_core_ir lib
125125
lang/core/ir/override.cc
126126
lang/core/ir/override.h
127127
lang/core/ir/referenced_functions.h
128+
lang/core/ir/referenced_module_decls.h
128129
lang/core/ir/referenced_module_vars.h
129130
lang/core/ir/return.cc
130131
lang/core/ir/return.h
@@ -222,6 +223,7 @@ tint_add_target(tint_lang_core_ir_test test
222223
lang/core/ir/operand_instruction_test.cc
223224
lang/core/ir/override_test.cc
224225
lang/core/ir/referenced_functions_test.cc
226+
lang/core/ir/referenced_module_decls_test.cc
225227
lang/core/ir/referenced_module_vars_test.cc
226228
lang/core/ir/return_test.cc
227229
lang/core/ir/store_test.cc
@@ -243,6 +245,7 @@ tint_target_add_dependencies(tint_lang_core_ir_test test
243245
tint_lang_core_constant
244246
tint_lang_core_intrinsic
245247
tint_lang_core_ir
248+
tint_lang_core_ir_type
246249
tint_lang_core_type
247250
tint_utils_containers
248251
tint_utils_diagnostic

src/tint/lang/core/ir/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ libtint_source_set("ir") {
127127
"override.cc",
128128
"override.h",
129129
"referenced_functions.h",
130+
"referenced_module_decls.h",
130131
"referenced_module_vars.h",
131132
"return.cc",
132133
"return.h",
@@ -218,6 +219,7 @@ if (tint_build_unittests) {
218219
"operand_instruction_test.cc",
219220
"override_test.cc",
220221
"referenced_functions_test.cc",
222+
"referenced_module_decls_test.cc",
221223
"referenced_module_vars_test.cc",
222224
"return_test.cc",
223225
"store_test.cc",
@@ -240,6 +242,7 @@ if (tint_build_unittests) {
240242
"${tint_src_dir}/lang/core/constant",
241243
"${tint_src_dir}/lang/core/intrinsic",
242244
"${tint_src_dir}/lang/core/ir",
245+
"${tint_src_dir}/lang/core/ir/type",
243246
"${tint_src_dir}/lang/core/type",
244247
"${tint_src_dir}/utils/containers",
245248
"${tint_src_dir}/utils/diagnostic",

src/tint/lang/core/ir/builder.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ class Builder {
14171417
/// Creates a new `let` declaration, with an unassigned value
14181418
/// @param type the let type
14191419
/// @returns the instruction
1420-
ir::Let* Let(const type::Type* type) {
1420+
ir::Let* Let(const core::type::Type* type) {
14211421
auto* let = ir.CreateInstruction<ir::Let>(InstructionResult(type), nullptr);
14221422
Append(let);
14231423
return let;
@@ -1791,15 +1791,15 @@ class Builder {
17911791
/// @param name the override name
17921792
/// @param type the override type
17931793
/// @returns the instruction
1794-
ir::Override* Override(std::string_view name, const type::Type* type) {
1794+
ir::Override* Override(std::string_view name, const core::type::Type* type) {
17951795
return Override(Source{}, name, type);
17961796
}
17971797

17981798
/// Creates a new `override` declaration, with an unassigned value
17991799
/// @param name the override name
18001800
/// @param type the override type
18011801
/// @returns the instruction
1802-
ir::Override* Override(Source src, std::string_view name, const type::Type* type) {
1802+
ir::Override* Override(Source src, std::string_view name, const core::type::Type* type) {
18031803
auto* override = ir.CreateInstruction<ir::Override>(InstructionResult(type));
18041804
ir.SetName(override->Result(0), name);
18051805
ir.SetSource(override, src);
@@ -1810,7 +1810,7 @@ class Builder {
18101810
/// Creates a new `override` declaration, with an unassigned value
18111811
/// @param type the override type
18121812
/// @returns the instruction
1813-
ir::Override* Override(const type::Type* type) {
1813+
ir::Override* Override(const core::type::Type* type) {
18141814
auto* override = ir.CreateInstruction<ir::Override>(InstructionResult(type));
18151815
Append(override);
18161816
return override;

src/tint/lang/core/ir/disassembler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Disassembler {
9595
const std::shared_ptr<Source::File>& File() const { return file_; }
9696

9797
/// @returns the disassembled name for the Type @p ty
98-
StyledText NameOf(const type::Type* ty);
98+
StyledText NameOf(const core::type::Type* ty);
9999

100100
/// @returns the disassembled name for the Block @p blk
101101
StyledText NameOf(const Block* blk);
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
// Copyright 2024 The Dawn & Tint Authors
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions are met:
5+
//
6+
// 1. Redistributions of source code must retain the above copyright notice, this
7+
// list of conditions and the following disclaimer.
8+
//
9+
// 2. Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
//
13+
// 3. Neither the name of the copyright holder nor the names of its
14+
// contributors may be used to endorse or promote products derived from
15+
// this software without specific prior written permission.
16+
//
17+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
#ifndef SRC_TINT_LANG_CORE_IR_REFERENCED_MODULE_DECLS_H_
29+
#define SRC_TINT_LANG_CORE_IR_REFERENCED_MODULE_DECLS_H_
30+
31+
#include "src/tint/lang/core/ir/control_instruction.h"
32+
#include "src/tint/lang/core/ir/instruction.h"
33+
#include "src/tint/lang/core/ir/let.h"
34+
#include "src/tint/lang/core/ir/module.h"
35+
#include "src/tint/lang/core/ir/override.h"
36+
#include "src/tint/lang/core/ir/type/array_count.h"
37+
#include "src/tint/lang/core/ir/user_call.h"
38+
#include "src/tint/lang/core/ir/var.h"
39+
#include "src/tint/lang/core/type/array.h"
40+
#include "src/tint/lang/core/type/pointer.h"
41+
#include "src/tint/utils/containers/hashmap.h"
42+
#include "src/tint/utils/containers/unique_vector.h"
43+
#include "src/tint/utils/rtti/switch.h"
44+
45+
// Forward declarations.
46+
namespace tint::core::ir {
47+
class Block;
48+
class Function;
49+
} // namespace tint::core::ir
50+
51+
/// Utility that helps guarantee the same const-ness is applied to both types.
52+
template <class Src, class Dst>
53+
using TranscribeConst = std::conditional_t<std::is_const<Src>{}, std::add_const_t<Dst>, Dst>;
54+
55+
namespace tint::core::ir {
56+
57+
/// ReferencedModuleDecls is a helper to determine the set of module-scope declarations that are
58+
/// transitively referenced by functions in a module.
59+
///
60+
/// References are determined lazily and cached for future requests.
61+
///
62+
/// Note:
63+
/// The template param M is used to ensure that inputs and outputs of this class have the same
64+
/// const-ness. If 'Module' is supplied then the internal operations and output will not be
65+
/// const, which is needed for transforms. Whereas if the param is 'const Module' the internals
66+
/// and outputs will be const, which is needed for the IR validator.
67+
/// Note:
68+
/// Changes to the module can invalidate the cached data. This is intended to be created by
69+
/// operations that need this information, and discarded when they complete. Tracking this
70+
/// information inside the IR module would add overhead any time an instruction is added or
71+
/// removed from the module. Since only a few operations need this information, it is expected
72+
/// to be more efficient to generate it on demand.
73+
template <typename M>
74+
class ReferencedModuleDecls {
75+
// Replace this with concepts when C++20 is available
76+
static_assert(std::is_same<std::remove_cv_t<M>, Module>());
77+
78+
public:
79+
/// Short form aliases for types that have the same constant-ness as M.
80+
/// (The single use types are not aliased)
81+
using BlockT = TranscribeConst<M, Block>;
82+
using DeclT = TranscribeConst<M, Instruction>;
83+
using FunctionT = TranscribeConst<M, Function>;
84+
85+
/// A set of a declarations referenced by a function (in declaration order).
86+
using DeclSet = UniqueVector<DeclT*, 16>;
87+
88+
/// Constructor.
89+
/// @param ir the module
90+
explicit ReferencedModuleDecls(M& ir) {
91+
// Loop over module-scope declarations, recording the blocks that they are referenced from.
92+
BlockT* root_block = ir.root_block;
93+
for (auto* inst : *root_block) {
94+
if (!inst || !inst->Result(0)) {
95+
continue;
96+
}
97+
98+
inst->Result(0)->ForEachUseUnsorted([&](const Usage& use) {
99+
auto& decls = block_to_direct_decls_.GetOrAddZero(use.instruction->Block());
100+
101+
// If this is an override we need to add the initializer to used instructions
102+
if (inst->template Is<core::ir::Override>()) {
103+
AddToBlock(decls, inst);
104+
} else {
105+
decls.Add(inst);
106+
}
107+
});
108+
109+
// If the instruction is a `var<workgroup>` we have to check the type. If the type is an
110+
// array with a `ValueArrayCount` then we need to check the count. If it's not
111+
// `Constant` we need to add the instruction and any referenced instructions to the used
112+
// set.
113+
auto* var = inst->template As<core::ir::Var>();
114+
if (!var) {
115+
continue;
116+
}
117+
auto* ptr = var->Result(0)->Type()->template As<core::type::Pointer>();
118+
TINT_ASSERT(ptr);
119+
120+
if (ptr->AddressSpace() != core::AddressSpace::kWorkgroup) {
121+
continue;
122+
}
123+
auto* ary = ptr->UnwrapPtr()->template As<core::type::Array>();
124+
if (!ary) {
125+
continue;
126+
}
127+
auto* cnt = ary->Count()->template As<core::ir::type::ValueArrayCount>();
128+
if (!cnt || cnt->value->template Is<core::ir::Constant>()) {
129+
continue;
130+
}
131+
132+
auto* cnt_inst = cnt->value->template As<core::ir::InstructionResult>();
133+
TINT_ASSERT(cnt_inst);
134+
135+
// The usage of the var is as a `let` initializer. The array count needs to
136+
// propagate to the `let` block.
137+
var->Result(0)->ForEachUseUnsorted([&](const Usage& use) {
138+
AddToBlock(block_to_direct_decls_.GetOrAddZero(use.instruction->Block()),
139+
cnt_inst->Instruction());
140+
});
141+
}
142+
}
143+
144+
/// Get the set of transitively referenced module-scope declarations for a function.
145+
/// @param func the function
146+
/// @returns the set of transitively reference module-scope declarations
147+
DeclSet& TransitiveReferences(FunctionT* func) {
148+
return transitive_references_.GetOrAdd(func, [&] {
149+
DeclSet decls;
150+
GetTransitiveReferences(func ? func->Block() : nullptr, decls);
151+
152+
// For a compute entry point, we need to check if any of the workgroup sizes are built
153+
// on overrides.
154+
if (func && func->Stage() == core::ir::Function::PipelineStage::kCompute) {
155+
TINT_ASSERT(func->WorkgroupSize().has_value());
156+
157+
const auto workgroup_size = func->WorkgroupSize();
158+
for (auto wg_size : *workgroup_size) {
159+
if (wg_size->template Is<core::ir::Constant>()) {
160+
continue;
161+
}
162+
163+
// Workgroup size is based on instructions, walk up the chain adding those
164+
// instructions to the `decls` list.
165+
auto* inst = wg_size->template As<core::ir::InstructionResult>();
166+
TINT_ASSERT(inst);
167+
168+
AddToBlock(decls, inst->Instruction());
169+
}
170+
}
171+
return decls;
172+
});
173+
}
174+
175+
void AddToBlock(DeclSet& decls, core::ir::Instruction* inst) {
176+
Vector<DeclT*, 4> worklist;
177+
worklist.Push(inst);
178+
179+
while (!worklist.IsEmpty()) {
180+
auto* wl_inst = worklist.Pop();
181+
if (decls.Add(wl_inst)) {
182+
for (auto* operand : wl_inst->Operands()) {
183+
if (!operand) {
184+
continue;
185+
}
186+
auto* res = operand->template As<core::ir::InstructionResult>();
187+
if (!res) {
188+
continue;
189+
}
190+
worklist.Push(res->Instruction());
191+
}
192+
}
193+
194+
for (auto* operand : wl_inst->Operands()) {
195+
if (!operand) {
196+
continue;
197+
}
198+
auto* res = operand->template As<core::ir::InstructionResult>();
199+
if (!res) {
200+
continue;
201+
}
202+
worklist.Push(res->Instruction());
203+
}
204+
}
205+
}
206+
207+
private:
208+
/// A map from blocks to their directly referenced declarations.
209+
Hashmap<BlockT*, DeclSet, 64> block_to_direct_decls_{};
210+
211+
/// A map from functions to their transitively referenced declarations.
212+
Hashmap<FunctionT*, DeclSet, 8> transitive_references_;
213+
214+
/// Get the set of transitively referenced module-scope declarations for a block.
215+
/// @param block the block
216+
/// @param decls the set of transitively reference module-scope declarations to populate
217+
void GetTransitiveReferences(BlockT* block, DeclSet& decls) {
218+
if (!block) {
219+
return;
220+
}
221+
222+
// Add directly referenced declarations.
223+
if (auto itr = block_to_direct_decls_.Get(block)) {
224+
for (auto& decl : *itr) {
225+
decls.Add(decl);
226+
}
227+
}
228+
229+
// Loop over instructions in the block to find indirectly referenced vars.
230+
for (auto* inst : *block) {
231+
tint::Switch(
232+
inst,
233+
[&](TranscribeConst<M, UserCall>* call) {
234+
// Get declarations referenced by a function called from this block.
235+
const auto& callee_decls = TransitiveReferences(call->Target());
236+
for (auto* decl : callee_decls) {
237+
decls.Add(decl);
238+
}
239+
},
240+
[&](TranscribeConst<M, ControlInstruction>* ctrl) {
241+
// Recurse into control instructions and gather their referenced declarations.
242+
ctrl->ForeachBlock([&](BlockT* blk) { GetTransitiveReferences(blk, decls); });
243+
});
244+
}
245+
}
246+
};
247+
248+
} // namespace tint::core::ir
249+
250+
#endif // SRC_TINT_LANG_CORE_IR_REFERENCED_MODULE_DECLS_H_

0 commit comments

Comments
 (0)