summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/fuzz_opt.py2
-rw-r--r--src/passes/OptimizeInstructions.cpp21
-rw-r--r--test/lit/passes/optimize-instructions-call_ref.wast8
-rw-r--r--test/lit/passes/optimize-instructions-gc-iit.wast6
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast74
5 files changed, 78 insertions, 33 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index abc6225ee..d4e9ccc4d 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -176,6 +176,8 @@ IMPORTANT_INITIAL_CONTENTS = [
os.path.join('lit', 'passes', 'optimize-instructions-bulk-memory.wast'),
os.path.join('lit', 'passes', 'optimize-instructions-ignore-traps.wast'),
os.path.join('lit', 'passes', 'optimize-instructions-gc.wast'),
+ os.path.join('lit', 'passes', 'optimize-instructions-gc-iit.wast'),
+ os.path.join('lit', 'passes', 'optimize-instructions-call_ref.wast'),
os.path.join('lit', 'passes', 'inlining_splitting.wast'),
]
IMPORTANT_INITIAL_CONTENTS = [os.path.join(shared.get_test_dir('.'), t) for t in IMPORTANT_INITIAL_CONTENTS]
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index d18990e8e..387d76b37 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -207,8 +207,6 @@ struct OptimizeInstructions
bool fastMath;
- bool refinalize = false;
-
void doWalkFunction(Function* func) {
fastMath = getPassOptions().fastMath;
@@ -222,11 +220,6 @@ struct OptimizeInstructions
// Main walk.
super::doWalkFunction(func);
- // If we need to update parent types, do so.
- if (refinalize) {
- ReFinalize().walkFunctionInModule(func, getModule());
- }
-
// Final optimizations.
{
FinalOptimizer optimizer(getPassOptions());
@@ -1383,11 +1376,12 @@ struct OptimizeInstructions
// This cast cannot succeed. If the input is not a null, it will
// definitely trap.
if (fallthrough->type.isNonNullable()) {
- // Our type will now be unreachable; update the parents.
- refinalize = true;
+ // Make sure to emit a block with the same type as us; leave updating
+ // types for other passes.
replaceCurrent(builder.makeBlock({builder.makeDrop(curr->ref),
builder.makeDrop(curr->rtt),
- builder.makeUnreachable()}));
+ builder.makeUnreachable()},
+ curr->type));
return;
}
// Otherwise, we are not sure what it is, and need to wait for runtime
@@ -1575,8 +1569,11 @@ struct OptimizeInstructions
// drop, which is no worse, and the value and the drop can be optimized
// out later if the value has no side effects.
Builder builder(*getModule());
- replaceCurrent(builder.makeSequence(builder.makeDrop(curr->value),
- builder.makeUnreachable()));
+ // Make sure to emit a block with the same type as us; leave updating
+ // types for other passes.
+ replaceCurrent(builder.makeBlock(
+ {builder.makeDrop(curr->value), builder.makeUnreachable()},
+ curr->type));
return;
}
diff --git a/test/lit/passes/optimize-instructions-call_ref.wast b/test/lit/passes/optimize-instructions-call_ref.wast
index b3b781b1d..320237d1e 100644
--- a/test/lit/passes/optimize-instructions-call_ref.wast
+++ b/test/lit/passes/optimize-instructions-call_ref.wast
@@ -5,12 +5,12 @@
;; remove-unused-names is to allow fallthrough computations to work on blocks
(module
- ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
-
;; CHECK: (type $none_=>_i32 (func (result i32)))
(type $none_=>_i32 (func (result i32)))
+ ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+
;; CHECK: (type $none_=>_none (func))
(type $none_=>_none (func))
@@ -143,7 +143,7 @@
;; CHECK: (func $fallthrough-bad-type (result i32)
;; CHECK-NEXT: (call_ref
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref $none_=>_i32))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $return-nothing)
;; CHECK-NEXT: )
diff --git a/test/lit/passes/optimize-instructions-gc-iit.wast b/test/lit/passes/optimize-instructions-gc-iit.wast
index b99042643..d6bb9eb31 100644
--- a/test/lit/passes/optimize-instructions-gc-iit.wast
+++ b/test/lit/passes/optimize-instructions-gc-iit.wast
@@ -57,7 +57,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $child)
;; CHECK-NEXT: )
@@ -92,7 +92,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result (ref $other))
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $child)
;; NOMNL-NEXT: )
@@ -127,7 +127,7 @@
;; NOMNL-TNH-NEXT: )
;; NOMNL-TNH-NEXT: )
;; NOMNL-TNH-NEXT: (drop
- ;; NOMNL-TNH-NEXT: (block
+ ;; NOMNL-TNH-NEXT: (block (result (ref $other))
;; NOMNL-TNH-NEXT: (drop
;; NOMNL-TNH-NEXT: (local.get $child)
;; NOMNL-TNH-NEXT: )
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 3f12f58e9..993eb222c 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -569,7 +569,7 @@
;; data, etc.), so we know we will trap
;; CHECK: (func $unneeded_as_bad_kinds (param $func funcref) (param $data (ref null data)) (param $i31 (ref null i31))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref func))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $data)
;; CHECK-NEXT: )
@@ -577,7 +577,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result dataref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $i31)
;; CHECK-NEXT: )
@@ -585,7 +585,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result i31ref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $func)
;; CHECK-NEXT: )
@@ -593,7 +593,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref func))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $data)
;; CHECK-NEXT: )
@@ -601,7 +601,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result dataref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $i31)
;; CHECK-NEXT: )
@@ -609,7 +609,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result i31ref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $func)
;; CHECK-NEXT: )
@@ -619,7 +619,7 @@
;; CHECK-NEXT: )
;; NOMNL: (func $unneeded_as_bad_kinds (param $func funcref) (param $data (ref null data)) (param $i31 (ref null i31))
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result (ref func))
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $data)
;; NOMNL-NEXT: )
@@ -627,7 +627,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result dataref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $i31)
;; NOMNL-NEXT: )
@@ -635,7 +635,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result i31ref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $func)
;; NOMNL-NEXT: )
@@ -643,7 +643,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result (ref func))
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $data)
;; NOMNL-NEXT: )
@@ -651,7 +651,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result dataref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $i31)
;; NOMNL-NEXT: )
@@ -659,7 +659,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result i31ref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $func)
;; NOMNL-NEXT: )
@@ -1668,7 +1668,7 @@
;; CHECK: (func $incompatible-cast-of-non-null (param $struct (ref $struct))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref $array))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
@@ -1681,7 +1681,7 @@
;; CHECK-NEXT: )
;; NOMNL: (func $incompatible-cast-of-non-null (param $struct (ref $struct))
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block
+ ;; NOMNL-NEXT: (block (result (ref $array))
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.get $struct)
;; NOMNL-NEXT: )
@@ -1908,4 +1908,50 @@
)
)
)
+
+ ;; CHECK: (func $consecutive-opts-with-unreachable (param $func funcref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast
+ ;; CHECK-NEXT: (block (result dataref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (rtt.canon $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $consecutive-opts-with-unreachable (param $func funcref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast
+ ;; NOMNL-NEXT: (block (result dataref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $func)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (rtt.canon $struct)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $consecutive-opts-with-unreachable (param $func funcref)
+ (drop
+ (ref.cast
+ ;; Casting a funcref to data will definitely fail, so this will be
+ ;; replaced with an unreachable. But it should be enclosed in a block of
+ ;; the previous type, so that the outside ref.cast is not confused. This
+ ;; is a regression test for a bug where we replace this node with an
+ ;; unreachable one, but we left refinalize til the end of all the other
+ ;; opts - and that meant that we got to our parent, the ref.cast, with
+ ;; one unreachable child but before it itself was refinalized, so its
+ ;; type was *not* unreachable yet, which meant it saw inconsistent IR
+ ;; that then led to an assertion.
+ (ref.as_data
+ (local.get $func)
+ )
+ (rtt.canon $struct)
+ )
+ )
+ )
)