Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/passes/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ struct IntrinsicLowering : public WalkerPass<PostWalker<IntrinsicLowering>> {
// forgets to optimize.
Builder builder(*getModule());
if (auto* refFunc = target->dynCast<RefFunc>()) {
replaceCurrent(builder.makeCall(refFunc->func, operands, curr->type));
replaceCurrent(builder.makeCall(
refFunc->func, operands, curr->type, curr->isReturn));
} else {
replaceCurrent(builder.makeCallRef(target, operands, curr->type));
replaceCurrent(
builder.makeCallRef(target, operands, curr->type, curr->isReturn));
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/passes/TailCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@ struct TailCall : public WalkerPass<PreWalker<TailCall>> {
template<typename CallType> void handleCall(CallType* call, bool isTail) {
// A call in tail position can have a type incompatible with the function's
// return type if it is dead code at the end of a block following an earlier
// unreachable instruction.
if (call->isReturn || !isTail ||
// unreachable instruction. Also avoid optimizing unreachable calls (e.g.
// calls with unreachable operands), since their callee return type may not
// match the caller return type.
if (call->isReturn || !isTail || call->type == Type::unreachable ||
!Type::isSubType(call->type, getFunction()->getResults())) {
return;
}
Expand Down
26 changes: 21 additions & 5 deletions test/lit/passes/intrinsic-lowering.wast
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
(type $none (func))

;; call.without.effects with no params.
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-v (type $1) (param funcref) (result i32)))
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-v (type $3) (param funcref) (result i32)))
(import "binaryen-intrinsics" "call.without.effects" (func $cwe-v (param funcref) (result i32)))

;; call.without.effects with some params.
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-dif (type $2) (param f64 i32 funcref) (result f32)))
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-dif (type $4) (param f64 i32 funcref) (result f32)))
(import "binaryen-intrinsics" "call.without.effects" (func $cwe-dif (param f64) (param i32) (param funcref) (result f32)))

;; call.without.effects with no result.
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-n (type $3) (param funcref)))
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-n (type $5) (param funcref)))
(import "binaryen-intrinsics" "call.without.effects" (func $cwe-n (param funcref)))

