CXX_FAST_TLS calling convention: Add support for ARM on Darwin.
authorManman Ren <manman.ren@gmail.com>
Mon, 11 Jan 2016 23:50:43 +0000 (23:50 +0000)
committerManman Ren <manman.ren@gmail.com>
Mon, 11 Jan 2016 23:50:43 +0000 (23:50 +0000)
rdar://9001553

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257417 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMBaseRegisterInfo.cpp
lib/Target/ARM/ARMBaseRegisterInfo.h
lib/Target/ARM/ARMCallingConv.td
lib/Target/ARM/ARMISelLowering.cpp
test/CodeGen/ARM/cxx-tlscc.ll [new file with mode: 0644]

index adc6b6b1894af8f3959353b065cc77583b14fb0c..595975de9054eccd10eca68c636a05a6ac506ad9 100644 (file)
@@ -87,6 +87,8 @@ ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
     }
   }
 
+  if (STI.isTargetDarwin() && F->getCallingConv() == CallingConv::CXX_FAST_TLS)
+    return CSR_iOS_CXX_TLS_SaveList;
   return RegList;
 }
 
@@ -97,6 +99,8 @@ ARMBaseRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
   if (CC == CallingConv::GHC)
     // This is academic becase all GHC calls are (supposed to be) tail calls
     return CSR_NoRegs_RegMask;
+  if (STI.isTargetDarwin() && CC == CallingConv::CXX_FAST_TLS)
+    return CSR_iOS_CXX_TLS_RegMask;
   return STI.isTargetDarwin() ? CSR_iOS_RegMask : CSR_AAPCS_RegMask;
 }
 
index e2335b0480e77c1dd7a6b505ade8469161131e8a..4c762dc1a23481102a225ace8c896a532d1959c3 100644 (file)
@@ -62,6 +62,12 @@ static inline bool isARMArea3Register(unsigned Reg, bool isIOS) {
   switch (Reg) {
     case D15: case D14: case D13: case D12:
     case D11: case D10: case D9:  case D8:
+    case D7:  case D6:  case D5:  case D4:
+    case D3:  case D2:  case D1:  case D0:
+    case D31: case D30: case D29: case D28:
+    case D27: case D26: case D25: case D24:
+    case D23: case D22: case D21: case D20:
+    case D19: case D18: case D17: case D16:
       return true;
     default:
       return false;
index 22ea166d540235740797bc08f38b93bf9a1980b1..e386a2e5cff8accecbeae3247b44248e64594382 100644 (file)
@@ -229,6 +229,11 @@ def CSR_iOS_TLSCall : CalleeSavedRegs<(add LR, SP,
                                            (sequence "R%u", 12, 1),
                                            (sequence "D%u", 31, 0))>;
 
+// C++ TLS access function saves all registers except SP. Try to match
+// the order of CSRs in CSR_iOS.
+def CSR_iOS_CXX_TLS : CalleeSavedRegs<(add CSR_iOS, (sequence "R%u", 12, 1),
+                                           (sequence "D%u", 31, 0))>;
+
 // The "interrupt" attribute is used to generate code that is acceptable in
 // exception-handlers of various kinds. It makes us use a different return
 // instruction (handled elsewhere) and affects which registers we must return to
index 1f93d2c38b9b8a90690e75b8f8ef42c8f80bb808..3c7356ada6cac98ce78b83b6de3b3dd8b2af1652 100644 (file)
@@ -1385,6 +1385,7 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
     else
       return CallingConv::ARM_AAPCS;
   case CallingConv::Fast:
+  case CallingConv::CXX_FAST_TLS:
     if (!Subtarget->isAAPCS_ABI()) {
       if (Subtarget->hasVFP2() && !Subtarget->isThumb1Only() && !isVarArg)
         return CallingConv::Fast;
diff --git a/test/CodeGen/ARM/cxx-tlscc.ll b/test/CodeGen/ARM/cxx-tlscc.ll
new file mode 100644 (file)
index 0000000..7fb9b18
--- /dev/null
@@ -0,0 +1,44 @@
+; RUN: llc < %s -mtriple=armv7k-apple-watchos2.0 | FileCheck %s
+; RUN: llc < %s -mtriple=armv7k-apple-watchos2.0 -enable-shrink-wrap=true | FileCheck --check-prefix=CHECK %s
+; RUN: llc < %s -mtriple=armv7-apple-ios8.0 | FileCheck %s
+; RUN: llc < %s -mtriple=armv7-apple-ios8.0 -enable-shrink-wrap=true | FileCheck --check-prefix=CHECK %s
+
+%struct.S = type { i8 }
+
+@sg = internal thread_local global %struct.S zeroinitializer, align 1
+@__dso_handle = external global i8
+@__tls_guard = internal thread_local unnamed_addr global i1 false
+
+declare %struct.S* @_ZN1SC1Ev(%struct.S* returned)
+declare %struct.S* @_ZN1SD1Ev(%struct.S* returned)
+declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*)
+
+define cxx_fast_tlscc nonnull %struct.S* @_ZTW2sg() nounwind {
+  %.b.i = load i1, i1* @__tls_guard, align 1
+  br i1 %.b.i, label %__tls_init.exit, label %init.i
+
+init.i:
+  store i1 true, i1* @__tls_guard, align 1
+  %call.i.i = tail call %struct.S* @_ZN1SC1Ev(%struct.S* nonnull @sg)
+  %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)
+  br label %__tls_init.exit
+
+__tls_init.exit:
+  ret %struct.S* @sg
+}
+
+; CHECK-LABEL: _ZTW2sg
+; CHECK: push {r1, r2, r3, r4, r7, lr}
+; CHECK: push {r9, r12}
+; CHECK: vpush {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31}
+; CHECK: vpush {d0, d1, d2, d3, d4, d5, d6, d7}
+; CHECK: blx
+; CHECK: bne [[BB_end:.?LBB0_[0-9]+]]
+; CHECK; blx
+; CHECK: tlv_atexit
+; CHECK: [[BB_end]]:
+; CHECK: blx
+; CHECK: vpop {d0, d1, d2, d3, d4, d5, d6, d7}
+; CHECK: vpop {d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31}
+; CHECK: pop {r9, r12}
+; CHECK: pop {r1, r2, r3, r4, r7, pc}