Index: lib/Target/ARM/ARMBaseRegisterInfo.h =================================================================== --- lib/Target/ARM/ARMBaseRegisterInfo.h +++ lib/Target/ARM/ARMBaseRegisterInfo.h @@ -156,6 +156,7 @@ const uint32_t *getThisReturnPreservedMask(const MachineFunction &MF, CallingConv::ID) const; + unsigned mapToValidGlobalRegister(StringRef RegName) const; BitVector getReservedRegs(const MachineFunction &MF) const override; bool isAsmClobberable(const MachineFunction &MF, unsigned PhysReg) const override; Index: lib/Target/ARM/ARMBaseRegisterInfo.cpp =================================================================== --- lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -179,6 +180,22 @@ : CSR_AAPCS_ThisReturn_RegMask; } +unsigned ARMBaseRegisterInfo:: +mapToValidGlobalRegister(StringRef RegName) const { + unsigned Reg = StringSwitch(RegName) + .Case("r4", ARM::R4) + .Case("r5", ARM::R5) + .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); + return Reg; +} + BitVector ARMBaseRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { const ARMSubtarget &STI = MF.getSubtarget(); @@ -211,6 +228,21 @@ if (Reserved.test(*SI)) markSuperRegs(Reserved, Reg); + SmallVector ModuleFlags; + MF.getFunction().getParent()->getModuleFlagsMetadata(ModuleFlags); + for (const Module::ModuleFlagEntry &MFE : ModuleFlags) { + if (MFE.Key->getString().startswith("fixed_reg.")) + if (isa(MFE.Val)){ + const auto *VD = cast(MFE.Val); + StringRef RegName = VD->getString(); + unsigned Reg = mapToValidGlobalRegister(RegName); + if (Reg == ARM::NoRegister) + report_fatal_error( + Twine("Invalid register name \"" + StringRef(RegName) + "\".")); + markSuperRegs(Reserved, Reg); + } + } + assert(checkAllSuperRegsMarked(Reserved)); return Reserved; } Index: lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- lib/Target/ARM/ARMFrameLowering.cpp +++ lib/Target/ARM/ARMFrameLowering.cpp @@ -2093,6 +2093,21 @@ } } + SmallVector ModuleFlags; + MF.getFunction().getParent()->getModuleFlagsMetadata(ModuleFlags); + for (const Module::ModuleFlagEntry &MFE : ModuleFlags) { + if (MFE.Key->getString().startswith("fixed_reg.")) + if (isa(MFE.Val)){ + const auto *VD = cast(MFE.Val); + StringRef RegName = VD->getString(); + unsigned Reg = RegInfo->mapToValidGlobalRegister(RegName); + if (Reg == ARM::NoRegister) + report_fatal_error( + Twine("Invalid register name \"" + StringRef(RegName) + "\".")); + SavedRegs.reset(Reg); + } + } + if (ForceLRSpill) { SavedRegs.set(ARM::LR); AFI->setLRIsSpilledForFarJump(true); Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -5240,13 +5240,13 @@ // this table could be generated automatically from RegInfo. unsigned ARMTargetLowering::getRegisterByName(const char* RegName, EVT VT, SelectionDAG &DAG) const { - unsigned Reg = StringSwitch(RegName) - .Case("sp", ARM::SP) - .Default(0); - if (Reg) - return Reg; - report_fatal_error(Twine("Invalid register name \"" - + StringRef(RegName) + "\".")); + const ARMBaseRegisterInfo &ARI = + *static_cast(RegInfo); + unsigned Reg = ARI.mapToValidGlobalRegister(RegName); + if (Reg == ARM::NoRegister) + report_fatal_error(Twine("Invalid register name \"" + + StringRef(RegName) + "\".")); + return Reg; } // Result is 64 bit value so split into two 32 bit values and return as a Index: test/CodeGen/ARM/named-reg-alloc-r5.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/named-reg-alloc-r5.ll @@ -0,0 +1,13 @@ +; RUN: llc < %s -mtriple=arm-apple-darwin 2>&1 | FileCheck %s +; RUN: llc < %s -mtriple=arm-linux-gnueabi 2>&1 | FileCheck %s + +define i32 @get_stack() nounwind { +entry: +; CHECK-NOT: Invalid register name "r5". + %sp = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %sp +} + +declare i32 @llvm.read_register.i32(metadata) nounwind + +!0 = !{!"r5\00"} Index: test/CodeGen/ARM/named-reg-alloc.ll =================================================================== --- test/CodeGen/ARM/named-reg-alloc.ll +++ test/CodeGen/ARM/named-reg-alloc.ll @@ -4,11 +4,11 @@ define i32 @get_stack() nounwind { entry: ; FIXME: Include an allocatable-specific error message -; CHECK: Invalid register name "r5". - %sp = call i32 @llvm.read_register.i32(metadata !0) +; CHECK: Invalid register name "r3". + %sp = call i32 @llvm.read_register.i32(metadata !0) ret i32 %sp } declare i32 @llvm.read_register.i32(metadata) nounwind -!0 = !{!"r5\00"} +!0 = !{!"r3\00"} Index: test/CodeGen/ARM/reg-alloc-with-fixed-reg-r4-r5.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/reg-alloc-with-fixed-reg-r4-r5.ll @@ -0,0 +1,62 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; Compile Command: +; bin/llc -mtriple=arm-arm-none-eabi -mcpu=cortex-m4 -O0 -filetype=asm --regalloc=fast %s -o - +; +; 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 {{{.*}}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-NOT: {{.*}}r4{{.*}} +; CHECK-NOT: {{.*}}r5{{.*}} + ret void +; CHECK-NOT: pop {{{.*}}r4, r5{{.*}}} +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"fixed_reg.foo1", !"r4"} +!1 = !{i32 1, !"fixed_reg.foo2", !"r5"} Index: test/CodeGen/ARM/reg-alloc-with-fixed-reg-r4.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/reg-alloc-with-fixed-reg-r4.ll @@ -0,0 +1,61 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; Compile Command: +; bin/llc -mtriple=arm-arm-none-eabi -mcpu=cortex-m4 -O0 -filetype=asm --regalloc=fast %s -o - +; +; 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 {{{.*}}r4,{{.*}}} + %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-NOT: {{.*}}r4{{.*}} +; CHECK: {{.*}}r5{{.*}} + ret void +; CHECK-NOT: pop {{{.*}}r4,{{.*}}} +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"fixed_reg.foo", !"r4"} Index: test/CodeGen/ARM/reg-alloc-with-fixed-reg-r5.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/reg-alloc-with-fixed-reg-r5.ll @@ -0,0 +1,61 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; Compile Command: +; bin/llc -mtriple=arm-arm-none-eabi -mcpu=cortex-m4 -O0 -filetype=asm --regalloc=fast %s -o - +; +; 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 {{{.*}}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-NOT: {{.*}}r5{{.*}} + ret void +; CHECK-NOT: pop {{{.*}}r5,{{.*}}} +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"fixed_reg.foo", !"r5"} Index: test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/reg-alloc-wout-fixed-regs.ll @@ -0,0 +1,59 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 -filetype=asm --regalloc=fast 2>&1 | FileCheck %s +; Compile Command: +; bin/llc -mtriple=arm-arm-none-eabi -mcpu=cortex-m4 -O0 -filetype=asm --regalloc=fast %s -o - +; +; 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 +} \ No newline at end of file