diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Target/ARM/ARM.td | 8 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMFrameLowering.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 12 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMSubtarget.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMSubtarget.h | 9 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMTargetTransformInfo.h | 4 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/reg-alloc-fixed-r6-vla.ll | 44 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6-modified.ll | 63 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6.ll | 57 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll | 58 | ||||
-rw-r--r-- | llvm/test/CodeGen/Thumb/callee_save_reserved.ll | 15 | ||||
-rw-r--r-- | llvm/test/Feature/reserve_global_reg.ll | 29 |
14 files changed, 334 insertions, 22 deletions
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td index 66bfd4c82e2..285dad1cf29 100644 --- a/llvm/lib/Target/ARM/ARM.td +++ b/llvm/lib/Target/ARM/ARM.td @@ -391,9 +391,11 @@ def FeatureExecuteOnly : SubtargetFeature<"execute-only", "Enable the generation of " "execute only code.">; -def FeatureReserveR9 : SubtargetFeature<"reserve-r9", "ReserveR9", "true", - "Reserve R9, making it unavailable" - " as GPR">; +foreach i = {6-11} in + def FeatureReserveR#i : SubtargetFeature<"reserve-r"#i, + "ReservedGPRegisters["#i#"]", "true", + "Reserve R"#i#", making it " + "unavailable as a GPR">; def FeatureNoMovt : SubtargetFeature<"no-movt", "NoMovt", "true", "Don't use movt/movw pairs for " diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index ed0969fa625..10153dd2e39 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -752,7 +752,7 @@ void ARMAsmPrinter::emitAttributes() { if (STI.isRWPI()) ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9IsSB); - else if (STI.isR9Reserved()) + else if (STI.isGPRegisterReserved(9)) ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9Reserved); else diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 4ace52b32e9..afcdb648cbc 100644 --- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -198,9 +198,11 @@ getReservedRegs(const MachineFunction &MF) const { markSuperRegs(Reserved, getFramePointerReg(STI)); if (hasBasePointer(MF)) markSuperRegs(Reserved, BasePtr); - // Some targets reserve R9. - if (STI.isR9Reserved()) - markSuperRegs(Reserved, ARM::R9); + for (size_t R = 0; R < ARM::GPRRegClass.getNumRegs(); ++R) { + if (STI.isGPRegisterReserved(R)) { + markSuperRegs(Reserved, ARM::R0 + R); + } + } // Reserve D16-D31 if the subtarget doesn't support them. if (!STI.hasD32()) { static_assert(ARM::D31 == ARM::D16 + 15, "Register list not consecutive!"); @@ -280,7 +282,7 @@ ARMBaseRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, case ARM::GPRRegClassID: { bool HasFP = MF.getFrameInfo().isMaxCallFrameSizeComputed() ? TFI->hasFP(MF) : true; - return 10 - HasFP - (STI.isR9Reserved() ? 1 : 0); + return 10 - HasFP - STI.getNumGPRegistersReserved(); } case ARM::SPRRegClassID: // Currently not used as 'rep' register class. case ARM::DPRRegClassID: @@ -380,6 +382,11 @@ bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); const ARMFrameLowering *TFI = getFrameLowering(MF); + const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); + + // Disable base pointer R6 if -ffixed-r6 is used. + if (STI.isGPRegisterReserved(BasePtr - ARM::R0)) + return false; // If we have stack realignment and VLAs, we have no pointer to use to // access the stack. If we have stack realignment, and a large call frame, @@ -416,6 +423,7 @@ bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const { bool ARMBaseRegisterInfo::canRealignStack(const MachineFunction &MF) const { const MachineRegisterInfo *MRI = &MF.getRegInfo(); const ARMFrameLowering *TFI = getFrameLowering(MF); + const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); // We can't realign the stack if: // 1. Dynamic stack realignment is explicitly disabled, // 2. There are VLAs in the function and the base pointer is disabled. @@ -425,6 +433,9 @@ bool ARMBaseRegisterInfo::canRealignStack(const MachineFunction &MF) const { // register allocation with frame pointer elimination, it is too late now. if (!MRI->canReserveReg(getFramePointerReg(MF.getSubtarget<ARMSubtarget>()))) return false; + // Disable base pointer R6 if -ffixed-r6 is used. + if (STI.isGPRegisterReserved(BasePtr - ARM::R0)) + return false; // We may also need a base pointer if there are dynamic allocas or stack // pointer adjustments around calls. if (TFI->hasReservedCallFrame(MF)) diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp index 5428bd6c94b..106894e28f0 100644 --- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp +++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp @@ -1704,6 +1704,19 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF, const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF); for (unsigned i = 0; CSRegs[i]; ++i) { unsigned Reg = CSRegs[i]; + if (STI.isRWPI() && Reg == ARM::R9) { + // Paranoid check for use of R9 with RWPI. Clobbering R9 with -frwpi will + // emit warnings about undefined behaviour but maybe theres's a valid use + // case so on that basis allow it to be pushed/popped in the + // prologue/epilogue. + } else if (Reg > ARM::R0 && ARM::GPRRegClass.contains(Reg) && + STI.isGPRegisterReserved(Reg - ARM::R0)) { + LLVM_DEBUG(dbgs() << printReg(Reg, TRI) << " has been reserved and" + << " should not be allocatable" + << " or spillable.\n"); + SavedRegs.reset(Reg); + continue; + } bool Spilled = false; if (SavedRegs.test(Reg)) { Spilled = true; @@ -1948,7 +1961,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF, LLVM_DEBUG(dbgs() << printReg(Reg, TRI) << " is saved low register, RegDeficit = " << RegDeficit << "\n"); - } else { + } else if (!STI.isGPRegisterReserved(Reg - ARM::R0)) { AvailableRegs.push_back(Reg); LLVM_DEBUG( dbgs() @@ -1963,7 +1976,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF, --RegDeficit; LLVM_DEBUG(dbgs() << "%r7 is saved low register, RegDeficit = " << RegDeficit << "\n"); - } else { + } else if (!STI.isGPRegisterReserved(7)) { AvailableRegs.push_back(ARM::R7); LLVM_DEBUG( dbgs() diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index c395a4feea7..b1d1d4fd5fc 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -5572,9 +5572,15 @@ SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { Register ARMTargetLowering::getRegisterByName(const char* RegName, EVT VT, const MachineFunction &MF) const { Register Reg = StringSwitch<unsigned>(RegName) - .Case("sp", ARM::SP) - .Default(0); - if (Reg) + .Case("r6", ARM::R6) + .Case("r7", ARM::R7) + .Case("r8", ARM::R8) + .Case("r9", ARM::R9) + .Case("r10", ARM::R10) + .Case("r11", ARM::R11) + .Case("sp", ARM::SP) + .Default(ARM::NoRegister); + if (Reg != ARM::NoRegister) return Reg; report_fatal_error(Twine("Invalid register name \"" + StringRef(RegName) + "\".")); diff --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp index eb4d39b01cb..7a57376a689 100644 --- a/llvm/lib/Target/ARM/ARMSubtarget.cpp +++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp @@ -98,8 +98,9 @@ ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU, const ARMBaseTargetMachine &TM, bool IsLittle, bool MinSize) : ARMGenSubtargetInfo(TT, CPU, FS), UseMulOps(UseFusedMulOps), - CPUString(CPU), OptMinSize(MinSize), IsLittle(IsLittle), - TargetTriple(TT), Options(TM.Options), TM(TM), + ReservedGPRegisters(ARM::GPRRegClass.getNumRegs()), CPUString(CPU), + OptMinSize(MinSize), IsLittle(IsLittle), TargetTriple(TT), + Options(TM.Options), TM(TM), FrameLowering(initializeFrameLowering(CPU, FS)), // At this point initializeSubtargetDependencies has been called so // we can query directly. @@ -253,8 +254,18 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { (Options.UnsafeFPMath || isTargetDarwin())) UseNEONForSinglePrecisionFP = true; - if (isRWPI()) - ReserveR9 = true; + if (isRWPI() || (isTargetMachO() && !HasV6Ops)) + ReservedGPRegisters.set(9); + + // Throw an error when trying to reserve a target's FP register. It may + // be used by the compiler even when frame pointer elimination is enabled. + // FIXME: Throw this error if -frame-pointer=none is not set; otherwise + // only emit a warning. + const int restFP = (useR7AsFramePointer()) ? 7 : 11; + if (isGPRegisterReserved(restFP)) + report_fatal_error( + "Register r" + std::to_string(restFP) + + " has been specified but is used as the frame pointer for this target."); // If MVEVectorCostFactor is still 0 (has not been set to anything else), default it to 2 if (MVEVectorCostFactor == 0) diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h index f582a92f656..c5836a3eca7 100644 --- a/llvm/lib/Target/ARM/ARMSubtarget.h +++ b/llvm/lib/Target/ARM/ARMSubtarget.h @@ -229,8 +229,8 @@ protected: /// NoARM - True if subtarget does not support ARM mode execution. bool NoARM = false; - /// ReserveR9 - True if R9 is not available as a general purpose register. - bool ReserveR9 = false; + // ReservedGPRegisters[i] - R#i is not available as a general purpose register + BitVector ReservedGPRegisters; /// NoMovt - True if MOVT / MOVW pairs are not used for materialization of /// 32-bit imms (including global addresses). @@ -763,8 +763,9 @@ public: bool isAClass() const { return ARMProcClass == AClass; } bool isReadTPHard() const { return ReadTPHard; } - bool isR9Reserved() const { - return isTargetMachO() ? (ReserveR9 || !HasV6Ops) : ReserveR9; + bool isGPRegisterReserved(size_t i) const { return ReservedGPRegisters[i]; } + unsigned getNumGPRegistersReserved() const { + return ReservedGPRegisters.count(); } bool useR7AsFramePointer() const { diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h index 5bb3bcaf10e..c1fd01d2df9 100644 --- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h +++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h @@ -76,7 +76,9 @@ class ARMTTIImpl : public BasicTTIImplBase<ARMTTIImpl> { ARM::FeatureDSP, ARM::FeatureMP, ARM::FeatureVirtualization, ARM::FeatureMClass, ARM::FeatureRClass, ARM::FeatureAClass, ARM::FeatureNaClTrap, ARM::FeatureStrictAlign, ARM::FeatureLongCalls, - ARM::FeatureExecuteOnly, ARM::FeatureReserveR9, ARM::FeatureNoMovt, + ARM::FeatureExecuteOnly, ARM::FeatureReserveR6, ARM::FeatureReserveR7, + ARM::FeatureReserveR8, ARM::FeatureReserveR9, ARM::FeatureReserveR10, + ARM::FeatureReserveR11, ARM::FeatureNoMovt, ARM::FeatureNoNegativeImmediates }; diff --git a/llvm/test/CodeGen/ARM/reg-alloc-fixed-r6-vla.ll b/llvm/test/CodeGen/ARM/reg-alloc-fixed-r6-vla.ll new file mode 100644 index 00000000000..0b6fd7443af --- /dev/null +++ b/llvm/test/CodeGen/ARM/reg-alloc-fixed-r6-vla.ll @@ -0,0 +1,44 @@ +; Using VLAs(Variable Length Arrays) in a function will use R6 to keep track +; of the stack frame, and also spill/restore R6 to the stack. +; This tests that using -ffixed-r6 (-mattr=+reserve-r6) will stop R6 +; being used and also stop it being spilled/restored to the stack. +; RUN: llc < %s -mcpu=cortex-m0 -mtriple=thumbv7-arm-none-eabi | FileCheck %s --check-prefix=CHECK-STATIC --check-prefix=CHECK-R6 +; RUN: llc < %s -mcpu=cortex-m0 -mtriple=thumbv7-arm-none-eabi -mattr=+reserve-r6 | FileCheck %s --check-prefix=CHECK-STATIC --check-prefix=CHECK-NO-R6 + +define void @f() #0 { +entry: + %i = alloca i32, align 4 + store i32 0, i32* %i, align 4 + + %saved_stack = alloca i8*, align 4 + %0 = call i8* @llvm.stacksave() + store i8* %0, i8** %saved_stack, align 4 + + %__vla_expr0 = alloca i32, align 4 + %1 = load i32, i32* %i, align 4 + %vla = alloca double, i32 %1, align 8 + store i32 %1, i32* %__vla_expr0, align 4 + + %2 = load i8*, i8** %saved_stack, align 4 + call void @llvm.stackrestore(i8* %2) + + ret void +} + +declare i8* @llvm.stacksave() #1 +declare void @llvm.stackrestore(i8* %ptr) #1 + +attributes #0 = { noinline nounwind "stackrealign" } +attributes #1 = { nounwind } + +; CHECK-STATIC: push {r4, +; CHECK-R6: r6 +; CHECK-NO-R6-NOT: r6 +; CHECK-STATIC: lr} +; CHECK-R6: r6 +; CHECK-NO-R6-NOT: r6 +; CHECK-STATIC: pop {r4, +; CHECK-R6: r6 +; CHECK-NO-R6-NOT: r6 +; CHECK-STATIC: pc} + diff --git a/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6-modified.ll b/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6-modified.ll new file mode 100644 index 00000000000..e2a4af87dde --- /dev/null +++ b/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6-modified.ll @@ -0,0 +1,63 @@ +; RUN: llc < %s -mattr=+reserve-r6 -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; +; Equivalent C source code +; register unsigned r6 asm("r6"); +; void bar(unsigned int i, +; unsigned int j, +; unsigned int k, +; unsigned int l, +; unsigned int m, +; unsigned int n, +; unsigned int o, +; unsigned int p) +; { +; r6 = 10; +; unsigned int result = i + j + k + l + m + n + o + p; +; } +declare void @llvm.write_register.i32(metadata, i32) nounwind + +define void @bar(i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p) nounwind { +entry: +; CHECK-NOT: push {{{.*}}r6,{{.*}}} +; CHECK: {{.*}}mov{{.*}}r6,{{.*}} +; CHECK-NOT: {{.*}}r6{{.*}} + %i.addr = alloca i32, align 4 + %j.addr = alloca i32, align 4 + %k.addr = alloca i32, align 4 + %l.addr = alloca i32, align 4 + %m.addr = alloca i32, align 4 + %n.addr = alloca i32, align 4 + %o.addr = alloca i32, align 4 + %p.addr = alloca i32, align 4 + %result = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + store i32 %j, i32* %j.addr, align 4 + store i32 %k, i32* %k.addr, align 4 + store i32 %l, i32* %l.addr, align 4 + store i32 %m, i32* %m.addr, align 4 + store i32 %n, i32* %n.addr, align 4 + store i32 %o, i32* %o.addr, align 4 + store i32 %p, i32* %p.addr, align 4 + call void @llvm.write_register.i32(metadata !0, i32 10) + %0 = load i32, i32* %i.addr, align 4 + %1 = load i32, i32* %j.addr, align 4 + %add = add i32 %0, %1 + %2 = load i32, i32* %k.addr, align 4 + %add1 = add i32 %add, %2 + %3 = load i32, i32* %l.addr, align 4 + %add2 = add i32 %add1, %3 + %4 = load i32, i32* %m.addr, align 4 + %add3 = add i32 %add2, %4 + %5 = load i32, i32* %n.addr, align 4 + %add4 = add i32 %add3, %5 + %6 = load i32, i32* %o.addr, align 4 + %add5 = add i32 %add4, %6 + %7 = load i32, i32* %p.addr, align 4 + %add6 = add i32 %add5, %7 + store i32 %add6, i32* %result, align 4 + ret void +} + +!llvm.named.register.r6 = !{!0} +!0 = !{!"r6"} + diff --git a/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6.ll b/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6.ll new file mode 100644 index 00000000000..3647c0701a7 --- /dev/null +++ b/llvm/test/CodeGen/ARM/reg-alloc-with-fixed-reg-r6.ll @@ -0,0 +1,57 @@ +; RUN: llc < %s -mattr=+reserve-r6 -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; +; Equivalent C source code +; void bar(unsigned int i, +; unsigned int j, +; unsigned int k, +; unsigned int l, +; unsigned int m, +; unsigned int n, +; unsigned int o, +; unsigned int p) +; { +; unsigned int result = i + j + k + l + m + n + o + p; +; } + +define void @bar(i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p) nounwind { +entry: +; CHECK-NOT: push {{{.*}}r6,{{.*}}} + %i.addr = alloca i32, align 4 + %j.addr = alloca i32, align 4 + %k.addr = alloca i32, align 4 + %l.addr = alloca i32, align 4 + %m.addr = alloca i32, align 4 + %n.addr = alloca i32, align 4 + %o.addr = alloca i32, align 4 + %p.addr = alloca i32, align 4 + %result = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + store i32 %j, i32* %j.addr, align 4 + store i32 %k, i32* %k.addr, align 4 + store i32 %l, i32* %l.addr, align 4 + store i32 %m, i32* %m.addr, align 4 + store i32 %n, i32* %n.addr, align 4 + store i32 %o, i32* %o.addr, align 4 + store i32 %p, i32* %p.addr, align 4 + %0 = load i32, i32* %i.addr, align 4 + %1 = load i32, i32* %j.addr, align 4 + %add = add i32 %0, %1 + %2 = load i32, i32* %k.addr, align 4 + %add1 = add i32 %add, %2 + %3 = load i32, i32* %l.addr, align 4 + %add2 = add i32 %add1, %3 + %4 = load i32, i32* %m.addr, align 4 + %add3 = add i32 %add2, %4 + %5 = load i32, i32* %n.addr, align 4 + %add4 = add i32 %add3, %5 + %6 = load i32, i32* %o.addr, align 4 + %add5 = add i32 %add4, %6 + %7 = load i32, i32* %p.addr, align 4 + %add6 = add i32 %add5, %7 + store i32 %add6, i32* %result, align 4 +; CHECK: {{.*}}r5{{.*}} +; CHECK-NOT: {{.*}}r6{{.*}} + ret void +; CHECK-NOT: pop {{{.*}}r6,{{.*}}} +} + diff --git a/llvm/test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll b/llvm/test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll new file mode 100644 index 00000000000..d1f020936a3 --- /dev/null +++ b/llvm/test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll @@ -0,0 +1,58 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; +; Equivalent C source code +; void bar(unsigned int i, +; unsigned int j, +; unsigned int k, +; unsigned int l, +; unsigned int m, +; unsigned int n, +; unsigned int o, +; unsigned int p) +; { +; unsigned int result = i + j + k + l + m + n + o + p; +; } + +define void @bar(i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p) nounwind { +entry: +; CHECK: push {{{.*}}r4, r5{{.*}}} + %i.addr = alloca i32, align 4 + %j.addr = alloca i32, align 4 + %k.addr = alloca i32, align 4 + %l.addr = alloca i32, align 4 + %m.addr = alloca i32, align 4 + %n.addr = alloca i32, align 4 + %o.addr = alloca i32, align 4 + %p.addr = alloca i32, align 4 + %result = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + store i32 %j, i32* %j.addr, align 4 + store i32 %k, i32* %k.addr, align 4 + store i32 %l, i32* %l.addr, align 4 + store i32 %m, i32* %m.addr, align 4 + store i32 %n, i32* %n.addr, align 4 + store i32 %o, i32* %o.addr, align 4 + store i32 %p, i32* %p.addr, align 4 + %0 = load i32, i32* %i.addr, align 4 + %1 = load i32, i32* %j.addr, align 4 + %add = add i32 %0, %1 + %2 = load i32, i32* %k.addr, align 4 + %add1 = add i32 %add, %2 + %3 = load i32, i32* %l.addr, align 4 + %add2 = add i32 %add1, %3 + %4 = load i32, i32* %m.addr, align 4 + %add3 = add i32 %add2, %4 + %5 = load i32, i32* %n.addr, align 4 + %add4 = add i32 %add3, %5 + %6 = load i32, i32* %o.addr, align 4 + %add5 = add i32 %add4, %6 + %7 = load i32, i32* %p.addr, align 4 + %add6 = add i32 %add5, %7 + store i32 %add6, i32* %result, align 4 +; CHECK: {{.*}}r4{{.*}} +; CHECK: {{.*}}r5{{.*}} + +; CHECK: pop {{{.*}}r4, r5{{.*}}} + ret void +} + diff --git a/llvm/test/CodeGen/Thumb/callee_save_reserved.ll b/llvm/test/CodeGen/Thumb/callee_save_reserved.ll new file mode 100644 index 00000000000..0329d7886a2 --- /dev/null +++ b/llvm/test/CodeGen/Thumb/callee_save_reserved.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s -mtriple=thumbv6m-none-eabi -verify-machineinstrs -frame-pointer=none -mattr=+reserve-r6,+reserve-r8 \ +; RUN: -asm-verbose=false | FileCheck --check-prefix=CHECK-INVALID %s + +; Reserved low registers should not be used to correct reg deficit. +define <4 x i32> @four_high_four_return_reserved() { +entry: + ; CHECK-INVALID-NOT: r{{6|8}} + tail call void asm sideeffect "", "~{r8},~{r9}"() + %vecinit = insertelement <4 x i32> undef, i32 1, i32 0 + %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1 + %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2 + %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3 + ret <4 x i32> %vecinit13 +} + diff --git a/llvm/test/Feature/reserve_global_reg.ll b/llvm/test/Feature/reserve_global_reg.ll new file mode 100644 index 00000000000..06081cae1fb --- /dev/null +++ b/llvm/test/Feature/reserve_global_reg.ll @@ -0,0 +1,29 @@ +; RUN: not llc < %s -mtriple=thumbv7-apple-darwin -mattr=+reserve-r7 -o - 2>&1 | FileCheck -check-prefix=CHECK-RESERVE-FP7 %s +; RUN: not llc < %s -mtriple=armv7-windows-msvc -mattr=+reserve-r11 -o - 2>&1 | FileCheck -check-prefix=CHECK-RESERVE-FP11 %s +; RUN: not llc < %s -mtriple=thumbv7-windows -mattr=+reserve-r11 -o - 2>&1 | FileCheck -check-prefix=CHECK-RESERVE-FP11-2 %s + +; int test(int a, int b, int c) { +; return a + b + c; +; } + +; Function Attrs: noinline nounwind optnone +define hidden i32 @_Z4testiii(i32 %a, i32 %b, i32 %c) #0 { +entry: + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + %c.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + store i32 %c, i32* %c.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %1 = load i32, i32* %b.addr, align 4 + %add = add nsw i32 %0, %1 + %2 = load i32, i32* %c.addr, align 4 + %add1 = add nsw i32 %add, %2 + ret i32 %add1 +} + +; CHECK-RESERVE-FP7: Register r7 has been specified but is used as the frame pointer for this target. +; CHECK-RESERVE-FP11: Register r11 has been specified but is used as the frame pointer for this target. +; CHECK-RESERVE-FP11-2: Register r11 has been specified but is used as the frame pointer for this target. + |