diff options
-rw-r--r-- | src/ir/possible-constant.h | 39 | ||||
-rw-r--r-- | test/lit/passes/dae-gc.wast | 8 |
2 files changed, 27 insertions, 20 deletions
diff --git a/src/ir/possible-constant.h b/src/ir/possible-constant.h index c75669dab..f8b690a93 100644 --- a/src/ir/possible-constant.h +++ b/src/ir/possible-constant.h @@ -72,22 +72,9 @@ public: // Note either a Literal or a Name. template<typename T> void note(T curr) { - if (std::get_if<None>(&value)) { - // This is the first value. - value = curr; - return; - } - - if (std::get_if<Many>(&value)) { - // This was already representing multiple values; nothing changes. - return; - } - - // This is a subsequent value. Check if it is different from all previous - // ones. - if (Variant(curr) != value) { - noteUnknown(); - } + PossibleConstantValues other; + other.value = curr; + combine(other); } // Notes a value that is unknown - it can be anything. We have failed to @@ -118,6 +105,22 @@ public: return true; } + // Nulls compare equal, and we could consider any of the input nulls as the + // combination of the two (as any of them would be valid to place in the + // location we are working to optimize). In order to have simple symmetric + // behavior here, which does not depend on the order of the inputs, use the + // LUB. + if (isNull() && other.isNull()) { + auto type = getConstantLiteral().type.getHeapType(); + auto otherType = other.getConstantLiteral().type.getHeapType(); + auto lub = HeapType::getLeastUpperBound(type, otherType); + if (lub != type) { + value = Literal::makeNull(lub); + return true; + } + return false; + } + return false; } @@ -130,6 +133,10 @@ public: bool isConstantGlobal() const { return std::get_if<Name>(&value); } + bool isNull() const { + return isConstantLiteral() && getConstantLiteral().isNull(); + } + // Returns the single constant value. Literal getConstantLiteral() const { assert(isConstant()); diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index 1d12150eb..a8e078468 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -169,7 +169,7 @@ ;; CHECK: (func $bar (param $0 (ref null $none_=>_none)) ;; CHECK-NEXT: (local $1 anyref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null any) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop @@ -183,7 +183,7 @@ ;; NOMNL: (func $bar (type $ref?|none_->_none|_=>_none) (param $0 (ref null $none_=>_none)) ;; NOMNL-NEXT: (local $1 anyref) ;; NOMNL-NEXT: (local.set $1 - ;; NOMNL-NEXT: (ref.null func) + ;; NOMNL-NEXT: (ref.null any) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop @@ -218,8 +218,8 @@ ;; NOMNL-NEXT: ) (func $call-bar ;; Call with nulls. Mixing nulls is fine as they all have the same value, and - ;; we can optimize. However, mixing a null with a reference stops us in the - ;; second param. + ;; we can optimize (to the LUB of the nulls). However, mixing a null with a + ;; reference stops us in the second param. (call $bar (ref.null func) (ref.null func) |