summaryrefslogtreecommitdiff
path: root/src/passes/Heap2Local.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-04-09 15:31:26 -0700
committerGitHub <noreply@github.com>2024-04-09 15:31:26 -0700
commit738e8fca4bea0c37e859e5bf0d37866ff432714e (patch)
tree4c6a3779d5f02794c49ddf15b559817589850247 /src/passes/Heap2Local.cpp
parentfca1d3aa467303938b6d21a94931528ffcb02a6b (diff)
downloadbinaryen-738e8fca4bea0c37e859e5bf0d37866ff432714e.tar.gz
binaryen-738e8fca4bea0c37e859e5bf0d37866ff432714e.tar.bz2
binaryen-738e8fca4bea0c37e859e5bf0d37866ff432714e.zip
Heap2Local: Optimize packed fields (#6480)
Previously we did not optimize a struct or an array with a packed field. As a result a single packed field in a struct prevented the entire struct from being localized, which this fixes. This is also useful for arrays as packed arrays are common (e.g. for string data).
Diffstat (limited to 'src/passes/Heap2Local.cpp')
-rw-r--r--src/passes/Heap2Local.cpp38
1 files changed, 26 insertions, 12 deletions
diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp
index a9465b1d7..3b0410a77 100644
--- a/src/passes/Heap2Local.cpp
+++ b/src/passes/Heap2Local.cpp
@@ -150,6 +150,7 @@
// This optimization focuses on such cases.
//
+#include "ir/bits.h"
#include "ir/branch-utils.h"
#include "ir/find_all.h"
#include "ir/local-graph.h"
@@ -648,6 +649,21 @@ struct Struct2Local : PostWalker<Struct2Local> {
curr->finalize();
}
+ // Add a mask for packed fields. We add masks on sets rather than on gets
+ // because gets tend to be more numerous both in code appearances and in
+ // runtime execution. As a result of masking on sets, the value in the local
+ // is always the masked value (which is also nice for debugging,
+ // incidentally).
+ Expression* addMask(Expression* value, const Field& field) {
+ if (!field.isPacked()) {
+ return value;
+ }
+
+ auto mask = Bits::lowBitMask(field.getByteSize() * 8);
+ return builder.makeBinary(
+ AndInt32, value, builder.makeConst(int32_t(mask)));
+ }
+
void visitStructNew(StructNew* curr) {
if (curr != allocation) {
return;
@@ -693,9 +709,10 @@ struct Struct2Local : PostWalker<Struct2Local> {
// Copy them to the normal ones.
for (Index i = 0; i < tempIndexes.size(); i++) {
- contents.push_back(builder.makeLocalSet(
- localIndexes[i],
- builder.makeLocalGet(tempIndexes[i], fields[i].type)));
+ auto* value = builder.makeLocalGet(tempIndexes[i], fields[i].type);
+ // Add a mask on the values we write.
+ contents.push_back(
+ builder.makeLocalSet(localIndexes[i], addMask(value, fields[i])));
}
// TODO Check if the nondefault case does not increase code size in some
@@ -704,8 +721,11 @@ struct Struct2Local : PostWalker<Struct2Local> {
// defaults.
} else {
// Set the default values.
+ //
// Note that we must assign the defaults because we might be in a loop,
// that is, there might be a previous value.
+ //
+ // Note there is no need to mask as these are zeros anyhow.
for (Index i = 0; i < localIndexes.size(); i++) {
contents.push_back(builder.makeLocalSet(
localIndexes[i],
@@ -766,7 +786,8 @@ struct Struct2Local : PostWalker<Struct2Local> {
// write the data to the local instead of the heap allocation.
replaceCurrent(builder.makeSequence(
builder.makeDrop(curr->ref),
- builder.makeLocalSet(localIndexes[curr->index], curr->value)));
+ builder.makeLocalSet(localIndexes[curr->index],
+ addMask(curr->value, fields[curr->index]))));
}
void visitStructGet(StructGet* curr) {
@@ -1111,14 +1132,7 @@ struct Heap2Local {
}
bool canHandleAsLocal(const Field& field) {
- if (!TypeUpdating::canHandleAsLocal(field.type)) {
- return false;
- }
- if (field.isPacked()) {
- // TODO: support packed fields by adding coercions/truncations.
- return false;
- }
- return true;
+ return TypeUpdating::canHandleAsLocal(field.type);
}
bool canHandleAsLocals(Type type) {