;; CHECK: (func $test (type $4) (param $none (ref null $none))
;; CHECK: (func $test (type $1) (param $none (ref null $none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $make-i32)
;; CHECK-NEXT: )
Expand All @@ -39,7 +39,7 @@
(call $cwe-n (local.get $none))
)

;; CHECK: (func $make-i32 (type $5) (result i32)
;; CHECK: (func $make-i32 (type $2) (result i32)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
(func $make-i32 (result i32)
Expand All @@ -53,4 +53,20 @@
;; Helper function for the above.
(unreachable)
)

;; CHECK: (func $test-return-call (type $2) (result i32)
;; CHECK-NEXT: (return_call $make-i32)
;; CHECK-NEXT: )
(func $test-return-call (result i32)
(return_call $cwe-v (ref.func $make-i32))
)

;; CHECK: (func $test-return-call-ref (type $1) (param $none (ref null $none))
;; CHECK-NEXT: (return_call_ref $none
;; CHECK-NEXT: (local.get $none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-return-call-ref (param $none (ref null $none))
(return_call $cwe-n (local.get $none))
)
)
129 changes: 111 additions & 18 deletions test/lit/passes/tail-call.wast
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
(module
;; CHECK: (type $none-to-i32 (func (result i32)))

;; CHECK: (type $i32-to-none (func (param i32)))

;; CHECK: (type $none-to-none (func))
(type $none-to-none (func))
(type $none-to-i32 (func (result i32)))
(type $i32-to-none (func (param i32)))
;; CHECK: (type $struct (sub (struct)))
(type $struct (sub (struct)))
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe (type $6) (param i32 funcref) (result i32)))
(import "binaryen-intrinsics" "call.without.effects" (func $cwe (param i32) (param funcref) (result i32)))
;; CHECK: (global $g (mut i32) (i32.const 0))
(global $g (mut i32) (i32.const 0))
;; CHECK: (table $table 1 funcref)
Expand All @@ -19,6 +24,15 @@
;; CHECK: (func $void-callee (type $none-to-none)
;; CHECK-NEXT: )
(func $void-callee)
;; CHECK: (func $void-arg-callee (type $i32-to-none) (param $x i32)
;; CHECK-NEXT: )
(func $void-arg-callee (param $x i32))
;; CHECK: (func $i32-to-i32-callee (type $2) (param $x i32) (result i32)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
(func $i32-to-i32-callee (param $x i32) (result i32)
(local.get $x)
)
;; CHECK: (func $value-callee (type $none-to-i32) (result i32)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
Expand All @@ -31,7 +45,7 @@
(func $ref-callee (result i32)
(i32.const 2)
)
;; CHECK: (func $param-callee (type $6) (param $x i32) (param $y i32) (result i32)
;; CHECK: (func $param-callee (type $7) (param $x i32) (param $y i32) (result i32)
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (local.get $y)
Expand All @@ -43,7 +57,7 @@
(local.get $y)
)
)
;; CHECK: (func $subtype-callee (type $7) (result (ref $struct))
;; CHECK: (func $subtype-callee (type $8) (result (ref $struct))
;; CHECK-NEXT: (struct.new_default $struct)
;; CHECK-NEXT: )
(func $subtype-callee (result (ref $struct))
Expand Down Expand Up @@ -93,7 +107,7 @@
)
)

;; CHECK: (func $call-with-params (type $1) (param $x i32) (result i32)
;; CHECK: (func $call-with-params (type $2) (param $x i32) (result i32)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (return_call $param-callee
;; CHECK-NEXT: (local.get $x)
Expand Down Expand Up @@ -123,7 +137,7 @@
)
)

;; CHECK: (func $subtype-return (type $8) (result anyref)
;; CHECK: (func $subtype-return (type $9) (result anyref)
;; CHECK-NEXT: (return_call $subtype-callee)
;; CHECK-NEXT: )
(func $subtype-return (result anyref)
Expand All @@ -140,7 +154,7 @@
(call $multivalue-callee)
)

;; CHECK: (func $conditional (type $1) (param $condition i32) (result i32)
;; CHECK: (func $conditional (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $condition)
;; CHECK-NEXT: (then
Expand All @@ -164,7 +178,7 @@
)
)

;; CHECK: (func $one-armed-if (type $3) (param $condition i32)
;; CHECK: (func $one-armed-if (type $i32-to-none) (param $condition i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $condition)
;; CHECK-NEXT: (then
Expand Down Expand Up @@ -207,7 +221,7 @@
)
)

;; CHECK: (func $break (type $1) (param $condition i32) (result i32)
;; CHECK: (func $break (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $condition)
Expand All @@ -234,7 +248,7 @@
)
)

;; CHECK: (func $return-break (type $1) (param $condition i32) (result i32)
;; CHECK: (func $return-break (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (if
Expand Down Expand Up @@ -265,7 +279,7 @@
)
)

;; CHECK: (func $br-if-tail (type $1) (param $condition i32) (result i32)
;; CHECK: (func $br-if-tail (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (block
;; CHECK-NEXT: (return_call $value-callee)
Expand All @@ -287,7 +301,7 @@
)
)

;; CHECK: (func $br-if-not-tail (type $1) (param $condition i32) (result i32)
;; CHECK: (func $br-if-not-tail (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (block $out (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_if $out
Expand Down Expand Up @@ -340,7 +354,7 @@
)
)

;; CHECK: (func $br-table-all-tail (type $1) (param $idx i32) (result i32)
;; CHECK: (func $br-table-all-tail (type $2) (param $idx i32) (result i32)
;; CHECK-NEXT: (block $out1
;; CHECK-NEXT: (block $out2
;; CHECK-NEXT: (block
Expand All @@ -364,7 +378,7 @@
)
)

;; CHECK: (func $br-table-not-all-tail (type $1) (param $idx i32) (result i32)
;; CHECK: (func $br-table-not-all-tail (type $2) (param $idx i32) (result i32)
;; CHECK-NEXT: (block $exit (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $not-exit (result i32)
Expand Down Expand Up @@ -392,7 +406,7 @@
)
)

;; CHECK: (func $void-break (type $3) (param $condition i32)
;; CHECK: (func $void-break (type $i32-to-none) (param $condition i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $condition)
Expand All @@ -419,7 +433,7 @@
)
)

;; CHECK: (func $void-br-if-tail (type $3) (param $condition i32)
;; CHECK: (func $void-br-if-tail (type $i32-to-none) (param $condition i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (return_call $void-callee)
;; CHECK-NEXT: (br_if $out
Expand All @@ -438,7 +452,7 @@
)
)

;; CHECK: (func $void-br-if-not-tail (type $3) (param $condition i32)
;; CHECK: (func $void-br-if-not-tail (type $i32-to-none) (param $condition i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (call $void-callee)
;; CHECK-NEXT: (br_if $out
Expand All @@ -459,7 +473,7 @@
)
)

;; CHECK: (func $void-br-table-all-tail (type $3) (param $idx i32)
;; CHECK: (func $void-br-table-all-tail (type $i32-to-none) (param $idx i32)
;; CHECK-NEXT: (block $out1
;; CHECK-NEXT: (block $out2
;; CHECK-NEXT: (return_call $void-callee)
Expand All @@ -482,7 +496,7 @@
)
)

;; CHECK: (func $void-br-table-not-all-tail (type $3) (param $idx i32)
;; CHECK: (func $void-br-table-not-all-tail (type $i32-to-none) (param $idx i32)
;; CHECK-NEXT: (block $exit
;; CHECK-NEXT: (block $not-exit
;; CHECK-NEXT: (call $void-callee)
Expand All @@ -507,7 +521,7 @@
)
)

;; CHECK: (func $loop-tail (type $1) (param $condition i32) (result i32)
;; CHECK: (func $loop-tail (type $2) (param $condition i32) (result i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (br_if $l
;; CHECK-NEXT: (local.get $condition)
Expand Down Expand Up @@ -579,4 +593,83 @@
(call $void-callee)
)
)

;; CHECK: (func $unreachable-arg-mismatched-call (type $none-to-i32) (result i32)
;; CHECK-NEXT: (call $void-arg-callee
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-arg-mismatched-call (result i32)
;; Unreachable calls (e.g. due to an unreachable operand) are not converted
;; to return calls, avoiding return type mismatches and optimizing dead code.
(call $void-arg-callee
(unreachable)
)
)

;; CHECK: (func $unreachable-arg-matching-call (type $none-to-i32) (result i32)
;; CHECK-NEXT: (call $param-callee
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-arg-matching-call (result i32)
(call $param-callee
(unreachable)
(i32.const 1)
)
)

;; CHECK: (func $unreachable-arg-mismatched-call-indirect (type $none-to-i32) (result i32)
;; CHECK-NEXT: (call_indirect $table (type $i32-to-none)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-arg-mismatched-call-indirect (result i32)
(call_indirect $table (type $i32-to-none)
(unreachable)
(i32.const 0)
)
)

;; CHECK: (func $unreachable-arg-mismatched-call-ref (type $10) (param $f (ref $i32-to-none)) (result i32)
;; CHECK-NEXT: (call_ref $i32-to-none
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (local.get $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-arg-mismatched-call-ref (param $f (ref $i32-to-none)) (result i32)
(call_ref $i32-to-none
(unreachable)
(local.get $f)
)
)

;; CHECK: (func $unreachable-arg-mismatched-cwe (type $none-to-i32) (result i32)
;; CHECK-NEXT: (call $cwe
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (ref.func $void-arg-callee)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-arg-mismatched-cwe (result i32)
(call $cwe
(unreachable)
(ref.func $void-arg-callee)
)
)

;; CHECK: (func $tail-cwe (type $none-to-i32) (result i32)
;; CHECK-NEXT: (return_call $cwe
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (ref.func $i32-to-i32-callee)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $tail-cwe (result i32)
;; call.without.effects is optimized when reachable.
(call $cwe
Comment thread
tlively marked this conversation as resolved.
(i32.const 42)
(ref.func $i32-to-i32-callee)
)
)
)
Loading