summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-08-18 14:08:51 -0700
committerGitHub <noreply@github.com>2021-08-18 14:08:51 -0700
commit3d6ddaf16232c42ab9a82f5114d562c2d8807870 (patch)
treed3f3e84498a6035278a2083e70e82dbfb2d9ff5f /src
parent8d95402260d268966eb0b06c5f4da7e1c5854418 (diff)
downloadbinaryen-3d6ddaf16232c42ab9a82f5114d562c2d8807870.tar.gz
binaryen-3d6ddaf16232c42ab9a82f5114d562c2d8807870.tar.bz2
binaryen-3d6ddaf16232c42ab9a82f5114d562c2d8807870.zip
[Wasm GC] Effects: Differentiate Struct and Array types (#4088)
This allows common patterns in J2CL to be optimized, where we write to various array indices and get the values or the reference from a struct. It would be nice to do even better here, and look at actually specific types, but I think we should be careful to keep the runtime constant. That seems hard to do if we accumulate a list of types and do Type::isSubType on them etc. But maybe someone has a better idea than this PR?
Diffstat (limited to 'src')
-rw-r--r--src/ir/effects.h40
1 files changed, 24 insertions, 16 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h
index fd4c68cba..e8fba8e3a 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -72,10 +72,12 @@ public:
std::set<Name> globalsWritten;
bool readsMemory = false;
bool writesMemory = false;
- // TODO: Type-based alias analysis. For example, writes to Arrays never
- // interfere with reads from Structs.
- bool readsHeap = false;
- bool writesHeap = false;
+ // TODO: More specific type-based alias analysis, and not just at the
+ // struct/array level.
+ bool readsStruct = false;
+ bool writesStruct = false;
+ bool readsArray = false;
+ bool writesArray = false;
// A trap, either from an unreachable instruction, or from an implicit trap
// that we do not ignore (see below).
//
@@ -124,7 +126,8 @@ public:
return globalsRead.size() + globalsWritten.size() > 0;
}
bool accessesMemory() const { return calls || readsMemory || writesMemory; }
- bool accessesHeap() const { return calls || readsHeap || writesHeap; }
+ bool accessesStruct() const { return calls || readsStruct || writesStruct; }
+ bool accessesArray() const { return calls || readsArray || writesArray; }
// Check whether this may transfer control flow to somewhere outside of this
// expression (aside from just flowing out normally). That includes a break
// or a throw (if the throw is not known to be caught inside this expression;
@@ -138,11 +141,12 @@ public:
// Changes something in globally-stored state.
bool writesGlobalState() const {
- return globalsWritten.size() || writesMemory || writesHeap || isAtomic ||
- calls;
+ return globalsWritten.size() || writesMemory || writesStruct ||
+ writesArray || isAtomic || calls;
}
bool readsGlobalState() const {
- return globalsRead.size() || readsMemory || readsHeap || isAtomic || calls;
+ return globalsRead.size() || readsMemory || readsStruct || readsArray ||
+ isAtomic || calls;
}
bool hasNonTrapSideEffects() const {
@@ -191,8 +195,10 @@ public:
(other.transfersControlFlow() && hasSideEffects()) ||
((writesMemory || calls) && other.accessesMemory()) ||
((other.writesMemory || other.calls) && accessesMemory()) ||
- ((writesHeap || calls) && other.accessesHeap()) ||
- ((other.writesHeap || other.calls) && accessesHeap()) ||
+ ((writesStruct || calls) && other.accessesStruct()) ||
+ ((other.writesStruct || other.calls) && accessesStruct()) ||
+ ((writesArray || calls) && other.accessesArray()) ||
+ ((other.writesArray || other.calls) && accessesArray()) ||
(danglingPop || other.danglingPop)) {
return true;
}
@@ -252,8 +258,10 @@ public:
calls = calls || other.calls;
readsMemory = readsMemory || other.readsMemory;
writesMemory = writesMemory || other.writesMemory;
- readsHeap = readsHeap || other.readsHeap;
- writesHeap = writesHeap || other.writesHeap;
+ readsStruct = readsStruct || other.readsStruct;
+ writesStruct = writesStruct || other.writesStruct;
+ readsArray = readsArray || other.readsArray;
+ writesArray = writesArray || other.writesArray;
trap = trap || other.trap;
implicitTrap = implicitTrap || other.implicitTrap;
trapsNeverHappen = trapsNeverHappen || other.trapsNeverHappen;
@@ -618,14 +626,14 @@ private:
void visitRttSub(RttSub* curr) {}
void visitStructNew(StructNew* curr) {}
void visitStructGet(StructGet* curr) {
- parent.readsHeap = true;
+ parent.readsStruct = true;
// traps when the arg is null
if (curr->ref->type.isNullable()) {
parent.implicitTrap = true;
}
}
void visitStructSet(StructSet* curr) {
- parent.writesHeap = true;
+ parent.writesStruct = true;
// traps when the arg is null
if (curr->ref->type.isNullable()) {
parent.implicitTrap = true;
@@ -633,12 +641,12 @@ private:
}
void visitArrayNew(ArrayNew* curr) {}
void visitArrayGet(ArrayGet* curr) {
- parent.readsHeap = true;
+ parent.readsArray = true;
// traps when the arg is null or the index out of bounds
parent.implicitTrap = true;
}
void visitArraySet(ArraySet* curr) {
- parent.writesHeap = true;
+ parent.writesArray = true;
// traps when the arg is null or the index out of bounds
parent.implicitTrap = true;
}