242 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc %s -o - -mtriple=thumbv8m.base | FileCheck %s3 4declare i32 @g(...)5 6declare i32 @h0(i32, i32, i32, i32)7define hidden i32 @f0() {8; CHECK-LABEL: f0:9; CHECK: @ %bb.0:10; CHECK-NEXT: push {r7, lr}11; CHECK-NEXT: bl g12; CHECK-NEXT: movs r1, #113; CHECK-NEXT: movs r2, #214; CHECK-NEXT: movs r3, #315; CHECK-NEXT: ldr r7, [sp, #4]16; CHECK-NEXT: mov lr, r717; CHECK-NEXT: pop {r7}18; CHECK-NEXT: add sp, #419; CHECK-NEXT: b h020 %1 = tail call i32 @g()21 %2 = tail call i32 @h0(i32 %1, i32 1, i32 2, i32 3)22 ret i32 %223}24 25declare i32 @h1(i32)26define hidden i32 @f1() {27; CHECK-LABEL: f1:28; CHECK: @ %bb.0:29; CHECK-NEXT: push {r7, lr}30; CHECK-NEXT: bl g31; CHECK-NEXT: pop {r7}32; CHECK-NEXT: pop {r1}33; CHECK-NEXT: mov lr, r134; CHECK-NEXT: b h135 %1 = tail call i32 @g()36 %2 = tail call i32 @h1(i32 %1)37 ret i32 %238}39 40declare i32 @h2(i32, i32, i32, i32, i32)41define hidden i32 @f2(i32, i32, i32, i32, i32) {42; CHECK-LABEL: f2:43; CHECK: @ %bb.0:44; CHECK-NEXT: push {r4, r5, r6, r7, lr}45; CHECK-NEXT: sub sp, #446; CHECK-NEXT: mov r4, r347; CHECK-NEXT: mov r5, r248; CHECK-NEXT: mov r6, r149; CHECK-NEXT: ldr r7, [sp, #24]50; CHECK-NEXT: bl g51; CHECK-NEXT: cbz r0, .LBB2_252; CHECK-NEXT: @ %bb.1:53; CHECK-NEXT: str r7, [sp, #24]54; CHECK-NEXT: mov r1, r655; CHECK-NEXT: mov r2, r556; CHECK-NEXT: mov r3, r457; CHECK-NEXT: add sp, #458; CHECK-NEXT: ldr r4, [sp, #16]59; CHECK-NEXT: mov lr, r460; CHECK-NEXT: pop {r4, r5, r6, r7}61; CHECK-NEXT: add sp, #462; CHECK-NEXT: b h263; CHECK-NEXT: .LBB2_2:64; CHECK-NEXT: movs r0, #065; CHECK-NEXT: mvns r0, r066; CHECK-NEXT: add sp, #467; CHECK-NEXT: pop {r4, r5, r6, r7, pc}68 %6 = tail call i32 @g()69 %7 = icmp eq i32 %6, 070 br i1 %7, label %10, label %871 72 %9 = tail call i32 @h2(i32 %6, i32 %1, i32 %2, i32 %3, i32 %4)73 br label %1074 75 %11 = phi i32 [ %9, %8 ], [ -1, %5 ]76 ret i32 %1177}78 79; Make sure that tail calls to function pointers that require r0-r3 for argument80; passing do not break the compiler.81@fnptr = global ptr null82define i32 @test3() {83; CHECK-LABEL: test3:84; CHECK: @ %bb.0:85; CHECK-NEXT: push {r4, lr}86; CHECK-NEXT: movw r0, :lower16:fnptr87; CHECK-NEXT: movt r0, :upper16:fnptr88; CHECK-NEXT: ldr r4, [r0]89; CHECK-NEXT: movs r0, #190; CHECK-NEXT: movs r1, #291; CHECK-NEXT: movs r2, #392; CHECK-NEXT: movs r3, #493; CHECK-NEXT: blx r494; CHECK-NEXT: pop {r4, pc}95 %1 = load ptr, ptr @fnptr96 %2 = tail call i32 %1(i32 1, i32 2, i32 3, i32 4)97 ret i32 %298}99 100@fnptr2 = global ptr null101define i32 @test4() {102; CHECK-LABEL: test4:103; CHECK: @ %bb.0:104; CHECK-NEXT: push {r4, lr}105; CHECK-NEXT: movw r0, :lower16:fnptr2106; CHECK-NEXT: movt r0, :upper16:fnptr2107; CHECK-NEXT: ldr r4, [r0]108; CHECK-NEXT: movs r0, #1109; CHECK-NEXT: movs r1, #2110; CHECK-NEXT: movs r2, #3111; CHECK-NEXT: movs r3, #0112; CHECK-NEXT: blx r4113; CHECK-NEXT: pop {r4, pc}114 %1 = load ptr, ptr @fnptr2115 %2 = tail call i32 %1(i32 1, i32 2, i64 3)116 ret i32 %2117}118 119; Check that tail calls to function pointers where not all of r0-r3 are used for120; parameter passing are tail-call optimized.121; test5: params in r0, r1. r2 & r3 are free.122@fnptr3 = global ptr null123define i32 @test5() {124; CHECK-LABEL: test5:125; CHECK: @ %bb.0:126; CHECK-NEXT: movw r0, :lower16:fnptr3127; CHECK-NEXT: movt r0, :upper16:fnptr3128; CHECK-NEXT: ldr r2, [r0]129; CHECK-NEXT: movs r0, #1130; CHECK-NEXT: movs r1, #2131; CHECK-NEXT: bx r2132 %1 = load ptr, ptr @fnptr3133 %2 = tail call i32 %1(i32 1, i32 2)134 ret i32 %2135}136 137; test6: params in r0 and r2-r3. r1 is free.138@fnptr4 = global ptr null139define i32 @test6() {140; CHECK-LABEL: test6:141; CHECK: @ %bb.0:142; CHECK-NEXT: movw r0, :lower16:fnptr4143; CHECK-NEXT: movt r0, :upper16:fnptr4144; CHECK-NEXT: ldr r1, [r0]145; CHECK-NEXT: movs r0, #1146; CHECK-NEXT: movs r2, #2147; CHECK-NEXT: movs r3, #0148; CHECK-NEXT: bx r1149 %1 = load ptr, ptr @fnptr4150 %2 = tail call i32 %1(i32 1, i64 2)151 ret i32 %2152}153 154; Check that tail calls to functions other than function pointers are155; tail-call optimized.156define i32 @test7() {157; CHECK-LABEL: test7:158; CHECK: @ %bb.0:159; CHECK-NEXT: movs r0, #1160; CHECK-NEXT: movs r1, #2161; CHECK-NEXT: movs r2, #3162; CHECK-NEXT: movs r3, #4163; CHECK-NEXT: b bar164 %tail = tail call i32 @bar(i32 1, i32 2, i32 3, i32 4)165 ret i32 %tail166}167 168declare i32 @bar(i32, i32, i32, i32)169 170; Regression test for failure to load indirect branch target (class tcGPR) from171; a stack slot.172%struct.S = type { i32 }173 174define void @test8(ptr nocapture %fn, i32 %x) local_unnamed_addr {175; CHECK-LABEL: test8:176; CHECK: @ %bb.0: @ %entry177; CHECK-NEXT: push {r4, r5, r6, r7, lr}178; CHECK-NEXT: sub sp, #4179; CHECK-NEXT: mov r4, r1180; CHECK-NEXT: str r0, [sp] @ 4-byte Spill181; CHECK-NEXT: bl test8_u182; CHECK-NEXT: mov r5, r0183; CHECK-NEXT: ldr r6, [r0]184; CHECK-NEXT: movs r7, #0185; CHECK-NEXT: mov r0, r7186; CHECK-NEXT: bl test8_h187; CHECK-NEXT: mov r1, r0188; CHECK-NEXT: mov r0, r6189; CHECK-NEXT: mov r2, r7190; CHECK-NEXT: bl test8_g191; CHECK-NEXT: str r4, [r5]192; CHECK-NEXT: movs r0, #1193; CHECK-NEXT: movs r1, #2194; CHECK-NEXT: movs r2, #3195; CHECK-NEXT: ldr r3, [sp] @ 4-byte Reload196; CHECK-NEXT: add sp, #4197; CHECK-NEXT: ldr r4, [sp, #16]198; CHECK-NEXT: mov lr, r4199; CHECK-NEXT: pop {r4, r5, r6, r7}200; CHECK-NEXT: add sp, #4201; CHECK-NEXT: bx r3202entry:203 %call = tail call ptr @test8_u()204 %0 = load i32, ptr %call, align 4205 %call1 = tail call i32 @test8_h(i32 0)206 %call2 = tail call i32 @test8_g(i32 %0, i32 %call1, i32 0)207 store i32 %x, ptr %call, align 4208 %call4 = tail call i32 %fn(i32 1, i32 2, i32 3)209 ret void210}211 212declare ptr @test8_u(...)213 214declare i32 @test8_g(i32, i32, i32)215 216declare i32 @test8_h(i32)217 218; Check that we don't introduce an unnecessary spill of lr.219declare i32 @h9(i32, i32, i32, i32)220define i32 @test9(ptr %x, ptr %y, ptr %z, ptr %a) {221; CHECK-LABEL: test9:222; CHECK: @ %bb.0:223; CHECK-NEXT: push {r4, r7}224; CHECK-NEXT: ldr r4, [r3]225; CHECK-NEXT: ldr r3, [r3, #4]226; CHECK-NEXT: adds r3, r4, r3227; CHECK-NEXT: ldr r1, [r1]228; CHECK-NEXT: ldr r0, [r0]229; CHECK-NEXT: ldr r2, [r2]230; CHECK-NEXT: pop {r4, r7}231; CHECK-NEXT: b h9232 %zz = load i32, ptr %z233 %xx = load i32, ptr %x234 %yy = load i32, ptr %y235 %aa1 = load i32, ptr %a236 %a2 = getelementptr i32, ptr %a, i32 1237 %aa2 = load i32, ptr %a2238 %aa = add i32 %aa1, %aa2239 %r = tail call i32 @h9(i32 %xx, i32 %yy, i32 %zz, i32 %aa)240 ret i32 %r241}242