diff options
author | Alon Zakai <azakai@google.com> | 2021-08-18 14:08:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 14:08:51 -0700 |
commit | 3d6ddaf16232c42ab9a82f5114d562c2d8807870 (patch) | |
tree | d3f3e84498a6035278a2083e70e82dbfb2d9ff5f /src | |
parent | 8d95402260d268966eb0b06c5f4da7e1c5854418 (diff) | |
download | binaryen-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.h | 40 |
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; } |