Skip to content

Commit 809e420

Browse files
jrpriceDawn LUCI CQ
authored andcommitted
[ir] Add ReferencedFunctions helper
A new helper that lazily determines (and caches) the set of functions that are transitively referenced by a function. This is similar to ReferencedModuleVars. This will be needed for the SingleEntryPoint transform, which needs to know which functions are used by a given entry point. Bug: 374972031 Change-Id: I0fd20bf2e87665dc18cb10725b6aab023eae5ed3 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/211795 Commit-Queue: dan sinclair <[email protected]> Reviewed-by: dan sinclair <[email protected]>
1 parent 8094ad1 commit 809e420

File tree

5 files changed

+483
-0
lines changed

5 files changed

+483
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ cc_library(
132132
"multi_in_block.h",
133133
"next_iteration.h",
134134
"operand_instruction.h",
135+
"referenced_functions.h",
135136
"referenced_module_vars.h",
136137
"return.h",
137138
"store.h",
@@ -208,6 +209,7 @@ cc_library(
208209
"multi_in_block_test.cc",
209210
"next_iteration_test.cc",
210211
"operand_instruction_test.cc",
212+
"referenced_functions_test.cc",
211213
"referenced_module_vars_test.cc",
212214
"return_test.cc",
213215
"store_test.cc",

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ tint_add_target(tint_lang_core_ir lib
119119
lang/core/ir/next_iteration.h
120120
lang/core/ir/operand_instruction.cc
121121
lang/core/ir/operand_instruction.h
122+
lang/core/ir/referenced_functions.h
122123
lang/core/ir/referenced_module_vars.h
123124
lang/core/ir/return.cc
124125
lang/core/ir/return.h
@@ -212,6 +213,7 @@ tint_add_target(tint_lang_core_ir_test test
212213
lang/core/ir/multi_in_block_test.cc
213214
lang/core/ir/next_iteration_test.cc
214215
lang/core/ir/operand_instruction_test.cc
216+
lang/core/ir/referenced_functions_test.cc
215217
lang/core/ir/referenced_module_vars_test.cc
216218
lang/core/ir/return_test.cc
217219
lang/core/ir/store_test.cc

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ libtint_source_set("ir") {
122122
"next_iteration.h",
123123
"operand_instruction.cc",
124124
"operand_instruction.h",
125+
"referenced_functions.h",
125126
"referenced_module_vars.h",
126127
"return.cc",
127128
"return.h",
@@ -209,6 +210,7 @@ if (tint_build_unittests) {
209210
"multi_in_block_test.cc",
210211
"next_iteration_test.cc",
211212
"operand_instruction_test.cc",
213+
"referenced_functions_test.cc",
212214
"referenced_module_vars_test.cc",
213215
"return_test.cc",
214216
"store_test.cc",
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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_FUNCTIONS_H_
29+
#define SRC_TINT_LANG_CORE_IR_REFERENCED_FUNCTIONS_H_
30+
31+
#include "src/tint/lang/core/ir/control_instruction.h"
32+
#include "src/tint/lang/core/ir/module.h"
33+
#include "src/tint/lang/core/ir/return.h"
34+
#include "src/tint/lang/core/ir/user_call.h"
35+
#include "src/tint/utils/containers/hashmap.h"
36+
#include "src/tint/utils/rtti/switch.h"
37+
38+
/// Utility that helps guarantee makes sure the same const-ness is applied to both type
39+
template <class Src, class Dst>
40+
using TranscribeConst = std::conditional_t<std::is_const<Src>{}, std::add_const_t<Dst>, Dst>;
41+
42+
namespace tint::core::ir {
43+
44+
/// ReferencedFunctions is a helper to determine the set of functions that are transitively
45+
/// referenced by functions in a module. References are determined lazily and cached for future
46+
/// requests.
47+
///
48+
/// Note:
49+
/// The template param M is used to ensure that inputs and outputs of this class have the same
50+
/// const-ness. If 'Module' is supplied then the internal operations and output will not be
51+
/// const, which is needed for transforms. Whereas if the param is 'const Module' the internals
52+
/// and outputs will be const, which is needed for the IR validator.
53+
/// Note:
54+
/// Changes to the module can invalidate the cached data. This is intended to be created by
55+
/// operations that need this information, and discarded when they complete. Tracking this
56+
/// information inside the IR module would add overhead any time an instruction is added or
57+
/// removed from the module. Since only a few operations need this information, it is expected
58+
/// to be more efficient to generate it on demand.
59+
template <typename M>
60+
class ReferencedFunctions {
61+
// Replace this with concepts when C++20 is available.
62+
static_assert(std::is_same<std::remove_cv_t<M>, Module>());
63+
64+
public:
65+
/// Short form aliases for types that have the same constant-ness as M.
66+
using BlockT = TranscribeConst<M, Block>;
67+
using FunctionT = TranscribeConst<M, Function>;
68+
69+
/// A set of a functions referenced by a function.
70+
using FunctionSet = Hashset<FunctionT*, 16>;
71+
72+
/// Constructor.
73+
/// @param ir the module
74+
explicit ReferencedFunctions(M& ir) {
75+
// Loop over functions, recording the blocks that they are called from.
76+
for (auto func : ir.functions) {
77+
if (!func) {
78+
continue;
79+
}
80+
func->ForEachUseUnsorted([&](const Usage& use) {
81+
if (auto* call = use.instruction->As<UserCall>()) {
82+
block_to_direct_calls_.GetOrAddZero(call->Block()).Add(func);
83+
} else {
84+
TINT_ASSERT(use.instruction->Is<Return>());
85+
}
86+
});
87+
}
88+
}
89+
90+
/// Get the set of transitively referenced functions for a function.
91+
/// @param func the function
92+
/// @returns the set of transitively reference functions
93+
FunctionSet& TransitiveReferences(FunctionT* func) {
94+
return transitive_references_.GetOrAdd(func, [&] {
95+
FunctionSet functions;
96+
if (!func) {
97+
return functions;
98+
}
99+
100+
// Walk blocks in the function to find function calls.
101+
Vector<BlockT*, 64> block_queue{func->Block()};
102+
while (!block_queue.IsEmpty()) {
103+
auto* next = block_queue.Pop();
104+
if (!next) {
105+
continue;
106+
}
107+
108+
// Add directly referenced functions.
109+
if (auto itr = block_to_direct_calls_.Get(next)) {
110+
for (auto& callee : *itr) {
111+
if (functions.Add(callee)) {
112+
// Add functions transitively referenced by the callee.
113+
const auto& callee_functions = TransitiveReferences(callee);
114+
for (auto& transitive_func : callee_functions) {
115+
functions.Add(transitive_func);
116+
}
117+
}
118+
}
119+
}
120+
121+
// Loop over instructions in the block to find nested blocks.
122+
for (auto* inst : *next) {
123+
if (auto* ctrl = inst->template As<ControlInstruction>()) {
124+
// Add nested blocks to the queue.
125+
ctrl->ForeachBlock([&](BlockT* blk) { block_queue.Push(blk); });
126+
}
127+
}
128+
}
129+
130+
return functions;
131+
});
132+
}
133+
134+
private:
135+
/// A map from blocks to their directly called functions.
136+
Hashmap<BlockT*, FunctionSet, 64> block_to_direct_calls_{};
137+
138+
/// A map from functions to their transitively referenced functions.
139+
Hashmap<FunctionT*, FunctionSet, 8> transitive_references_;
140+
};
141+
142+
} // namespace tint::core::ir
143+
144+
#endif // SRC_TINT_LANG_CORE_IR_REFERENCED_FUNCTIONS_H_

0 commit comments

Comments
 (0)