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>>, // Handle all vector types as either f64 or v2f64. CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, @@ -154,8 +154,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>>, CCIfType<[f64, v2f64], CCCustom<"CC_ARM_AAPCS_Custom_f64">>, CCIfType<[f32], CCBitConvertToType>, @@ -185,8 +185,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>>, // HFAs are passed in a contiguous block of registers, or on the stack CCIfConsecutiveRegs>, Index: lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- lib/Target/ARM/ARMFrameLowering.cpp +++ lib/Target/ARM/ARMFrameLowering.cpp @@ -910,27 +910,19 @@ 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. + Regs.push_back(std::make_pair(Reg, /*isKill=*/!isLiveIn)); } if (Regs.empty()) Index: test/CodeGen/ARM/swiftself.ll =================================================================== --- test/CodeGen/ARM/swiftself.ll +++ test/CodeGen/ARM/swiftself.ll @@ -1,32 +1,42 @@ -; 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 %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: - - %val0 = load volatile i32, i32* %addr0 -; CHECK-APPLE: ldr r{{.*}}, [r9] -; CHECK-O0: ldr r{{.*}}, [r9] - ret void +; 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 } -@var8_3 = global i8 0 -declare void @take_swiftself(i8* swiftself %addr0) - -define void @simple_args() { -; CHECK-APPLE-LABEL: simple_args: -; CHECK-O0-LABEL: simple_args: +; 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 +} - 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 +; 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 +} +; 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 }