summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/possible-constant.h39
-rw-r--r--test/lit/passes/dae-gc.wast8
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)