| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s | |
| ; Test that the "returned" attribute is optimized effectively. | |
| target triple = "wasm32-unknown-unknown" | |
| %class.Apple = type { i8 } | |
| declare noalias ptr @_Znwm(i32) | |
| declare ptr @_ZN5AppleC1Ev(ptr returned) | |
| define ptr @_Z3foov() { | |
| ; CHECK-LABEL: _Z3foov: | |
| ; CHECK: .functype _Z3foov () -> (i32) | |
| ; CHECK-NEXT: # %bb.0: # %entry | |
| ; CHECK-NEXT: i32.const $push0=, 1 | |
| ; CHECK-NEXT: call $push1=, _Znwm, $pop0 | |
| ; CHECK-NEXT: call $push2=, _ZN5AppleC1Ev, $pop1 | |
| ; CHECK-NEXT: return $pop2 | |
| entry: | |
| %call = tail call noalias ptr @_Znwm(i32 1) | |
| %call1 = tail call ptr @_ZN5AppleC1Ev(ptr %call) | |
| ret ptr %call | |
| } | |
| declare ptr @memcpy(ptr returned, ptr, i32) | |
| define ptr @_Z3barPvS_l(ptr %p, ptr %s, i32 %n) { | |
| ; CHECK-LABEL: _Z3barPvS_l: | |
| ; CHECK: .functype _Z3barPvS_l (i32, i32, i32) -> (i32) | |
| ; CHECK-NEXT: # %bb.0: # %entry | |
| ; CHECK-NEXT: call $push0=, memcpy, $0, $1, $2 | |
| ; CHECK-NEXT: return $pop0 | |
| entry: | |
| %call = tail call ptr @memcpy(ptr %p, ptr %s, i32 %n) | |
| ret ptr %p | |
| } | |
| ; Test that the optimization isn't performed on constant arguments. | |
| @global = external global i32 | |
| @addr = global ptr @global | |
| define void @test_constant_arg() { | |
| ; CHECK-LABEL: test_constant_arg: | |
| ; CHECK: .functype test_constant_arg () -> () | |
| ; CHECK-NEXT: # %bb.0: | |
| ; CHECK-NEXT: i32.const $push0=, global | |
| ; CHECK-NEXT: call $drop=, returns_arg, $pop0 | |
| ; CHECK-NEXT: return | |
| %call = call ptr @returns_arg(ptr @global) | |
| ret void | |
| } | |
| declare ptr @returns_arg(ptr returned) | |
| ; Test that the optimization isn't performed on arguments without the | |
| ; "returned" attribute. | |
| declare i32 @do_something(i32 returned, i32, double) | |
| declare void @do_something_with_i32(i32) | |
| declare void @do_something_with_double(double) | |
| define void @test_other_skipped(i32 %a, i32 %b, double %c) { | |
| ; CHECK-LABEL: test_other_skipped: | |
| ; CHECK: .functype test_other_skipped (i32, i32, f64) -> () | |
| ; CHECK-NEXT: # %bb.0: | |
| ; CHECK-NEXT: call $drop=, do_something, $0, $1, $2 | |
| ; CHECK-NEXT: call do_something_with_i32, $1 | |
| ; CHECK-NEXT: call do_something_with_double, $2 | |
| ; CHECK-NEXT: return | |
| %call = call i32 @do_something(i32 %a, i32 %b, double %c) | |
| call void @do_something_with_i32(i32 %b) | |
| call void @do_something_with_double(double %c) | |
| ret void | |
| } | |
| ; Test that the optimization is performed on arguments other than the first. | |
| declare i32 @do_something_else(i32, i32 returned) | |
| define i32 @test_second_arg(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: test_second_arg: | |
| ; CHECK: .functype test_second_arg (i32, i32) -> (i32) | |
| ; CHECK-NEXT: # %bb.0: | |
| ; CHECK-NEXT: call $push0=, do_something_else, $0, $1 | |
| ; CHECK-NEXT: return $pop0 | |
| %call = call i32 @do_something_else(i32 %a, i32 %b) | |
| ret i32 %b | |
| } | |
| define void @test() { | |
| ; CHECK-LABEL: test: | |
| ; CHECK: .functype test () -> () | |
| ; CHECK-NEXT: # %bb.0: # %entry | |
| ; CHECK-NEXT: global.get $push0=, __stack_pointer | |
| ; CHECK-NEXT: i32.const $push1=, 16 | |
| ; CHECK-NEXT: i32.sub $push7=, $pop0, $pop1 | |
| ; CHECK-NEXT: local.tee $push6=, $0=, $pop7 | |
| ; CHECK-NEXT: global.set __stack_pointer, $pop6 | |
| ; CHECK-NEXT: i32.const $push4=, 12 | |
| ; CHECK-NEXT: i32.add $push5=, $0, $pop4 | |
| ; CHECK-NEXT: call $drop=, returns_arg, $pop5 | |
| ; CHECK-NEXT: i32.const $push2=, 16 | |
| ; CHECK-NEXT: i32.add $push3=, $0, $pop2 | |
| ; CHECK-NEXT: global.set __stack_pointer, $pop3 | |
| ; CHECK-NEXT: return | |
| entry: | |
| %a = alloca i32 | |
| call void @llvm.lifetime.start.p0(ptr %a) | |
| %ret = call ptr @returns_arg(ptr %a) | |
| call void @llvm.lifetime.end.p0(ptr %a) | |
| ret void | |
| } |