diff options
-rw-r--r-- | llvm/lib/Target/ARM/ARMCallingConv.td | 21 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMFrameLowering.cpp | 22 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 29 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/swiftself.ll | 79 |
4 files changed, 105 insertions, 46 deletions
diff --git a/llvm/lib/Target/ARM/ARMCallingConv.td b/llvm/lib/Target/ARM/ARMCallingConv.td index 922b8001511..c477208b111 100644 --- a/llvm/lib/Target/ARM/ARMCallingConv.td +++ b/llvm/lib/Target/ARM/ARMCallingConv.td @@ -23,8 +23,8 @@ def CC_ARM_APCS : CallingConv<[ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, // A SwiftError is passed in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, @@ -48,6 +48,9 @@ def RetCC_ARM_APCS : CallingConv<[ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>, CCIfType<[f32], CCBitConvertToType<i32>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, + // A SwiftError is returned in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, @@ -160,8 +163,8 @@ def CC_ARM_AAPCS : CallingConv<[ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, // A SwiftError is passed in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, @@ -176,6 +179,9 @@ def RetCC_ARM_AAPCS : CallingConv<[ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, + // A SwiftError is returned in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, @@ -197,8 +203,8 @@ def CC_ARM_AAPCS_VFP : CallingConv<[ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, // A SwiftError is passed in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, @@ -218,6 +224,9 @@ def RetCC_ARM_AAPCS_VFP : CallingConv<[ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>, + // A SwiftError is returned in R6. CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>, diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp index d6bb723d477..71a5afd3e4d 100644 --- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp +++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp @@ -910,27 +910,21 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB, if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs) continue; - // Add the callee-saved register as live-in unless it's LR and - // @llvm.returnaddress is called. If LR is returned for - // @llvm.returnaddress then it's already added to the function and - // entry block live-in sets. - bool isKill = true; - if (Reg == ARM::LR) { - if (MF.getFrameInfo()->isReturnAddressTaken() && - MF.getRegInfo().isLiveIn(Reg)) - isKill = false; - } - - if (isKill) + bool isLiveIn = MF.getRegInfo().isLiveIn(Reg); + if (!isLiveIn) MBB.addLiveIn(Reg); - // If NoGap is true, push consecutive registers and then leave the rest // for other instructions. e.g. // vpush {d8, d10, d11} -> vpush {d8}, vpush {d10, d11} if (NoGap && LastReg && LastReg != Reg-1) break; LastReg = Reg; - Regs.push_back(std::make_pair(Reg, isKill)); + // Do not set a kill flag on values that are also marked as live-in. This + // happens with the @llvm-returnaddress intrinsic and with arguments + // passed in callee saved registers. + // Omitting the kill flags is conservatively correct even if the live-in + // is not used after all. + Regs.push_back(std::make_pair(Reg, /*isKill=*/!isLiveIn)); } if (Regs.empty()) diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 4c006d862fa..217e2550d9a 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2146,10 +2146,11 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, CCAssignFnForNode(CallerCC, true, isVarArg))) return false; // The callee has to preserve all registers the caller needs to preserve. + const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); + const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); if (CalleeCC != CallerCC) { - const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); - if (!TRI->regmaskSubsetEqual(TRI->getCallPreservedMask(MF, CallerCC), - TRI->getCallPreservedMask(MF, CalleeCC))) + const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); + if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) return false; } @@ -2206,6 +2207,28 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, } } } + + // Parameters passed in callee saved registers must have the same value in + // caller and callee. + for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) { + const CCValAssign &ArgLoc = ArgLocs[I]; + if (!ArgLoc.isRegLoc()) + continue; + unsigned Reg = ArgLoc.getLocReg(); + // Only look at callee saved registers. + if (MachineOperand::clobbersPhysReg(CallerPreserved, Reg)) + continue; + // Check that we pass the value used for the caller. + // (We look for a CopyFromReg reading a virtual register that is used + // for the function live-in value of register Reg) + SDValue Value = OutVals[I]; + if (Value->getOpcode() != ISD::CopyFromReg) + return false; + unsigned ArgReg = cast<RegisterSDNode>(Value->getOperand(1))->getReg(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + if (MRI.getLiveInPhysReg(ArgReg) != Reg) + return false; + } } return true; diff --git a/llvm/test/CodeGen/ARM/swiftself.ll b/llvm/test/CodeGen/ARM/swiftself.ll index cbeedc41066..6826b123472 100644 --- a/llvm/test/CodeGen/ARM/swiftself.ll +++ b/llvm/test/CodeGen/ARM/swiftself.ll @@ -1,32 +1,65 @@ -; RUN: llc -verify-machineinstrs < %s -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 | FileCheck --check-prefix=CHECK-APPLE %s -; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 | FileCheck --check-prefix=CHECK-O0 %s +; RUN: llc -verify-machineinstrs -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=OPT --check-prefix=TAILCALL %s +; RUN: llc -O0 -verify-machineinstrs -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 -o - %s | FileCheck %s -; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s -; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s +; RUN: llc -verify-machineinstrs -mtriple=armv7-apple-ios -o - %s | FileCheck --check-prefix=CHECK --check-prefix=OPT %s +; RUN: llc -O0 -verify-machineinstrs -mtriple=armv7-apple-ios -o - %s | FileCheck %s -; Parameter with swiftself should be allocated to r9. -define void @check_swiftself(i32* swiftself %addr0) { -; CHECK-APPLE-LABEL: check_swiftself: -; CHECK-O0-LABEL: check_swiftself: +; Parameter with swiftself should be allocated to r10. +; CHECK-LABEL: swiftself_param: +; CHECK: mov r0, r10 +define i8 *@swiftself_param(i8* swiftself %addr0) { + ret i8 *%addr0 +} - %val0 = load volatile i32, i32* %addr0 -; CHECK-APPLE: ldr r{{.*}}, [r9] -; CHECK-O0: ldr r{{.*}}, [r9] - ret void +; Check that r10 is used to pass a swiftself argument. +; CHECK-LABEL: call_swiftself: +; CHECK: mov r10, r0 +; CHECK: bl {{_?}}swiftself_param +define i8 *@call_swiftself(i8* %arg) { + %res = call i8 *@swiftself_param(i8* swiftself %arg) + ret i8 *%res } -@var8_3 = global i8 0 -declare void @take_swiftself(i8* swiftself %addr0) +; r10 should be saved by the callee even if used for swiftself +; CHECK-LABEL: swiftself_clobber: +; CHECK: push {r10} +; ... +; CHECK: pop {r10} +define i8 *@swiftself_clobber(i8* swiftself %addr0) { + call void asm sideeffect "", "~{r10}"() + ret i8 *%addr0 +} -define void @simple_args() { -; CHECK-APPLE-LABEL: simple_args: -; CHECK-O0-LABEL: simple_args: +; Demonstrate that we do not need any movs when calling multiple functions +; with swiftself argument. +; CHECK-LABEL: swiftself_passthrough: +; OPT-NOT: mov{{.*}}r10 +; OPT: bl {{_?}}swiftself_param +; OPT-NOT: mov{{.*}}r10 +; OPT-NEXT: bl {{_?}}swiftself_param +define void @swiftself_passthrough(i8* swiftself %addr0) { + call i8 *@swiftself_param(i8* swiftself %addr0) + call i8 *@swiftself_param(i8* swiftself %addr0) + ret void +} - call void @take_swiftself(i8* @var8_3) -; CHECK-APPLE: add r9, pc -; CHECK-APPLE: bl {{_?}}take_swiftself -; CHECK-O0: add r9, pc -; CHECK-O0: bl {{_?}}take_swiftself +; We can use a tail call if the callee swiftself is the same as the caller one. +; CHECK-LABEL: swiftself_tail: +; TAILCALL: b {{_?}}swiftself_param +; TAILCALL-NOT: pop +define i8* @swiftself_tail(i8* swiftself %addr0) { + call void asm sideeffect "", "~{r10}"() + %res = tail call i8* @swiftself_param(i8* swiftself %addr0) + ret i8* %res +} - ret void +; We can not use a tail call if the callee swiftself is not the same as the +; caller one. +; CHECK-LABEL: swiftself_notail: +; CHECK: mov r10, r0 +; CHECK: bl {{_?}}swiftself_param +; CHECK: pop +define i8* @swiftself_notail(i8* swiftself %addr0, i8* %addr1) nounwind { + %res = tail call i8* @swiftself_param(i8* swiftself %addr1) + ret i8* %res } |