diff options
author | Alon Zakai <azakai@google.com> | 2022-11-15 09:37:03 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-15 09:37:03 -0800 |
commit | df41c85856f2ffeea622e879840098f6200aa428 (patch) | |
tree | 3be41aba54db1f7ae02429d4774c3b7df5a05916 /src/passes/GlobalStructInference.cpp | |
parent | b2054b72b7daa89b7ad161c0693befad06a20c90 (diff) | |
download | binaryen-df41c85856f2ffeea622e879840098f6200aa428.tar.gz binaryen-df41c85856f2ffeea622e879840098f6200aa428.tar.bz2 binaryen-df41c85856f2ffeea622e879840098f6200aa428.zip |
GlobalStructInference: Handle cases with just 1 global too (#5253)
Expand GlobalStructInference to operate on cases with a single possible global, and
not just 2 or more. Even the case of a single global is useful, it turns out, as we can
alter the reference in places like this:
(struct.get $type 0
(..ref..)
)
No matter what ref is, if there is a single global it must refer to, we can switch to
this:
(struct.get $type 0
(global.get $global)
)
That can unlock further opts later. Note that we can do this even if we don't know
what the value actually is - we may not know what the struct.get returns, but we
do know what it reads from.
Diffstat (limited to 'src/passes/GlobalStructInference.cpp')
-rw-r--r-- | src/passes/GlobalStructInference.cpp | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/src/passes/GlobalStructInference.cpp b/src/passes/GlobalStructInference.cpp index 4d39768e2..39761c1d6 100644 --- a/src/passes/GlobalStructInference.cpp +++ b/src/passes/GlobalStructInference.cpp @@ -16,7 +16,8 @@ // // Finds types which are only created in assignments to immutable globals. For -// such types we can replace a struct.get with this pattern: +// such types we can replace a struct.get with a global.get when there is a +// single possible global, or if there are two then with this pattern: // // (struct.get $foo i // (..ref..)) @@ -44,6 +45,8 @@ // comparison. But we can compare structs, so if the function references are in // vtables, and the vtables follow the above pattern, then we can optimize. // +// TODO: Only do the case with a select when shrinkLevel == 0? +// #include "ir/find_all.h" #include "ir/module-utils.h" @@ -210,6 +213,25 @@ struct GlobalStructInference : public Pass { return; } + const auto& globals = iter->second; + if (globals.size() == 0) { + return; + } + + auto& wasm = *getModule(); + + if (globals.size() == 1) { + // Leave it to other passes to infer the constant value of the field, + // if there is one: just change the reference to the global, which + // will unlock those other optimizations. + auto global = globals[0]; + Builder builder(wasm); + curr->ref = builder.makeSequence( + builder.makeDrop(curr->ref), + builder.makeGlobalGet(global, wasm.getGlobal(globals[0])->type)); + return; + } + // We are looking for the case where we can pick between two values // using a single comparison. More than two values, or more than a // single comparison, add tradeoffs that may not be worth it, and a @@ -229,10 +251,6 @@ struct GlobalStructInference : public Pass { // (i32.const 1337) // (i32.const 42) // (ref.eq (ref) $global2)) - const auto& globals = iter->second; - if (globals.size() < 2) { - return; - } // Find the constant values and which globals correspond to them. // TODO: SmallVectors? @@ -240,7 +258,6 @@ struct GlobalStructInference : public Pass { std::vector<std::vector<Name>> globalsForValue; // Check if the relevant fields contain constants. - auto& wasm = *getModule(); auto fieldType = field.type; for (Index i = 0; i < globals.size(); i++) { Name global = globals[i]; @@ -279,6 +296,8 @@ struct GlobalStructInference : public Pass { // value. And we have already exited if we have more than 2, so that // only leaves 1 and 2. We are looking for the case of 2 here, since // other passes (ConstantFieldPropagation) can handle 1. + // TODO: We can perhaps do better than CFP, as we know the structs are + // created in globals. if (values.size() == 1) { return; } |