Index: lib/Target/ARM/ARMCallingConv.td =================================================================== --- lib/Target/ARM/ARMCallingConv.td +++ lib/Target/ARM/ARMCallingConv.td @@ -23,8 +23,8 @@ CCIfType<[i1, i8, i16], CCPromoteToType>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf>>, // A SwiftError is passed in R6. CCIfSwiftError>>, @@ -160,8 +160,8 @@ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf>>, // A SwiftError is passed in R6. CCIfSwiftError>>, @@ -197,8 +197,8 @@ CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, - // A SwiftSelf is passed in R9. - CCIfSwiftSelf>>, + // Pass SwiftSelf in a callee saved register. + CCIfSwiftSelf>>, // A SwiftError is passed in R6. CCIfSwiftError>>, Index: lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- lib/Target/ARM/ARMFrameLowering.cpp +++ lib/Target/ARM/ARMFrameLowering.cpp @@ -910,27 +910,21 @@ 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()) Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -2146,10 +2146,11 @@ 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,25 @@ } } } + + // 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(); + if (!MachineOperand::clobbersPhysReg(CallerPreserved, Reg)) { + // Check that we pass the value used for the caller. + SDValue Value = OutVals[I]; + if (Value->getOpcode() != ISD::CopyFromReg) + return false; + unsigned ArgReg = cast(Value->getOperand(1))->getReg(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + if (MRI.getLiveInPhysReg(ArgReg) != Reg) + return false; + } + } } return true; Index: test/CodeGen/ARM/swiftself.ll =================================================================== --- test/CodeGen/ARM/swiftself.ll +++ test/CodeGen/ARM/swiftself.ll @@ -1,32 +1,62 @@ -; 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: bl {{_?}}swiftself_param +; 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: 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 }