diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index ac645e77549..961f7eeefe0 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -331,17 +331,6 @@ struct Vacuum : public WalkerPass> { curr->condition = Builder(*getModule()).makeUnary(EqZInt32, curr->condition); BranchHints::flip(curr, getFunction()); - } else if (curr->ifTrue->is() && curr->ifFalse->is()) { - // instead of dropping both sides, drop the if, if they are the same - // type - auto* left = curr->ifTrue->cast()->value; - auto* right = curr->ifFalse->cast()->value; - if (left->type == right->type) { - curr->ifTrue = left; - curr->ifFalse = right; - curr->finalize(); - replaceCurrent(Builder(*getModule()).makeDrop(curr)); - } } } else { // This is an if without an else. If the body is empty, we do not need it. @@ -427,9 +416,11 @@ struct Vacuum : public WalkerPass> { } } } - // sink a drop into an arm of an if-else if the other arm ends in an - // unreachable, as it if is a branch, this can make that branch optimizable - // and more vacuuming possible + // Sink a drop into an arm of an if-else if the other arm ends in an + // unreachable, or sink drops into both arms if both arms are concrete. + // This allows the if expression to become void, eliminates block type + // overhead, and enables further vacuuming/dead-code elimination in each + // arm. auto* iff = curr->value->dynCast(); if (iff && iff->ifFalse && iff->type.isConcrete()) { // reuse the drop in both cases @@ -445,6 +436,13 @@ struct Vacuum : public WalkerPass> { iff->ifTrue = curr; iff->type = Type::none; replaceCurrent(iff); + } else if (iff->ifTrue->type.isConcrete() && + iff->ifFalse->type.isConcrete()) { + Builder builder(*getModule()); + iff->ifTrue = builder.dropIfConcretelyTyped(iff->ifTrue); + iff->ifFalse = builder.dropIfConcretelyTyped(iff->ifFalse); + iff->type = Type::none; + replaceCurrent(iff); } } } diff --git a/test/lit/passes/dae-optimizing.wast b/test/lit/passes/dae-optimizing.wast index 316c377586f..e7177a07138 100644 --- a/test/lit/passes/dae-optimizing.wast +++ b/test/lit/passes/dae-optimizing.wast @@ -8,7 +8,7 @@ (type $1 (func (param f64 f32 f32 f64 f32 i64 f64) (result i32))) ;; CHECK: (type $3 (func (result i32))) - ;; CHECK: (type $4 (func (result f32))) + ;; CHECK: (type $4 (func)) ;; CHECK: (type $2 (func (param f64 f32 f32 f64 f32 i32 i32 f64) (result i32))) (type $2 (func (param f64 f32 f32 f64 f32 i32 i32 f64) (result i32))) @@ -17,12 +17,12 @@ ;; CHECK: (func $0 (type $3) (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result f32) - ;; CHECK-NEXT: (local.tee $0 - ;; CHECK-NEXT: (i32.const 33554432) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (i32.const 33554432) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (loop $label$2 (result f32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (global.get $global$0) @@ -44,9 +44,9 @@ ;; CHECK-NEXT: (f32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (call $1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (call $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const -11) @@ -96,8 +96,8 @@ ) (i32.const -11) ) - ;; CHECK: (func $1 (type $4) (result f32) - ;; CHECK-NEXT: (f32.const 0) + ;; CHECK: (func $1 (type $4) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $1 (; 1 ;) (type $0) (param $0 f32) (result f32) (f32.const 0) diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast index bf931609666..5707cf6dfba 100644 --- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast +++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast @@ -418,188 +418,182 @@ ;; CHECK-NEXT: (local.get $6) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (i32.lt_s - ;; CHECK-NEXT: (call $_printf_core - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (i32.const 672) - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: (local.get $7) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (i32.ge_s + ;; CHECK-NEXT: (call $_printf_core ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 672) + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.const -1) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load offset=76 + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.load offset=76 + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (i32.le_s + ;; CHECK-NEXT: (i32.load8_s offset=74 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $3 - ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (i32.store ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (i32.const -33) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (i32.le_s - ;; CHECK-NEXT: (i32.load8_s offset=74 + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (local.tee $5 + ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 48) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $_printf_core ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: (i32.const -33) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 672) + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.tee $5 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 48) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (local.set $10 + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (local.tee $9 + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 44) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $_printf_core + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $9) + ;; CHECK-NEXT: (local.get $4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.tee $12 + ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 672) - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: (local.get $7) + ;; CHECK-NEXT: (i32.const 28) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $4) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (local.set $10 - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.tee $9 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 44) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.tee $11 + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $9) - ;; CHECK-NEXT: (local.get $4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.tee $12 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 28) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $5) + ;; CHECK-NEXT: (i32.const 80) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.tee $13 + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $4) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.tee $11 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 20) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (local.get $4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $5) ;; CHECK-NEXT: (i32.const 80) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.tee $13 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 16) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $4) - ;; CHECK-NEXT: (i32.const 80) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (call $_printf_core - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 672) - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: (local.get $7) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (call $_printf_core + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 672) + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (local.get $10) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call_indirect (type $FUNCSIG$iiii) - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (i32.load offset=36 - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 7) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $10) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call_indirect (type $FUNCSIG$iiii) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (i32.load offset=36 + ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 7) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.get $11) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $9) - ;; CHECK-NEXT: (local.get $10) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $5) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $13) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $12) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $11) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $9) + ;; CHECK-NEXT: (local.get $10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $5) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $13) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $12) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $11) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.or - ;; CHECK-NEXT: (i32.load - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: (i32.const 32) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.load + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (i32.const 32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/vacuum-intrinsics.wast b/test/lit/passes/vacuum-intrinsics.wast index 8f62ea36d46..6e12be47f98 100644 --- a/test/lit/passes/vacuum-intrinsics.wast +++ b/test/lit/passes/vacuum-intrinsics.wast @@ -145,21 +145,23 @@ ) ;; CHECK: (func $unused-fallthrough (type $0) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (block $condition (result i32) - ;; CHECK-NEXT: (call $nop) - ;; CHECK-NEXT: (call $call.without.effects - ;; CHECK-NEXT: (ref.func $i) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (block $condition (result i32) + ;; CHECK-NEXT: (call $nop) + ;; CHECK-NEXT: (call $call.without.effects + ;; CHECK-NEXT: (ref.func $i) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $ifTrue (result i32) ;; CHECK-NEXT: (call $nop) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $ifFalse (result i32) ;; CHECK-NEXT: (call $nop) ;; CHECK-NEXT: (i32.const 0) @@ -194,15 +196,17 @@ ) ;; CHECK: (func $unused-fallthrough-bad-type (type $0) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result (ref any)) - ;; CHECK-NEXT: (call $i) - ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (call $i) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $call.without.effects-ref ;; CHECK-NEXT: (ref.func $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $call.without.effects-ref ;; CHECK-NEXT: (ref.func $ref) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/vacuum_all-features.wast b/test/lit/passes/vacuum_all-features.wast index bdc313e7b1b..788ac197eb6 100644 --- a/test/lit/passes/vacuum_all-features.wast +++ b/test/lit/passes/vacuum_all-features.wast @@ -604,13 +604,15 @@ ) ) ;; CHECK: (func $if2drops (type $3) (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (call $if2drops) - ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (call $if2drops) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $if2drops) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $if2drops) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1218,43 +1220,49 @@ ;; CHECK-NEXT: (return) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (i32.eq - ;; CHECK-NEXT: (local.tee $0 - ;; CHECK-NEXT: (call $_deflate - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (call $_deflate + ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.store - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: (i32.load offset=20 - ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (i32.load offset=20 + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (call $_deflateEnd + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (call $_deflateEnd + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $global$1 ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.set $global$1 - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $_deflateEnd + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $_deflateEnd + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $global$1 ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.set $global$1 - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1417,3 +1425,107 @@ ) ) ) + +(module + ;; Sinking drop into arms of concrete if + ;; CHECK: (type $struct (struct (field (mut i32)))) + (type $struct (struct (field (mut i32)))) + + ;; CHECK: (type $1 (func (result i32))) + + ;; CHECK: (type $2 (func (param i32 i32 i32))) + + ;; CHECK: (type $3 (func (param i32))) + + ;; CHECK: (type $4 (func (param (ref null $struct) i32) (result (ref null $struct)))) + + ;; CHECK: (type $5 (func (param i32 (ref null $struct)))) + + ;; CHECK: (func $bar (type $1) (result i32) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + (func $bar (result i32) + (i32.const 1) + ) + + ;; CHECK: (func $pure-arms (type $2) (param $c i32) (param $x i32) (param $y i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $pure-arms (param $c i32) (param $x i32) (param $y i32) + (drop + (if (result i32) + (local.get $c) + (then (local.get $x)) + (else (local.get $y)) + ) + ) + ) + + ;; CHECK: (func $effectful-arms (type $3) (param $c i32) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $c) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $bar) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $bar) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $effectful-arms (param $c i32) + (drop + (if (result i32) + (local.get $c) + (then (call $bar)) + (else (call $bar)) + ) + ) + ) + + ;; CHECK: (func $put (type $4) (param $this (ref null $struct)) (param $v i32) (result (ref null $struct)) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $this) + ;; CHECK-NEXT: (local.get $v) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $this) + ;; CHECK-NEXT: ) + (func $put (param $this (ref null $struct)) (param $v i32) (result (ref null $struct)) + (struct.set $struct 0 (local.get $this) (local.get $v)) + (local.get $this) + ) + + ;; CHECK: (func $gc-effectful-arms (type $5) (param $c i32) (param $b (ref null $struct)) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $c) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $put + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $put + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $gc-effectful-arms (param $c i32) (param $b (ref null $struct)) + (drop + (if (result (ref null $struct)) + (local.get $c) + (then (call $put (local.get $b) (i32.const 1))) + (else (call $put (local.get $b) (i32.const 2))) + ) + ) + ) +)