Skip to content

Commit f7b2c8e

Browse files
authored
Handle arbitrary copies in CFP (#7900)
We previously special-cased copies from a field to itself in CFP. Generalize the analysis to handle copies from any field in any type to any field in any type. Along with this change, make the entire analysis more precise by explicit analyzing the written values, analyzing the readable values that result from the written values, then propagating readable values back to the writable values via copies and iterating until a fixed point. Use custom propagation logic after applying the copies the first time to minimize the amount of work done when propagating.
1 parent 3f3ed7f commit f7b2c8e

File tree

5 files changed

+9282
-268
lines changed

5 files changed

+9282
-268
lines changed

src/ir/possible-constant.h

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <variant>
2121

2222
#include "ir/properties.h"
23+
#include "support/utilities.h"
2324
#include "wasm-builder.h"
2425
#include "wasm.h"
2526

@@ -85,6 +86,45 @@ struct PossibleConstantValues {
8586
// identify a constant value here.
8687
void noteUnknown() { value = Many(); }
8788

89+
// Modify the possible constant to account for being written to or read from a
90+
// possibly-packed field. When used to model a read, `isSigned` controls
91+
// whether the value will be sign-extended or not.
92+
void packForField(const Field& field, bool isSigned = false) {
93+
if (field.type != Type::i32 || !field.isPacked()) {
94+
return;
95+
}
96+
if (!isConstant()) {
97+
// Nothing to pack.
98+
return;
99+
}
100+
if (isConstantGlobal()) {
101+
// Cannot track global and bit masking simultaneously, so give up.
102+
noteUnknown();
103+
return;
104+
}
105+
assert(isConstantLiteral());
106+
auto val = getConstantLiteral();
107+
assert(val.type == Type::i32);
108+
switch (field.packedType) {
109+
case Field::i8:
110+
if (isSigned) {
111+
value = val.extendS8();
112+
} else {
113+
value = val.and_(Literal(uint32_t(0xff)));
114+
}
115+
break;
116+
case Field::i16:
117+
if (isSigned) {
118+
value = val.extendS16();
119+
} else {
120+
value = val.and_(Literal(uint32_t(0xffff)));
121+
}
122+
break;
123+
case Field::not_packed:
124+
WASM_UNREACHABLE("unexpected packed type");
125+
}
126+
}
127+
88128
// Combine the information in a given PossibleConstantValues to this one. This
89129
// is the same as if we have called note*() on us with all the history of
90130
// calls to that other object.
@@ -109,28 +149,6 @@ struct PossibleConstantValues {
109149
return true;
110150
}
111151

112-
// Nulls compare equal, and we could consider any of the input nulls as the
113-
// combination of the two (as any of them would be valid to place in the
114-
// location we are working to optimize). In order to have simple symmetric
115-
// behavior here, which does not depend on the order of the inputs, use the
116-
// LUB.
117-
if (isNull() && other.isNull()) {
118-
auto type = getConstantLiteral().type.getHeapType();
119-
auto otherType = other.getConstantLiteral().type.getHeapType();
120-
auto lub = HeapType::getLeastUpperBound(type, otherType);
121-
if (!lub) {
122-
// TODO: Remove this workaround once we have bottom types to assign to
123-
// null literals.
124-
value = Many();
125-
return true;
126-
}
127-
if (*lub != type) {
128-
value = Literal::makeNull(*lub);
129-
return true;
130-
}
131-
return false;
132-
}
133-
134152
return false;
135153
}
136154

0 commit comments

Comments
 (0)