203 lines · plain
1; RUN: llc -mtriple armv7a--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLED2; RUN: llc -mtriple armv7a--none-eabi < %s -enable-ipra | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLED3 4define void @leaf() {5entry:6 tail call void asm sideeffect "", ""()7 ret void8}9 10define void @leaf_r3() {11entry:12 tail call void asm sideeffect "", "~{r3}"()13 ret void14}15 16define void @leaf_r4() {17entry:18 tail call void asm sideeffect "", "~{r4}"()19 ret void20}21 22define void @leaf_s0() {23entry:24 tail call void asm sideeffect "", "~{s0}"()25 ret void26}27 28define void @leaf_d0() {29entry:30 tail call void asm sideeffect "", "~{d0}"()31 ret void32}33 34; r3 is normally caller-saved, but with IPRA we can see that it isn't used in35; the callee, so can leave a live value in it.36define void @test_r3_presrved() {37; CHECK-LABEL: test_r3_presrved:38entry:39; CHECK: ASM1: r340; DISABLED: mov [[TEMP:r[0-9]+]], r341; ENABLED-NOT: r342; CHECK: bl leaf43; DISABLED: mov r3, [[TEMP]]44; ENABLED-NOT: r345; CHECK: ASM2: r346 %a = tail call i32 asm sideeffect "// ASM1: $0", "={r3},0"(i32 undef)47 tail call void @leaf()48 %b = tail call i32 asm sideeffect "// ASM2: $0", "={r3},0"(i32 %a)49 ret void50}51 52; Same as above, but r3 is clobbered in the callee, so it is clobbered by the53; call as normal.54define void @test_r3_clobbered() {55; CHECK-LABEL: test_r3_clobbered:56entry:57; CHECK: ASM1: r358; CHECK: mov [[TEMP:r[0-9]+]], r359; CHECK: bl leaf60; CHECK: mov r3, [[TEMP]]61; CHECK: ASM2: r362 %a = tail call i32 asm sideeffect "// ASM1: $0", "={r3},0"(i32 undef)63 tail call void @leaf_r3()64 %b = tail call i32 asm sideeffect "// ASM2: $0", "={r3},0"(i32 %a)65 ret void66}67 68; r4 is a callee-saved register, so IPRA has no effect.69define void @test_r4_preserved() {70; CHECK-LABEL: test_r4_preserved:71entry:72; CHECK: ASM1: r473; CHECK-NOT: r474; CHECK: bl leaf75; CHECK-NOT: r476; CHECK: ASM2: r477 %a = tail call i32 asm sideeffect "// ASM1: $0", "={r4},0"(i32 undef)78 tail call void @leaf()79 %b = tail call i32 asm sideeffect "// ASM2: $0", "={r4},0"(i32 %a)80 ret void81}82define void @test_r4_clobbered() {83; CHECK-LABEL: test_r4_clobbered:84entry:85; CHECK: ASM1: r486; CHECK-NOT: r487; CHECK: bl leaf_r488; CHECK-NOT: r489; CHECK: ASM2: r490 %a = tail call i32 asm sideeffect "// ASM1: $0", "={r4},0"(i32 undef)91 tail call void @leaf_r4()92 %b = tail call i32 asm sideeffect "// ASM2: $0", "={r4},0"(i32 %a)93 ret void94}95 96; r12 is the intra-call scratch register, so we have to assume it is clobbered97; even if we can see that the callee does not touch it.98define void @test_r12() {99; CHECK-LABEL: test_r12:100entry:101; CHECK: ASM1: r12102; CHECK: mov [[TEMP:r[0-9]+]], r12103; CHECK: bl leaf104; CHECK: mov r12, [[TEMP]]105; CHECK: ASM2: r12106 %a = tail call i32 asm sideeffect "// ASM1: $0", "={r12},0"(i32 undef)107 tail call void @leaf()108 %b = tail call i32 asm sideeffect "// ASM2: $0", "={r12},0"(i32 %a)109 ret void110}111 112; s0 and d0 are caller-saved, IPRA allows us to keep them live in the caller if113; the callee doesn't modify them.114define void @test_s0_preserved() {115; CHECK-LABEL: test_s0_preserved:116entry:117; CHECK: ASM1: s0118; DISABLED: vmov.f32 [[TEMP:s[0-9]+]], s0119; ENABLED-NOT: s0120; CHECK: bl leaf121; DISABLED: vmov.f32 s0, [[TEMP]]122; ENABLED-NOT: s0123; CHECK: ASM2: s0124 %a = tail call float asm sideeffect "// ASM1: $0", "={s0},0"(float undef)125 tail call void @leaf()126 %b = tail call float asm sideeffect "// ASM2: $0", "={s0},0"(float %a)127 ret void128}129 130define void @test_s0_clobbered() {131; CHECK-LABEL: test_s0_clobbered:132entry:133; CHECK: ASM1: s0134; CHECK: vmov.f32 [[TEMP:s[0-9]+]], s0135; CHECK: bl leaf_s0136; CHECK: vmov.f32 s0, [[TEMP]]137; CHECK: ASM2: s0138 %a = tail call float asm sideeffect "// ASM1: $0", "={s0},0"(float undef)139 tail call void @leaf_s0()140 %b = tail call float asm sideeffect "// ASM2: $0", "={s0},0"(float %a)141 ret void142}143 144define void @test_d0_preserved() {145; CHECK-LABEL: test_d0_preserved:146entry:147; CHECK: ASM1: d0148; DISABLED: vmov.f64 [[TEMP:d[0-9]+]], d0149; ENABLED-NOT: d0150; CHECK: bl leaf151; DISABLED: vmov.f64 d0, [[TEMP]]152; ENABLED-NOT: d0153; CHECK: ASM2: d0154 %a = tail call double asm sideeffect "// ASM1: $0", "={d0},0"(double undef)155 tail call void @leaf()156 %b = tail call double asm sideeffect "// ASM2: $0", "={d0},0"(double %a)157 ret void158}159 160define void @test_d0_clobbered() {161; CHECK-LABEL: test_d0_clobbered:162entry:163; CHECK: ASM1: d0164; CHECK: vmov.f64 [[TEMP:d[0-9]+]], d0165; CHECK: bl leaf_d0166; CHECK: vmov.f64 d0, [[TEMP]]167; CHECK: ASM2: d0168 %a = tail call double asm sideeffect "// ASM1: $0", "={d0},0"(double undef)169 tail call void @leaf_d0()170 %b = tail call double asm sideeffect "// ASM2: $0", "={d0},0"(double %a)171 ret void172}173 174; s0 and d0 overlap, so clobbering one in the callee prevents the other from175; being kept live across the call.176define void @test_s0_clobber_d0() {177; CHECK-LABEL: test_s0_clobber_d0:178entry:179; CHECK: ASM1: s0180; CHECK: vmov.f32 [[TEMP:s[0-9]+]], s0181; CHECK: bl leaf_d0182; CHECK: vmov.f32 s0, [[TEMP]]183; CHECK: ASM2: s0184 %a = tail call float asm sideeffect "// ASM1: $0", "={s0},0"(float undef)185 tail call void @leaf_d0()186 %b = tail call float asm sideeffect "// ASM2: $0", "={s0},0"(float %a)187 ret void188}189 190define void @test_d0_clobber_s0() {191; CHECK-LABEL: test_d0_clobber_s0:192entry:193; CHECK: ASM1: d0194; CHECK: vmov.f64 [[TEMP:d[0-9]+]], d0195; CHECK: bl leaf_s0196; CHECK: vmov.f64 d0, [[TEMP]]197; CHECK: ASM2: d0198 %a = tail call double asm sideeffect "// ASM1: $0", "={d0},0"(double undef)199 tail call void @leaf_s0()200 %b = tail call double asm sideeffect "// ASM2: $0", "={d0},0"(double %a)201 ret void202}203