1; RUN: llc < %s -mtriple=armv7k-apple-watchos2.0 | FileCheck %s 2; RUN: llc < %s -mtriple=armv7k-apple-watchos2.0 -enable-shrink-wrap=true | FileCheck %s 3; RUN: llc < %s -mtriple=armv7-apple-ios8.0 | FileCheck %s 4; RUN: llc < %s -mtriple=armv7-apple-ios8.0 -enable-shrink-wrap=true | FileCheck %s 5 6; RUN: llc < %s -mtriple=armv7k-apple-watchos2.0 -O0 | FileCheck --check-prefix=CHECK-O0 --check-prefix=WATCH-O0 %s 7; RUN: llc < %s -mtriple=armv7-apple-ios8.0 -O0 | FileCheck --check-prefix=CHECK-O0 --check-prefix=IOS-O0 %s 8 9; RUN: llc < %s -mtriple=thumbv7-apple-ios8.0 | FileCheck --check-prefix=THUMB %s 10 11%struct.S = type { i8 } 12 13@sg = internal thread_local global %struct.S zeroinitializer, align 1 14@__dso_handle = external global i8 15@__tls_guard = internal thread_local unnamed_addr global i1 false 16@sum1 = internal thread_local global i32 0, align 4 17 18%class.C = type { i32 } 19@tC = internal thread_local global %class.C zeroinitializer, align 4 20 21declare %struct.S* @_ZN1SC1Ev(%struct.S* returned) 22declare %struct.S* @_ZN1SD1Ev(%struct.S* returned) 23declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*) 24 25; Make sure Epilog does not overwrite an explicitly-handled CSR in CXX_FAST_TLS. 26; THUMB-LABEL: _ZTW2sg 27; THUMB: push {{.*}}lr 28; THUMB: blx 29; THUMB: bne{{(.w)?}} [[TH_end:.?LBB0_[0-9]+]] 30; THUMB: blx 31; THUMB: tlv_atexit 32; THUMB: [[TH_end]]: 33; THUMB: blx 34; THUMB: r4 35; THUMB: pop {{.*}}r4 36define cxx_fast_tlscc nonnull %struct.S* @_ZTW2sg() nounwind "no-frame-pointer-elim"="true" { 37 %.b.i = load i1, i1* @__tls_guard, align 1 38 br i1 %.b.i, label %__tls_init.exit, label %init.i 39 40init.i: 41 store i1 true, i1* @__tls_guard, align 1 42 %call.i.i = tail call %struct.S* @_ZN1SC1Ev(%struct.S* nonnull @sg) 43 %1 = tail call i32 @_tlv_atexit(void (i8*)* nonnull bitcast (%struct.S* (%struct.S*)* @_ZN1SD1Ev to void (i8*)*), i8* nonnull getelementptr inbounds (%struct.S, %struct.S* @sg, i64 0, i32 0), i8* nonnull @__dso_handle) 44 br label %__tls_init.exit 45 46__tls_init.exit: 47 ret %struct.S* @sg 48} 49 50; CHECK-LABEL: _ZTW2sg 51; CHECK: push {r4, r5, r7, lr} 52; CHECK: push {r11, r12} 53; CHECK-NOT: vpush {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} 54; CHECK-NOT: vpush {d0, d1, d2, d3, d4, d5, d6, d7} 55; CHECK: blx 56; CHECK: bne [[BB_end:.?LBB0_[0-9]+]] 57; CHECK: blx 58; CHECK: tlv_atexit 59; CHECK: [[BB_end]]: 60; CHECK: blx 61; CHECK-NOT: vpop {d0, d1, d2, d3, d4, d5, d6, d7} 62; CHECK-NOT: vpop {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} 63; CHECK-NOT: pop {r9, r12} 64; CHECK-NOT: pop {r1, r2, r3, r4, r7, pc} 65; CHECK: pop {r4, r5, r7, pc} 66 67; CHECK-O0-LABEL: _ZTW2sg 68; WATCH-O0: push {r1, r2, r3, r6, r7, lr} 69; IOS-O0: push {r1, r2, r3, r7, lr} 70; CHECK-O0: push {r9, r12} 71; CHECK-O0: vpush {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} 72; CHECK-O0: vpush {d0, d1, d2, d3, d4, d5, d6, d7} 73; CHECK-O0: blx 74; CHECK-O0: bne [[BB_end:.?LBB0_[0-9]+]] 75; CHECK-O0: blx 76; CHECK-O0: tlv_atexit 77; CHECK-O0: [[BB_end]]: 78; CHECK-O0: blx 79; CHECK-O0: vpop {d0, d1, d2, d3, d4, d5, d6, d7} 80; CHECK-O0: vpop {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} 81; CHECK-O0: pop {r9, r12} 82; WATCH-O0: pop {r1, r2, r3, r6, r7, pc} 83; IOS-O0: pop {r1, r2, r3, r7, pc} 84 85; CHECK-LABEL: _ZTW4sum1 86; CHECK-NOT: push {r1, r2, r3, r4, r7, lr} 87; CHECK-NOT: push {r9, r12} 88; CHECK-NOT: vpush {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31} 89; CHECK-NOT: vpush {d0, d1, d2, d3, d4, d5, d6, d7} 90; CHECK: blx 91 92; CHECK-O0-LABEL: _ZTW4sum1 93; CHECK-O0-NOT: vpush 94; CHECK-O0-NOT: vstr 95; CHECK-O0-NOT: vpop 96; CHECK-O0-NOT: vldr 97; CHECK-O0: pop 98define cxx_fast_tlscc nonnull i32* @_ZTW4sum1() nounwind "no-frame-pointer-elim"="true" { 99 ret i32* @sum1 100} 101 102; Make sure at O0, we don't generate spilling/reloading of the CSRs. 103; CHECK-O0-LABEL: tls_test2 104; CHECK-O0: push 105; CHECK-O0-NOT: vpush 106; CHECK-O0-NOT: vstr 107; CHECK-O0: tls_helper 108; CHECK-O0-NOT: vpop 109; CHECK-O0-NOT: vldr 110; CHECK-O0: pop 111declare cxx_fast_tlscc void @tls_helper() 112define cxx_fast_tlscc %class.C* @tls_test2() #1 "no-frame-pointer-elim"="true" { 113 call cxx_fast_tlscc void @tls_helper() 114 ret %class.C* @tC 115} 116 117; Make sure we do not allow tail call when caller and callee have different 118; calling conventions. 119declare %class.C* @_ZN1CD1Ev(%class.C* readnone returned %this) 120; CHECK-LABEL: tls_test 121; CHECK: bl __tlv_atexit 122define cxx_fast_tlscc void @__tls_test() "no-frame-pointer-elim"="true" { 123entry: 124 store i32 0, i32* getelementptr inbounds (%class.C, %class.C* @tC, i64 0, i32 0), align 4 125 %0 = tail call i32 @_tlv_atexit(void (i8*)* bitcast (%class.C* (%class.C*)* @_ZN1CD1Ev to void (i8*)*), i8* bitcast (%class.C* @tC to i8*), i8* nonnull @__dso_handle) #1 126 ret void 127} 128 129declare void @somefunc() 130define cxx_fast_tlscc void @test_ccmismatch_notail() "no-frame-pointer-elim"="true" { 131; A tail call is not possible here because somefunc does not preserve enough 132; registers. 133; CHECK-LABEL: test_ccmismatch_notail: 134; CHECK-NOT: b _somefunc 135; CHECK: bl _somefunc 136 tail call void @somefunc() 137 ret void 138} 139 140declare cxx_fast_tlscc void @some_fast_tls_func() 141define void @test_ccmismatch_tail() "no-frame-pointer-elim"="true" { 142; We can perform a tail call here because some_fast_tls_func preserves all 143; necessary registers (and more). 144; CHECK-LABEL: test_ccmismatch_tail: 145; CHECK-NOT: bl _some_fast_tls_func 146; CHECK: b _some_fast_tls_func 147 tail call cxx_fast_tlscc void @some_fast_tls_func() 148 ret void 149} 150 151attributes #0 = { nounwind "no-frame-pointer-elim"="true" } 152attributes #1 = { nounwind } 153