Skip to content

Commit 05f7d37

Browse files
Assign to shared_ptr directly
The Effects object is now shared within each SCC
1 parent 9bc667f commit 05f7d37

File tree

2 files changed

+29
-51
lines changed

2 files changed

+29
-51
lines changed

src/passes/GlobalEffects.cpp

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,7 @@ namespace wasm {
2929

3030
namespace {
3131

32-
constexpr auto UnknownEffects = std::nullopt;
33-
3432
struct FuncInfo {
35-
// Effects in this function. nullopt / UnknownEffects means that we don't know
36-
// what effects this function has, so we conservatively assume all effects.
37-
// Nullopt cases won't be copied to Function::effects.
38-
std::optional<EffectAnalyzer> effects;
39-
4033
// Directly-called functions from this function.
4134
std::unordered_set<Name> calledFunctions;
4235
};
@@ -46,37 +39,39 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
4639
ModuleUtils::ParallelFunctionAnalysis<FuncInfo> analysis(
4740
module, [&](Function* func, FuncInfo& funcInfo) {
4841
if (func->imported()) {
49-
// Imports can do anything, so we need to assume the worst anyhow,
50-
// which is the same as not specifying any effects for them in the
51-
// map (which we do by not setting funcInfo.effects).
42+
// Imports can do anything, so we need to assume the worst anyhow.
43+
func->effects = nullptr;
5244
return;
5345
}
5446

5547
// Gather the effects.
56-
funcInfo.effects.emplace(passOptions, module, func);
48+
func->effects =
49+
std::make_shared<EffectAnalyzer>(passOptions, module, func);
5750

58-
if (funcInfo.effects->calls) {
51+
if (func->effects->calls) {
5952
// There are calls in this function, which we will analyze in detail.
6053
// Clear the |calls| field first, and we'll handle calls of all sorts
6154
// below.
62-
funcInfo.effects->calls = false;
55+
func->effects->calls = false;
6356

6457
// Clear throws as well, as we are "forgetting" calls right now, and
6558
// want to forget their throwing effect as well. If we see something
6659
// else that throws, below, then we'll note that there.
67-
funcInfo.effects->throws_ = false;
60+
func->effects->throws_ = false;
6861

6962
struct CallScanner
7063
: public PostWalker<CallScanner,
7164
UnifiedExpressionVisitor<CallScanner>> {
7265
Module& wasm;
7366
const PassOptions& options;
7467
FuncInfo& funcInfo;
68+
Function* func;
7569

7670
CallScanner(Module& wasm,
7771
const PassOptions& options,
78-
FuncInfo& funcInfo)
79-
: wasm(wasm), options(options), funcInfo(funcInfo) {}
72+
FuncInfo& funcInfo,
73+
Function* func)
74+
: wasm(wasm), options(options), funcInfo(funcInfo), func(func) {}
8075

8176
void visitExpression(Expression* curr) {
8277
ShallowEffectAnalyzer effects(options, wasm, curr);
@@ -88,18 +83,18 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
8883
// worst. To do so, clear the effects, which indicates nothing
8984
// is known (so anything is possible).
9085
// TODO: We could group effects by function type etc.
91-
funcInfo.effects = UnknownEffects;
86+
func->effects = nullptr;
9287
} else {
9388
// No call here, but update throwing if we see it. (Only do so,
9489
// however, if we have effects; if we cleared it - see before -
9590
// then we assume the worst anyhow, and have nothing to update.)
96-
if (effects.throws_ && funcInfo.effects) {
97-
funcInfo.effects->throws_ = true;
91+
if (effects.throws_ && func->effects) {
92+
func->effects->throws_ = true;
9893
}
9994
}
10095
}
10196
};
102-
CallScanner scanner(module, passOptions, funcInfo);
97+
CallScanner scanner(module, passOptions, funcInfo, func);
10398
scanner.walkFunction(func);
10499
}
105100
});
@@ -171,15 +166,15 @@ void propagateEffects(
171166
CallGraphSCCs sccs(allFuncs, funcInfos, callGraph, module);
172167

173168
std::unordered_map<Function*, int> sccMembers;
174-
std::unordered_map<int, std::optional<EffectAnalyzer>> componentEffects;
169+
std::unordered_map<int, std::shared_ptr<EffectAnalyzer>> componentEffects;
175170

176171
int ccIndex = 0;
177172
for (auto ccIterator : sccs) {
178173
ccIndex++;
179-
std::optional<EffectAnalyzer>& ccEffects = componentEffects[ccIndex];
174+
std::shared_ptr<EffectAnalyzer>& ccEffects = componentEffects[ccIndex];
180175
std::vector<Function*> ccFuncs(ccIterator.begin(), ccIterator.end());
181176

182-
ccEffects.emplace(passOptions, module);
177+
ccEffects = std::make_shared<EffectAnalyzer>(passOptions, module);
183178

184179
for (Function* f : ccFuncs) {
185180
sccMembers.emplace(f, ccIndex);
@@ -199,25 +194,25 @@ void propagateEffects(
199194
// Merge in effects from callees
200195
for (int calleeScc : calleeSccs) {
201196
const auto& calleeComponentEffects = componentEffects.at(calleeScc);
202-
if (calleeComponentEffects == UnknownEffects) {
203-
ccEffects = UnknownEffects;
197+
if (calleeComponentEffects == nullptr) {
198+
ccEffects.reset();
204199
break;
205200
}
206201

207-
else if (ccEffects != UnknownEffects) {
202+
else if (ccEffects != nullptr) {
208203
ccEffects->mergeIn(*calleeComponentEffects);
209204
}
210205
}
211206

212207
// Add trap effects for potential cycles.
213208
if (ccFuncs.size() > 1) {
214-
if (ccEffects != UnknownEffects) {
209+
if (ccEffects != nullptr) {
215210
ccEffects->trap = true;
216211
}
217212
} else {
218213
auto* func = ccFuncs[0];
219214
if (funcInfos.at(func).calledFunctions.contains(func->name)) {
220-
if (ccEffects != UnknownEffects) {
215+
if (ccEffects != nullptr) {
221216
ccEffects->trap = true;
222217
}
223218
}
@@ -226,9 +221,9 @@ void propagateEffects(
226221
// Aggregate effects within this CC
227222
if (ccEffects) {
228223
for (Function* f : ccFuncs) {
229-
const auto& effects = funcInfos.at(f).effects;
230-
if (effects == UnknownEffects) {
231-
ccEffects = UnknownEffects;
224+
const auto& effects = f->effects;
225+
if (effects == nullptr) {
226+
ccEffects.reset();
232227
break;
233228
}
234229

@@ -238,23 +233,8 @@ void propagateEffects(
238233

239234
// Assign each function's effects to its CC effects.
240235
for (Function* f : ccFuncs) {
241-
if (!ccEffects) {
242-
funcInfos.at(f).effects = UnknownEffects;
243-
} else {
244-
funcInfos.at(f).effects.emplace(*ccEffects);
245-
}
246-
}
247-
}
248-
}
249-
250-
void copyEffectsToFunctions(const std::map<Function*, FuncInfo> funcInfos) {
251-
for (auto& [func, info] : funcInfos) {
252-
func->effects.reset();
253-
if (!info.effects) {
254-
continue;
236+
f->effects = ccEffects;
255237
}
256-
257-
func->effects = std::make_shared<EffectAnalyzer>(*info.effects);
258238
}
259239
}
260240

@@ -266,8 +246,6 @@ struct GenerateGlobalEffects : public Pass {
266246
auto callGraph = buildCallGraph(*module, funcInfos);
267247

268248
propagateEffects(*module, getPassOptions(), funcInfos, callGraph);
269-
270-
copyEffectsToFunctions(funcInfos);
271249
}
272250
};
273251

test/lit/passes/global-effects.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
;; WITHOUT-NEXT: (call $cycle-2)
9393
;; WITHOUT-NEXT: )
9494
;; INCLUDE: (func $cycle-1 (type $void)
95-
;; INCLUDE-NEXT: (call $cycle-2)
95+
;; INCLUDE-NEXT: (nop)
9696
;; INCLUDE-NEXT: )
9797
(func $cycle-1
9898
;; $cycle-1 and -2 form a cycle together, in which no call can be removed.
@@ -103,7 +103,7 @@
103103
;; WITHOUT-NEXT: (call $cycle-1)
104104
;; WITHOUT-NEXT: )
105105
;; INCLUDE: (func $cycle-2 (type $void)
106-
;; INCLUDE-NEXT: (call $cycle-1)
106+
;; INCLUDE-NEXT: (nop)
107107
;; INCLUDE-NEXT: )
108108
(func $cycle-2
109109
(call $cycle-1)

0 commit comments

Comments
 (0)