brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · aa7b81d Raw
343 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 52; RUN: llc -mtriple=armv7a-none-eabi %s -o - | FileCheck %s3 4declare i32 @many_args_callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5)5 6define i32 @many_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32  %5) {7; CHECK-LABEL: many_args_tail:8; CHECK:       @ %bb.0:9; CHECK-NEXT:    mov r0, #510; CHECK-NEXT:    mov r1, #211; CHECK-NEXT:    str r0, [sp]12; CHECK-NEXT:    mov r0, #613; CHECK-NEXT:    str r0, [sp, #4]14; CHECK-NEXT:    mov r0, #115; CHECK-NEXT:    mov r2, #316; CHECK-NEXT:    mov r3, #417; CHECK-NEXT:    b many_args_callee18  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)19  ret i32 %ret20}21 22define i32 @many_args_musttail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32  %5) {23; CHECK-LABEL: many_args_musttail:24; CHECK:       @ %bb.0:25; CHECK-NEXT:    mov r0, #526; CHECK-NEXT:    mov r1, #227; CHECK-NEXT:    str r0, [sp]28; CHECK-NEXT:    mov r0, #629; CHECK-NEXT:    str r0, [sp, #4]30; CHECK-NEXT:    mov r0, #131; CHECK-NEXT:    mov r2, #332; CHECK-NEXT:    mov r3, #433; CHECK-NEXT:    b many_args_callee34  %ret = musttail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)35  ret i32 %ret36}37 38; This function has more arguments than it's tail-callee. This isn't valid for39; the musttail attribute, but can still be tail-called as a non-guaranteed40; optimisation, because the outgoing arguments to @many_args_callee fit in the41; stack space allocated by the caller of @more_args_tail.42define i32 @more_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4, i32 %5, i32 %6) {43; CHECK-LABEL: more_args_tail:44; CHECK:       @ %bb.0:45; CHECK-NEXT:    mov r0, #546; CHECK-NEXT:    mov r1, #247; CHECK-NEXT:    str r0, [sp]48; CHECK-NEXT:    mov r0, #649; CHECK-NEXT:    str r0, [sp, #4]50; CHECK-NEXT:    mov r0, #151; CHECK-NEXT:    mov r2, #352; CHECK-NEXT:    mov r3, #453; CHECK-NEXT:    b many_args_callee54  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)55  ret i32 %ret56}57 58; Again, this isn't valid for musttail, but can be tail-called in practice59; because the stack size if the same.60define i32 @different_args_tail(i64 %0, i64 %1, i64 %2) {61; CHECK-LABEL: different_args_tail:62; CHECK:       @ %bb.0:63; CHECK-NEXT:    mov r0, #564; CHECK-NEXT:    mov r1, #265; CHECK-NEXT:    str r0, [sp]66; CHECK-NEXT:    mov r0, #667; CHECK-NEXT:    str r0, [sp, #4]68; CHECK-NEXT:    mov r0, #169; CHECK-NEXT:    mov r2, #370; CHECK-NEXT:    mov r3, #471; CHECK-NEXT:    b many_args_callee72  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)73  ret i32 %ret74}75 76; Here, the caller requires less stack space for it's arguments than the77; callee, so it would not ba valid to do a tail-call.78define i32 @fewer_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32  %4) {79; CHECK-LABEL: fewer_args_tail:80; CHECK:       @ %bb.0:81; CHECK-NEXT:    .save {r11, lr}82; CHECK-NEXT:    push {r11, lr}83; CHECK-NEXT:    .pad #884; CHECK-NEXT:    sub sp, sp, #885; CHECK-NEXT:    mov r1, #686; CHECK-NEXT:    mov r0, #587; CHECK-NEXT:    strd r0, r1, [sp]88; CHECK-NEXT:    mov r0, #189; CHECK-NEXT:    mov r1, #290; CHECK-NEXT:    mov r2, #391; CHECK-NEXT:    mov r3, #492; CHECK-NEXT:    bl many_args_callee93; CHECK-NEXT:    add sp, sp, #894; CHECK-NEXT:    pop {r11, pc}95  %ret = tail call i32 @many_args_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6)96  ret i32 %ret97}98 99declare void @sret_callee(ptr sret({ double, double }) align 8)100 101; Functions which return by sret can be tail-called because the incoming sret102; pointer gets passed through to the callee.103define void @sret_caller_tail(ptr sret({ double, double }) align 8 %result) {104; CHECK-LABEL: sret_caller_tail:105; CHECK:       @ %bb.0: @ %entry106; CHECK-NEXT:    b sret_callee107entry:108  tail call void @sret_callee(ptr sret({ double, double }) align 8 %result)109  ret void110}111 112define void @sret_caller_musttail(ptr sret({ double, double }) align 8 %result) {113; CHECK-LABEL: sret_caller_musttail:114; CHECK:       @ %bb.0: @ %entry115; CHECK-NEXT:    b sret_callee116entry:117  musttail call void @sret_callee(ptr sret({ double, double }) align 8 %result)118  ret void119}120 121; Clang only uses byval for arguments of 65 bytes or larger, but we test with a122; 20 byte struct to keep the tests more readable. This size was chosen to still123; make sure that it will be split between registers and the stack, to test all124; of the interesting code paths in the backend.125%twenty_bytes = type { [5 x i32] }126declare void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4)127 128; Functions with byval parameters can be tail-called, because the value is129; actually passed in registers and the stack in the same way for the caller and130; callee. Within @large_caller the first 16 bytes of the argument are spilled131; to the local stack frame, but for the tail-call they are passed in r0-r3, so132; it's safe to de-allocate that memory before the call.133; TODO: The SUB and STM instructions are unnecessary and could be optimised134; out, but the behaviour of this is still correct.135define void @large_caller(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {136; CHECK-LABEL: large_caller:137; CHECK:       @ %bb.0: @ %entry138; CHECK-NEXT:    .pad #16139; CHECK-NEXT:    sub sp, sp, #16140; CHECK-NEXT:    stm sp!, {r0, r1, r2, r3}141; CHECK-NEXT:    b large_callee142entry:143  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %a)144  ret void145}146 147; As above, but with some inline asm to test that the arguments in r0-r3 are148; re-loaded before the call.149define void @large_caller_check_regs(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {150; CHECK-LABEL: large_caller_check_regs:151; CHECK:       @ %bb.0: @ %entry152; CHECK-NEXT:    .pad #16153; CHECK-NEXT:    sub sp, sp, #16154; CHECK-NEXT:    stm sp, {r0, r1, r2, r3}155; CHECK-NEXT:    @APP156; CHECK-NEXT:    @NO_APP157; CHECK-NEXT:    pop {r0, r1, r2, r3}158; CHECK-NEXT:    b large_callee159entry:160  tail call void asm sideeffect "", "~{r0},~{r1},~{r2},~{r3}"()161  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %a)162  ret void163}164 165; The IR for this one looks dodgy, because it has an alloca passed to a166; musttail function, but it is passed as a byval argument, so will be copied167; into the stack space allocated by @large_caller_new_value's caller, so is168; valid.169define void @large_caller_new_value(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {170; CHECK-LABEL: large_caller_new_value:171; CHECK:       @ %bb.0: @ %entry172; CHECK-NEXT:    .pad #36173; CHECK-NEXT:    sub sp, sp, #36174; CHECK-NEXT:    add r12, sp, #20175; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}176; CHECK-NEXT:    mov r0, #4177; CHECK-NEXT:    add r1, sp, #36178; CHECK-NEXT:    str r0, [sp, #16]179; CHECK-NEXT:    mov r0, #3180; CHECK-NEXT:    str r0, [sp, #12]181; CHECK-NEXT:    mov r0, #2182; CHECK-NEXT:    str r0, [sp, #8]183; CHECK-NEXT:    mov r0, #1184; CHECK-NEXT:    str r0, [sp, #4]185; CHECK-NEXT:    mov r0, #0186; CHECK-NEXT:    str r0, [sp]187; CHECK-NEXT:    mov r0, sp188; CHECK-NEXT:    add r0, r0, #16189; CHECK-NEXT:    mov r3, #3190; CHECK-NEXT:    ldr r2, [r0], #4191; CHECK-NEXT:    str r2, [r1], #4192; CHECK-NEXT:    mov r0, #0193; CHECK-NEXT:    mov r1, #1194; CHECK-NEXT:    mov r2, #2195; CHECK-NEXT:    add sp, sp, #36196; CHECK-NEXT:    b large_callee197entry:198  %y = alloca %twenty_bytes, align 4199  store i32 0, ptr %y, align 4200  %0 = getelementptr inbounds i8, ptr %y, i32 4201  store i32 1, ptr %0, align 4202  %1 = getelementptr inbounds i8, ptr %y, i32 8203  store i32 2, ptr %1, align 4204  %2 = getelementptr inbounds i8, ptr %y, i32 12205  store i32 3, ptr %2, align 4206  %3 = getelementptr inbounds i8, ptr %y, i32 16207  store i32 4, ptr %3, align 4208  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %y)209  ret void210}211 212declare void @two_byvals_callee(%twenty_bytes* byval(%twenty_bytes) align 4, %twenty_bytes* byval(%twenty_bytes) align 4)213define void @swap_byvals(%twenty_bytes* byval(%twenty_bytes) align 4 %a, %twenty_bytes* byval(%twenty_bytes) align 4 %b) {214; CHECK-LABEL: swap_byvals:215; CHECK:       @ %bb.0: @ %entry216; CHECK-NEXT:    .pad #16217; CHECK-NEXT:    sub sp, sp, #16218; CHECK-NEXT:    .save {r4, r5, r11, lr}219; CHECK-NEXT:    push {r4, r5, r11, lr}220; CHECK-NEXT:    .pad #40221; CHECK-NEXT:    sub sp, sp, #40222; CHECK-NEXT:    add r12, sp, #56223; CHECK-NEXT:    add lr, sp, #20224; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}225; CHECK-NEXT:    add r0, sp, #56226; CHECK-NEXT:    mov r12, sp227; CHECK-NEXT:    ldr r1, [r0], #4228; CHECK-NEXT:    mov r2, r12229; CHECK-NEXT:    str r1, [r2], #4230; CHECK-NEXT:    add r3, sp, #20231; CHECK-NEXT:    ldr r1, [r0], #4232; CHECK-NEXT:    add r4, sp, #76233; CHECK-NEXT:    str r1, [r2], #4234; CHECK-NEXT:    ldr r1, [r0], #4235; CHECK-NEXT:    str r1, [r2], #4236; CHECK-NEXT:    ldr r1, [r0], #4237; CHECK-NEXT:    str r1, [r2], #4238; CHECK-NEXT:    ldr r1, [r0], #4239; CHECK-NEXT:    add r0, sp, #76240; CHECK-NEXT:    str r1, [r2], #4241; CHECK-NEXT:    mov r2, lr242; CHECK-NEXT:    ldr r1, [r0], #4243; CHECK-NEXT:    str r1, [r2], #4244; CHECK-NEXT:    ldr r1, [r0], #4245; CHECK-NEXT:    str r1, [r2], #4246; CHECK-NEXT:    ldr r1, [r0], #4247; CHECK-NEXT:    str r1, [r2], #4248; CHECK-NEXT:    ldr r1, [r0], #4249; CHECK-NEXT:    str r1, [r2], #4250; CHECK-NEXT:    ldr r1, [r0], #4251; CHECK-NEXT:    str r1, [r2], #4252; CHECK-NEXT:    ldm r3, {r0, r1, r2, r3}253; CHECK-NEXT:    ldr r5, [r12], #4254; CHECK-NEXT:    str r5, [r4], #4255; CHECK-NEXT:    ldr r5, [r12], #4256; CHECK-NEXT:    str r5, [r4], #4257; CHECK-NEXT:    ldr r5, [r12], #4258; CHECK-NEXT:    str r5, [r4], #4259; CHECK-NEXT:    ldr r5, [r12], #4260; CHECK-NEXT:    str r5, [r4], #4261; CHECK-NEXT:    ldr r5, [r12], #4262; CHECK-NEXT:    str r5, [r4], #4263; CHECK-NEXT:    add r5, lr, #16264; CHECK-NEXT:    add r12, sp, #72265; CHECK-NEXT:    ldr r4, [r5], #4266; CHECK-NEXT:    str r4, [r12], #4267; CHECK-NEXT:    add sp, sp, #40268; CHECK-NEXT:    pop {r4, r5, r11, lr}269; CHECK-NEXT:    add sp, sp, #16270; CHECK-NEXT:    b two_byvals_callee271entry:272  musttail call void @two_byvals_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %b, %twenty_bytes* byval(%twenty_bytes) align 4 %a)273  ret void274}275 276; A forwarded byval arg, but at a different offset on the stack, so it needs to277; be copied to the local stack frame first. This can't be musttail because of278; the different signatures, but is still tail-called as an optimisation.279declare void @shift_byval_callee(%twenty_bytes* byval(%twenty_bytes) align 4)280define void @shift_byval(i32 %a, %twenty_bytes* byval(%twenty_bytes) align 4 %b) {281; CHECK-LABEL: shift_byval:282; CHECK:       @ %bb.0: @ %entry283; CHECK-NEXT:    .pad #12284; CHECK-NEXT:    sub sp, sp, #12285; CHECK-NEXT:    .save {r4, lr}286; CHECK-NEXT:    push {r4, lr}287; CHECK-NEXT:    .pad #20288; CHECK-NEXT:    sub sp, sp, #20289; CHECK-NEXT:    add r0, sp, #28290; CHECK-NEXT:    add lr, sp, #40291; CHECK-NEXT:    stm r0, {r1, r2, r3}292; CHECK-NEXT:    add r0, sp, #28293; CHECK-NEXT:    mov r1, sp294; CHECK-NEXT:    ldr r2, [r0], #4295; CHECK-NEXT:    add r12, r1, #16296; CHECK-NEXT:    str r2, [r1], #4297; CHECK-NEXT:    ldr r2, [r0], #4298; CHECK-NEXT:    str r2, [r1], #4299; CHECK-NEXT:    ldr r2, [r0], #4300; CHECK-NEXT:    str r2, [r1], #4301; CHECK-NEXT:    ldr r2, [r0], #4302; CHECK-NEXT:    str r2, [r1], #4303; CHECK-NEXT:    ldr r2, [r0], #4304; CHECK-NEXT:    str r2, [r1], #4305; CHECK-NEXT:    ldm sp, {r0, r1, r2, r3}306; CHECK-NEXT:    ldr r4, [r12], #4307; CHECK-NEXT:    str r4, [lr], #4308; CHECK-NEXT:    add sp, sp, #20309; CHECK-NEXT:    pop {r4, lr}310; CHECK-NEXT:    add sp, sp, #12311; CHECK-NEXT:    b shift_byval_callee312entry:313  tail call void @shift_byval_callee(%twenty_bytes* byval(%twenty_bytes) align 4 %b)314  ret void315}316 317; A global object passed to a byval argument, so it must be copied, but doesn't318; need a stack temporary.319@large_global = external global %twenty_bytes320define void @large_caller_from_global(%twenty_bytes* byval(%twenty_bytes) align 4 %a) {321; CHECK-LABEL: large_caller_from_global:322; CHECK:       @ %bb.0: @ %entry323; CHECK-NEXT:    .pad #16324; CHECK-NEXT:    sub sp, sp, #16325; CHECK-NEXT:    .save {r4, lr}326; CHECK-NEXT:    push {r4, lr}327; CHECK-NEXT:    add r12, sp, #8328; CHECK-NEXT:    add lr, sp, #24329; CHECK-NEXT:    stm r12, {r0, r1, r2, r3}330; CHECK-NEXT:    movw r3, :lower16:large_global331; CHECK-NEXT:    movt r3, :upper16:large_global332; CHECK-NEXT:    add r12, r3, #16333; CHECK-NEXT:    ldm r3, {r0, r1, r2, r3}334; CHECK-NEXT:    ldr r4, [r12], #4335; CHECK-NEXT:    str r4, [lr], #4336; CHECK-NEXT:    pop {r4, lr}337; CHECK-NEXT:    add sp, sp, #16338; CHECK-NEXT:    b large_callee339entry:340  musttail call void @large_callee(%twenty_bytes* byval(%twenty_bytes) align 4 @large_global)341  ret void342}343