diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 11 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc.wast | 44 |
2 files changed, 52 insertions, 3 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index acb2c8d66..af7369994 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2924,6 +2924,11 @@ private: } } }; + // Noting the type here not only simplifies the code below, but is also + // necessary to avoid an error: if we look at walked->type then it may + // actually differ from the original type, say if the walk ended up turning + // |binary| into a simpler unreachable expression. + auto type = binary->type; Expression* walked = binary; ZeroRemover remover(getPassOptions()); remover.setModule(getModule()); @@ -2936,14 +2941,14 @@ private: // Accumulated 64-bit constant value in 32-bit context will be wrapped // during downcasting. So it's valid unification for 32-bit and 64-bit // values. - c->value = Literal::makeFromInt64(constant, c->type); + c->value = Literal::makeFromInt64(constant, type); return c; } Builder builder(*getModule()); return builder.makeBinary( - Abstract::getBinary(walked->type, Abstract::Add), + Abstract::getBinary(type, Abstract::Add), walked, - builder.makeConst(Literal::makeFromInt64(constant, walked->type))); + builder.makeConst(Literal::makeFromInt64(constant, type))); } // Given an i64.wrap operation, see if we can remove it. If all the things diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index e973ca086..4535a53b3 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -38,6 +38,9 @@ (type $void2 (func_subtype $void)) + ;; CHECK: (type $struct_i64 (func (param structref) (result i64))) + (type $struct_i64 (func (param (ref null struct)) (result i64))) + ;; CHECK: (import "env" "get-i32" (func $get-i32 (result i32))) (import "env" "get-i32" (func $get-i32 (result i32))) @@ -2455,4 +2458,45 @@ ) ) ) + + ;; CHECK: (func $gc_to_unreachable_in_added_constants (type $void) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.add + ;; CHECK-NEXT: (call $struct_i64_helper + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $gc_to_unreachable_in_added_constants + (drop + (i32.wrap_i64 + (i64.add + (i64.const 1) + (i64.add + (i64.const 1) + (call_ref $struct_i64 + ;; This will turn into an unreachable. That should not cause an + ;; error in later i64 add optimizations (optimizeAddedConstants), + ;; which should not assume this is an i64-typed expression. + (ref.as_non_null + (ref.null none) + ) + (ref.func $struct_i64_helper) + ) + ) + ) + ) + ) + ) + + ;; CHECK: (func $struct_i64_helper (type $struct_i64) (param $0 structref) (result i64) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $struct_i64_helper (type $struct_i64) (param $0 (ref null struct)) (result i64) + (unreachable) + ) ) |