18
18
#include < memory>
19
19
#include < optional>
20
20
#include < string>
21
+ #include < string_view>
21
22
#include < vector>
22
23
23
24
#include " absl/container/flat_hash_map.h"
24
25
#include " absl/container/flat_hash_set.h"
25
- #include " absl/status/status.h"
26
26
#include " absl/status/statusor.h"
27
- #include " absl/strings/str_format.h"
28
27
#include " xls/common/logging/logging.h"
29
28
#include " xls/common/status/status_macros.h"
30
29
#include " xls/data_structures/union_find.h"
31
30
#include " xls/ir/block.h"
32
31
#include " xls/ir/channel.h"
32
+ #include " xls/ir/elaboration.h"
33
33
#include " xls/ir/function_base.h"
34
+ #include " xls/ir/instantiation.h"
34
35
#include " xls/ir/node_util.h"
35
36
#include " xls/ir/op.h"
36
37
#include " xls/ir/package.h"
@@ -79,63 +80,104 @@ void MarkReachedFunctions(FunctionBase* func,
79
80
}
80
81
}
81
82
}
82
- } // namespace
83
83
84
- // Starting from the return_value(s), DFS over all nodes. Unvisited
85
- // nodes, or parameters, are dead.
86
- absl::StatusOr<bool > DeadFunctionEliminationPass::RunInternal (
87
- Package* p, const OptimizationPassOptions& options,
88
- PassResults* results) const {
89
- std::optional<FunctionBase*> top = p->GetTop ();
90
- if (!top.has_value ()) {
91
- return false ;
84
+ // Data structure describing the liveness of global constructs in a package.
85
+ struct FunctionBaseLiveness {
86
+ // The live roots of the package. This does not include FunctionBases which
87
+ // are live because they are called/instantiated from other FunctionBases.
88
+ std::vector<FunctionBase*> live_roots;
89
+
90
+ // Set of the live global channels. Only set for old-style procs.
91
+ absl::flat_hash_set<Channel*> live_global_channels;
92
+ };
93
+
94
+ absl::StatusOr<FunctionBaseLiveness> LivenessFromTopProc (Proc* top) {
95
+ if (top->is_new_style_proc ()) {
96
+ XLS_ASSIGN_OR_RETURN (Elaboration elab, Elaboration::Elaborate (top));
97
+ return FunctionBaseLiveness{.live_roots = std::vector<FunctionBase*>(
98
+ elab.procs ().begin (), elab.procs ().end ()),
99
+ .live_global_channels = {}};
92
100
}
93
101
94
- // Mapping from proc->channel, where channel is a representative value
95
- // for all the channel names in the UnionFind.
96
- absl::flat_hash_map<Proc*, std::string> representative_channels;
102
+ Package* p = top->package ();
103
+
104
+ // Mapping from proc to channel, where channel is a representative value for
105
+ // all the channel names in the UnionFind. If the proc uses no channels then
106
+ // the value will be nullopt.
107
+ absl::flat_hash_map<Proc*, std::optional<std::string_view>>
108
+ representative_channels;
97
109
representative_channels.reserve (p->procs ().size ());
98
110
// Channels in the same proc will be union'd.
99
- UnionFind<std::string > channel_union;
100
- for (std::unique_ptr<Proc>& proc : p->procs ()) {
101
- std::optional<std::string > representative_proc_channel;
111
+ UnionFind<std::string_view > channel_union;
112
+ for (const std::unique_ptr<Proc>& proc : p->procs ()) {
113
+ std::optional<std::string_view > representative_proc_channel;
102
114
for (Node* node : proc->nodes ()) {
103
115
if (IsChannelNode (node)) {
104
- std::string channel;
105
- if (node->Is <Send>()) {
106
- channel = node->As <Send>()->channel_name ();
107
- } else if (node->Is <Receive>()) {
108
- channel = node->As <Receive>()->channel_name ();
109
- } else {
110
- return absl::NotFoundError (absl::StrFormat (
111
- " No channel associated with node %s" , node->GetName ()));
112
- }
113
- channel_union.Insert (channel);
116
+ XLS_ASSIGN_OR_RETURN (Channel * channel, GetChannelUsedByNode (node));
117
+ channel_union.Insert (channel->name ());
114
118
if (representative_proc_channel.has_value ()) {
115
- channel_union.Union (representative_proc_channel.value (), channel);
119
+ channel_union.Union (representative_proc_channel.value (),
120
+ channel->name ());
116
121
} else {
117
- representative_proc_channel = channel;
118
- representative_channels.insert ({proc.get (), channel});
122
+ representative_proc_channel = channel->name ();
119
123
}
120
124
}
121
125
}
126
+ representative_channels[proc.get ()] = representative_proc_channel;
122
127
}
123
128
124
- absl::flat_hash_set<FunctionBase*> reached;
125
- MarkReachedFunctions (top.value (), &reached);
126
- std::optional<std::string> top_proc_representative_channel;
127
- if ((*top)->IsProc ()) {
128
- auto itr = representative_channels.find (top.value ()->AsProcOrDie ());
129
- if (itr != representative_channels.end ()) {
130
- top_proc_representative_channel = channel_union.Find (itr->second );
131
- for (auto [proc, representative_channel] : representative_channels) {
132
- if (channel_union.Find (representative_channel) ==
133
- *top_proc_representative_channel) {
134
- MarkReachedFunctions (proc, &reached);
135
- }
129
+ FunctionBaseLiveness liveness;
130
+
131
+ // Add procs to the live set if they are connnected to `top` via channels.
132
+ for (const std::unique_ptr<Proc>& proc : p->procs ()) {
133
+ if (proc.get () == top) {
134
+ liveness.live_roots .push_back (proc.get ());
135
+ continue ;
136
+ }
137
+ if (representative_channels.at (top).has_value () &&
138
+ representative_channels.at (proc.get ()) &&
139
+ channel_union.Find (representative_channels.at (top).value ()) ==
140
+ channel_union.Find (
141
+ representative_channels.at (proc.get ()).value ())) {
142
+ liveness.live_roots .push_back (proc.get ());
143
+ }
144
+ }
145
+
146
+ // Add channels to the live set if they are connnected to `top`.
147
+ if (representative_channels.at (top).has_value ()) {
148
+ for (Channel* channel : p->channels ()) {
149
+ if (channel_union.Find (channel->name ()) ==
150
+ channel_union.Find (representative_channels.at (top).value ())) {
151
+ liveness.live_global_channels .insert (channel);
136
152
}
137
153
}
138
154
}
155
+ return liveness;
156
+ }
157
+
158
+ } // namespace
159
+
160
+ // Starting from the return_value(s), DFS over all nodes. Unvisited
161
+ // nodes, or parameters, are dead.
162
+ absl::StatusOr<bool > DeadFunctionEliminationPass::RunInternal (
163
+ Package* p, const OptimizationPassOptions& options,
164
+ PassResults* results) const {
165
+ std::optional<FunctionBase*> top = p->GetTop ();
166
+ if (!top.has_value ()) {
167
+ return false ;
168
+ }
169
+
170
+ FunctionBaseLiveness liveness;
171
+ if ((*top)->IsProc ()) {
172
+ XLS_ASSIGN_OR_RETURN (liveness, LivenessFromTopProc ((*top)->AsProcOrDie ()));
173
+ } else {
174
+ liveness.live_roots = {*top};
175
+ }
176
+
177
+ absl::flat_hash_set<FunctionBase*> reached;
178
+ for (FunctionBase* fb : liveness.live_roots ) {
179
+ MarkReachedFunctions (fb, &reached);
180
+ }
139
181
140
182
// Accumulate a list of FunctionBases to unlink.
141
183
bool changed = false ;
@@ -147,19 +189,15 @@ absl::StatusOr<bool> DeadFunctionEliminationPass::RunInternal(
147
189
}
148
190
}
149
191
150
- // Find any channels which are only used by now-removed procs .
151
- std::vector<std::string > channels_to_remove;
192
+ // Remove dead channels.
193
+ std::vector<Channel* > channels_to_remove;
152
194
channels_to_remove.reserve (p->channels ().size ());
153
195
for (Channel* channel : p->channels ()) {
154
- if (!top_proc_representative_channel.has_value () ||
155
- channel_union.Find (std::string{channel->name ()}) !=
156
- *top_proc_representative_channel) {
157
- channels_to_remove.push_back (std::string{channel->name ()});
196
+ if (!liveness.live_global_channels .contains (channel)) {
197
+ channels_to_remove.push_back (channel);
158
198
}
159
199
}
160
- // Now remove any channels which are only used by now-removed procs.
161
- for (const std::string& channel_name : channels_to_remove) {
162
- XLS_ASSIGN_OR_RETURN (Channel * channel, p->GetChannel (channel_name));
200
+ for (Channel* channel : channels_to_remove) {
163
201
XLS_VLOG (2 ) << " Removing channel: " << channel->name ();
164
202
XLS_RETURN_IF_ERROR (p->RemoveChannel (channel));
165
203
changed = true ;
0 commit comments