https://github.com/koachan created https://github.com/llvm/llvm-project/pull/74927
This adds support for marking arbitrary general purpose registers - except for those with special purpose (G0, I6-I7, O6-O7) - as reserved, as needed by some software like the Linux kernel. >From 956ca7e210a438caac7c5dda8c9945305a53de39 Mon Sep 17 00:00:00 2001 From: Koakuma <koac...@protonmail.com> Date: Wed, 29 Nov 2023 08:08:29 +0700 Subject: [PATCH] [SPARC] Support reserving arbitrary general purpose registers This adds support for marking arbitrary general purpose registers - except for those with special purpose (G0, I6-I7, O6-O7) - as reserved, as needed by some software like the Linux kernel. --- clang/include/clang/Driver/Options.td | 12 ++ clang/lib/Driver/ToolChains/Arch/Sparc.cpp | 81 +++++++++ clang/test/Driver/sparc-fixed-register.c | 181 +++++++++++++++++++ llvm/lib/Target/Sparc/Sparc.td | 14 ++ llvm/lib/Target/Sparc/SparcISelLowering.cpp | 23 +++ llvm/lib/Target/Sparc/SparcRegisterInfo.cpp | 45 ++++- llvm/lib/Target/Sparc/SparcRegisterInfo.h | 3 + llvm/lib/Target/Sparc/SparcRegisterInfo.td | 4 + llvm/lib/Target/Sparc/SparcSubtarget.cpp | 6 +- llvm/lib/Target/Sparc/SparcSubtarget.h | 11 ++ llvm/test/CodeGen/SPARC/reserved-arg-regs.ll | 25 +++ llvm/test/CodeGen/SPARC/reserved-regs.ll | 17 ++ 12 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 clang/test/Driver/sparc-fixed-register.c create mode 100644 llvm/test/CodeGen/SPARC/reserved-arg-regs.ll diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index df12ba8fbcb296..94bdeff28d0146 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5730,6 +5730,18 @@ def mvis3 : Flag<["-"], "mvis3">, Group<m_sparc_Features_Group>; def mno_vis3 : Flag<["-"], "mno-vis3">, Group<m_sparc_Features_Group>; def mhard_quad_float : Flag<["-"], "mhard-quad-float">, Group<m_sparc_Features_Group>; def msoft_quad_float : Flag<["-"], "msoft-quad-float">, Group<m_sparc_Features_Group>; +foreach i = {1-7} in + def ffixed_g#i : Flag<["-"], "ffixed-g"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the G"#i#" register (SPARC only)">; +foreach i = {0-5} in + def ffixed_o#i : Flag<["-"], "ffixed-o"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the O"#i#" register (SPARC only)">; +foreach i = {0-7} in + def ffixed_l#i : Flag<["-"], "ffixed-l"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the L"#i#" register (SPARC only)">; +foreach i = {0-5} in + def ffixed_i#i : Flag<["-"], "ffixed-i"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the I"#i#" register (SPARC only)">; } // let Flags = [TargetSpecific] // M68k features flags diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp index 22e583021515e5..ae1a4ba7882627 100644 --- a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -178,4 +178,85 @@ void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args, else Features.push_back("-hard-quad-float"); } + + if (Args.hasArg(options::OPT_ffixed_g1)) + Features.push_back("+reserve-g1"); + + if (Args.hasArg(options::OPT_ffixed_g2)) + Features.push_back("+reserve-g2"); + + if (Args.hasArg(options::OPT_ffixed_g3)) + Features.push_back("+reserve-g3"); + + if (Args.hasArg(options::OPT_ffixed_g4)) + Features.push_back("+reserve-g4"); + + if (Args.hasArg(options::OPT_ffixed_g5)) + Features.push_back("+reserve-g5"); + + if (Args.hasArg(options::OPT_ffixed_g6)) + Features.push_back("+reserve-g6"); + + if (Args.hasArg(options::OPT_ffixed_g7)) + Features.push_back("+reserve-g7"); + + if (Args.hasArg(options::OPT_ffixed_o0)) + Features.push_back("+reserve-o0"); + + if (Args.hasArg(options::OPT_ffixed_o1)) + Features.push_back("+reserve-o1"); + + if (Args.hasArg(options::OPT_ffixed_o2)) + Features.push_back("+reserve-o2"); + + if (Args.hasArg(options::OPT_ffixed_o3)) + Features.push_back("+reserve-o3"); + + if (Args.hasArg(options::OPT_ffixed_o4)) + Features.push_back("+reserve-o4"); + + if (Args.hasArg(options::OPT_ffixed_o5)) + Features.push_back("+reserve-o5"); + + if (Args.hasArg(options::OPT_ffixed_l0)) + Features.push_back("+reserve-l0"); + + if (Args.hasArg(options::OPT_ffixed_l1)) + Features.push_back("+reserve-l1"); + + if (Args.hasArg(options::OPT_ffixed_l2)) + Features.push_back("+reserve-l2"); + + if (Args.hasArg(options::OPT_ffixed_l3)) + Features.push_back("+reserve-l3"); + + if (Args.hasArg(options::OPT_ffixed_l4)) + Features.push_back("+reserve-l4"); + + if (Args.hasArg(options::OPT_ffixed_l5)) + Features.push_back("+reserve-l5"); + + if (Args.hasArg(options::OPT_ffixed_l6)) + Features.push_back("+reserve-l6"); + + if (Args.hasArg(options::OPT_ffixed_l7)) + Features.push_back("+reserve-l7"); + + if (Args.hasArg(options::OPT_ffixed_i0)) + Features.push_back("+reserve-i0"); + + if (Args.hasArg(options::OPT_ffixed_i1)) + Features.push_back("+reserve-i1"); + + if (Args.hasArg(options::OPT_ffixed_i2)) + Features.push_back("+reserve-i2"); + + if (Args.hasArg(options::OPT_ffixed_i3)) + Features.push_back("+reserve-i3"); + + if (Args.hasArg(options::OPT_ffixed_i4)) + Features.push_back("+reserve-i4"); + + if (Args.hasArg(options::OPT_ffixed_i5)) + Features.push_back("+reserve-i5"); } diff --git a/clang/test/Driver/sparc-fixed-register.c b/clang/test/Driver/sparc-fixed-register.c new file mode 100644 index 00000000000000..24880b9c9d86fd --- /dev/null +++ b/clang/test/Driver/sparc-fixed-register.c @@ -0,0 +1,181 @@ +// RUN: %clang --target=sparc-none-gnu -ffixed-g1 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G1 < %t %s +// CHECK-FIXED-G1: "-target-feature" "+reserve-g1" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g2 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G2 < %t %s +// CHECK-FIXED-G2: "-target-feature" "+reserve-g2" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g3 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G3 < %t %s +// CHECK-FIXED-G3: "-target-feature" "+reserve-g3" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g4 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G4 < %t %s +// CHECK-FIXED-G4: "-target-feature" "+reserve-g4" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g5 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G5 < %t %s +// CHECK-FIXED-G5: "-target-feature" "+reserve-g5" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g6 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G6 < %t %s +// CHECK-FIXED-G6: "-target-feature" "+reserve-g6" + +// RUN: %clang --target=sparc-none-gnu -ffixed-g7 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-G7 < %t %s +// CHECK-FIXED-G7: "-target-feature" "+reserve-g7" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o0 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O0 < %t %s +// CHECK-FIXED-O0: "-target-feature" "+reserve-o0" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o1 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O1 < %t %s +// CHECK-FIXED-O1: "-target-feature" "+reserve-o1" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o2 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O2 < %t %s +// CHECK-FIXED-O2: "-target-feature" "+reserve-o2" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o3 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O3 < %t %s +// CHECK-FIXED-O3: "-target-feature" "+reserve-o3" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o4 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O4 < %t %s +// CHECK-FIXED-O4: "-target-feature" "+reserve-o4" + +// RUN: %clang --target=sparc-none-gnu -ffixed-o5 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-O5 < %t %s +// CHECK-FIXED-O5: "-target-feature" "+reserve-o5" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l0 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L0 < %t %s +// CHECK-FIXED-L0: "-target-feature" "+reserve-l0" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l1 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L1 < %t %s +// CHECK-FIXED-L1: "-target-feature" "+reserve-l1" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l2 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L2 < %t %s +// CHECK-FIXED-L2: "-target-feature" "+reserve-l2" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l3 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L3 < %t %s +// CHECK-FIXED-L3: "-target-feature" "+reserve-l3" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l4 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L4 < %t %s +// CHECK-FIXED-L4: "-target-feature" "+reserve-l4" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l5 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L5 < %t %s +// CHECK-FIXED-L5: "-target-feature" "+reserve-l5" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l6 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L6 < %t %s +// CHECK-FIXED-L6: "-target-feature" "+reserve-l6" + +// RUN: %clang --target=sparc-none-gnu -ffixed-l7 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-L7 < %t %s +// CHECK-FIXED-L7: "-target-feature" "+reserve-l7" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i0 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I0 < %t %s +// CHECK-FIXED-I0: "-target-feature" "+reserve-i0" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i1 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I1 < %t %s +// CHECK-FIXED-I1: "-target-feature" "+reserve-i1" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i2 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I2 < %t %s +// CHECK-FIXED-I2: "-target-feature" "+reserve-i2" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i3 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I3 < %t %s +// CHECK-FIXED-I3: "-target-feature" "+reserve-i3" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i4 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I4 < %t %s +// CHECK-FIXED-I4: "-target-feature" "+reserve-i4" + +// RUN: %clang --target=sparc-none-gnu -ffixed-i5 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-I5 < %t %s +// CHECK-FIXED-I5: "-target-feature" "+reserve-i5" + +// Test multiple of reserve-* options together. +// RUN: %clang --target=sparc-none-gnu \ +// RUN: -ffixed-g1 \ +// RUN: -ffixed-o2 \ +// RUN: -ffixed-l3 \ +// RUN: -ffixed-i4 \ +// RUN: -### %s 2> %t +// RUN: FileCheck \ +// RUN: --check-prefix=CHECK-FIXED-G1 \ +// RUN: --check-prefix=CHECK-FIXED-O2 \ +// RUN: --check-prefix=CHECK-FIXED-L3 \ +// RUN: --check-prefix=CHECK-FIXED-I4 \ +// RUN: < %t %s + +// Test all reserve-* options together. +// RUN: %clang --target=sparc-none-gnu \ +// RUN: -ffixed-g1 \ +// RUN: -ffixed-g2 \ +// RUN: -ffixed-g3 \ +// RUN: -ffixed-g4 \ +// RUN: -ffixed-g5 \ +// RUN: -ffixed-g6 \ +// RUN: -ffixed-g7 \ +// RUN: -ffixed-o0 \ +// RUN: -ffixed-o1 \ +// RUN: -ffixed-o2 \ +// RUN: -ffixed-o3 \ +// RUN: -ffixed-o4 \ +// RUN: -ffixed-o5 \ +// RUN: -ffixed-l0 \ +// RUN: -ffixed-l1 \ +// RUN: -ffixed-l2 \ +// RUN: -ffixed-l3 \ +// RUN: -ffixed-l4 \ +// RUN: -ffixed-l5 \ +// RUN: -ffixed-l6 \ +// RUN: -ffixed-l7 \ +// RUN: -ffixed-i0 \ +// RUN: -ffixed-i1 \ +// RUN: -ffixed-i2 \ +// RUN: -ffixed-i3 \ +// RUN: -ffixed-i4 \ +// RUN: -ffixed-i5 \ +// RUN: -### %s 2> %t +// RUN: FileCheck \ +// RUN: --check-prefix=CHECK-FIXED-G1 \ +// RUN: --check-prefix=CHECK-FIXED-G2 \ +// RUN: --check-prefix=CHECK-FIXED-G3 \ +// RUN: --check-prefix=CHECK-FIXED-G4 \ +// RUN: --check-prefix=CHECK-FIXED-G5 \ +// RUN: --check-prefix=CHECK-FIXED-G6 \ +// RUN: --check-prefix=CHECK-FIXED-G7 \ +// RUN: --check-prefix=CHECK-FIXED-O0 \ +// RUN: --check-prefix=CHECK-FIXED-O1 \ +// RUN: --check-prefix=CHECK-FIXED-O2 \ +// RUN: --check-prefix=CHECK-FIXED-O3 \ +// RUN: --check-prefix=CHECK-FIXED-O4 \ +// RUN: --check-prefix=CHECK-FIXED-O5 \ +// RUN: --check-prefix=CHECK-FIXED-L0 \ +// RUN: --check-prefix=CHECK-FIXED-L1 \ +// RUN: --check-prefix=CHECK-FIXED-L2 \ +// RUN: --check-prefix=CHECK-FIXED-L3 \ +// RUN: --check-prefix=CHECK-FIXED-L4 \ +// RUN: --check-prefix=CHECK-FIXED-L5 \ +// RUN: --check-prefix=CHECK-FIXED-L6 \ +// RUN: --check-prefix=CHECK-FIXED-L7 \ +// RUN: --check-prefix=CHECK-FIXED-I0 \ +// RUN: --check-prefix=CHECK-FIXED-I1 \ +// RUN: --check-prefix=CHECK-FIXED-I2 \ +// RUN: --check-prefix=CHECK-FIXED-I3 \ +// RUN: --check-prefix=CHECK-FIXED-I4 \ +// RUN: --check-prefix=CHECK-FIXED-I5 \ +// RUN: < %t %s diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index 1a71cfed3128f0..29d07bd087e5ac 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -65,6 +65,20 @@ def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true", //==== Features added predmoninantly for LEON subtarget support include "LeonFeatures.td" +//==== Register allocation tweaks needed by some low-level software +foreach i = {1-7} in + def FeatureReserveG#i : SubtargetFeature<"reserve-g"#i, "ReserveGRegister["#i#"]", "true", + "Reserve G"#i#", making it unavailable as a GPR">; +foreach i = {0-5} in + def FeatureReserveO#i : SubtargetFeature<"reserve-o"#i, "ReserveORegister["#i#"]", "true", + "Reserve O"#i#", making it unavailable as a GPR">; +foreach i = {0-7} in + def FeatureReserveL#i : SubtargetFeature<"reserve-l"#i, "ReserveLRegister["#i#"]", "true", + "Reserve L"#i#", making it unavailable as a GPR">; +foreach i = {0-5} in + def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveIRegister["#i#"]", "true", + "Reserve I"#i#", making it unavailable as a GPR">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 4f080147921105..5a7830a1ecf61e 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -805,6 +805,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, bool &isTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool isVarArg = CLI.IsVarArg; + MachineFunction &MF = DAG.getMachineFunction(); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -1055,6 +1056,10 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, ((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CallConv) : TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv)); + + if (TRI->isAnyArgRegReserved(MF)) + TRI->emitReservedArgRegCallError(MF); + assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); @@ -1125,6 +1130,19 @@ Register SparcTargetLowering::getRegisterByName(const char* RegName, LLT VT, .Case("g4", SP::G4).Case("g5", SP::G5).Case("g6", SP::G6).Case("g7", SP::G7) .Default(0); + const SparcRegisterInfo *MRI = Subtarget->getRegisterInfo(); + unsigned DwarfRegNum = MRI->getDwarfRegNum(Reg, false); + if (!MRI->isReservedReg(MF, Reg)) { + bool IsG = DwarfRegNum < 8, IsO = DwarfRegNum >= 8 && DwarfRegNum < 16, + IsL = DwarfRegNum >= 16 && DwarfRegNum < 24, IsI = DwarfRegNum >= 24; + unsigned NumInBank = DwarfRegNum % 8; + if ((IsG && !Subtarget->isGRegisterReserved(NumInBank)) || + (IsO && !Subtarget->isORegisterReserved(NumInBank)) || + (IsL && !Subtarget->isLRegisterReserved(NumInBank)) || + (IsI && !Subtarget->isIRegisterReserved(NumInBank))) + Reg = 0; + } + if (Reg) return Reg; @@ -1189,6 +1207,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, SDLoc DL = CLI.DL; SDValue Chain = CLI.Chain; auto PtrVT = getPointerTy(DAG.getDataLayout()); + MachineFunction &MF = DAG.getMachineFunction(); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -1372,6 +1391,10 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, ((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CLI.CallConv) : TRI->getCallPreservedMask(DAG.getMachineFunction(), CLI.CallConv)); + + if (TRI->isAnyArgRegReserved(MF)) + TRI->emitReservedArgRegCallError(MF); + assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index f97bf57627d1aa..233f1dfd3ecf2b 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -12,7 +12,6 @@ #include "SparcRegisterInfo.h" #include "Sparc.h" -#include "SparcMachineFunctionInfo.h" #include "SparcSubtarget.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" @@ -20,6 +19,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -98,9 +98,52 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const { for (unsigned n = 0; n < 31; n++) Reserved.set(SP::ASR1 + n); + for (size_t i = 0; i < SP::IntRegsRegClass.getNumRegs() / 4; ++i) { + // Mark both single register and register pairs. + if (MF.getSubtarget<SparcSubtarget>().isGRegisterReserved(i)) { + Reserved.set(SP::G0 + i); + Reserved.set(SP::G0_G1 + i / 2); + } + if (MF.getSubtarget<SparcSubtarget>().isORegisterReserved(i)) { + Reserved.set(SP::O0 + i); + Reserved.set(SP::O0_O1 + i / 2); + } + if (MF.getSubtarget<SparcSubtarget>().isLRegisterReserved(i)) { + Reserved.set(SP::L0 + i); + Reserved.set(SP::L0_L1 + i / 2); + } + if (MF.getSubtarget<SparcSubtarget>().isIRegisterReserved(i)) { + Reserved.set(SP::I0 + i); + Reserved.set(SP::I0_I1 + i / 2); + } + } + return Reserved; } +bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF, + MCRegister Reg) const { + return getReservedRegs(MF)[Reg]; +} + +bool SparcRegisterInfo::isAnyArgRegReserved(const MachineFunction &MF) const { + bool Outgoing = + llvm::any_of(*SP::GPROutgoingArgRegClass.MC, + [this, &MF](MCPhysReg r) { return isReservedReg(MF, r); }); + bool Incoming = + llvm::any_of(*SP::GPRIncomingArgRegClass.MC, + [this, &MF](MCPhysReg r) { return isReservedReg(MF, r); }); + return Outgoing || Incoming; +} + +void SparcRegisterInfo::emitReservedArgRegCallError( + const MachineFunction &MF) const { + const Function &F = MF.getFunction(); + F.getContext().diagnose(DiagnosticInfoUnsupported{ + F, ("SPARC doesn't support" + " function calls if any of the argument registers is reserved.")}); +} + const TargetRegisterClass* SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind) const { diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.h b/llvm/lib/Target/Sparc/SparcRegisterInfo.h index 5b3c1a7ad07dd5..67c5d0c0fdac3d 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.h +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.h @@ -30,6 +30,9 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const; BitVector getReservedRegs(const MachineFunction &MF) const override; + bool isReservedReg(const MachineFunction &MF, MCRegister Reg) const; + bool isAnyArgRegReserved(const MachineFunction &MF) const; + void emitReservedArgRegCallError(const MachineFunction &MF) const; const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, unsigned Kind) const override; diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.td b/llvm/lib/Target/Sparc/SparcRegisterInfo.td index d5ba7464695c5f..d8319a8d41dda0 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.td +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.td @@ -370,6 +370,10 @@ def LowQFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 7)>; // Floating point control register classes. def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>; +// GPR argument registers. +def GPROutgoingArg : RegisterClass<"SP", [i32, i64], 32, (sequence "O%u", 0, 5)>; +def GPRIncomingArg : RegisterClass<"SP", [i32, i64], 32, (sequence "I%u", 0, 5)>; + let isAllocatable = 0 in { // Ancillary state registers // FIXME: TICK is special-cased here as it can be accessed diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp index 81c2137ea730f8..c7c37af83e206a 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -45,7 +45,11 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU, SparcSubtarget::SparcSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, const TargetMachine &TM, bool is64Bit) - : SparcGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TargetTriple(TT), + : SparcGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), + ReserveGRegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveORegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveLRegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveIRegister(SP::IntRegsRegClass.getNumRegs() / 4), TargetTriple(TT), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index 8e3d05d5d7e5df..fedc60e8d59bbb 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -29,6 +29,12 @@ namespace llvm { class StringRef; class SparcSubtarget : public SparcGenSubtargetInfo { + // Reserve*Register[i] - *#i is not available as a general purpose register. + BitVector ReserveGRegister; + BitVector ReserveORegister; + BitVector ReserveLRegister; + BitVector ReserveIRegister; + Triple TargetTriple; virtual void anchor(); @@ -80,6 +86,11 @@ class SparcSubtarget : public SparcGenSubtargetInfo { return is64Bit() ? 2047 : 0; } + bool isGRegisterReserved(size_t i) const { return ReserveGRegister[i]; } + bool isORegisterReserved(size_t i) const { return ReserveORegister[i]; } + bool isLRegisterReserved(size_t i) const { return ReserveLRegister[i]; } + bool isIRegisterReserved(size_t i) const { return ReserveIRegister[i]; } + /// Given a actual stack size as determined by FrameInfo, this function /// returns adjusted framesize which includes space for register window /// spills and arguments. diff --git a/llvm/test/CodeGen/SPARC/reserved-arg-regs.ll b/llvm/test/CodeGen/SPARC/reserved-arg-regs.ll new file mode 100644 index 00000000000000..3587ecb7f3c94a --- /dev/null +++ b/llvm/test/CodeGen/SPARC/reserved-arg-regs.ll @@ -0,0 +1,25 @@ +;; Test reserving argument registers. +; RUN: not llc < %s -mtriple=sparc-linux-gnu -mattr=+reserve-o0 2>&1 | FileCheck %s --check-prefixes=CHECK-RESERVED-O0 +; RUN: not llc < %s -mtriple=sparc64-linux-gnu -mattr=+reserve-o0 2>&1 | FileCheck %s --check-prefixes=CHECK-RESERVED-O0 +; RUN: not llc < %s -mtriple=sparc-linux-gnu -mattr=+reserve-i0 2>&1 | FileCheck %s --check-prefixes=CHECK-RESERVED-I0 +; RUN: not llc < %s -mtriple=sparc64-linux-gnu -mattr=+reserve-i0 2>&1 | FileCheck %s --check-prefixes=CHECK-RESERVED-I0 + +; CHECK-RESERVED-O0: error: +; CHECK-RESERVED-O0-SAME: SPARC doesn't support function calls if any of the argument registers is reserved. +; CHECK-RESERVED-I0: error: +; CHECK-RESERVED-I0-SAME: SPARC doesn't support function calls if any of the argument registers is reserved. +define void @call_function() { + call void @foo() + ret void +} +declare void @foo() + +; CHECK-RESERVED-O0: error: +; CHECK-RESERVED-O0-SAME: SPARC doesn't support function calls if any of the argument registers is reserved. +; CHECK-RESERVED-I0: error: +; CHECK-RESERVED-I0-SAME: SPARC doesn't support function calls if any of the argument registers is reserved. +define void @call_function_with_arg(i8 %in) { + call void @bar(i8 %in) + ret void +} +declare void @bar(i8) diff --git a/llvm/test/CodeGen/SPARC/reserved-regs.ll b/llvm/test/CodeGen/SPARC/reserved-regs.ll index ec6290586eeef2..7dea1f31538b84 100644 --- a/llvm/test/CodeGen/SPARC/reserved-regs.ll +++ b/llvm/test/CodeGen/SPARC/reserved-regs.ll @@ -1,5 +1,14 @@ ; RUN: llc -march=sparc -verify-machineinstrs < %s | FileCheck %s +;; Test reserve-* options. +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-g1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1 +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-o1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-O1 +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L1 +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-I1 + +;; Test multiple reserve-* options together. +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-g1 -mattr=+reserve-o1 -mattr=+reserve-l1 -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1,CHECK-RESERVED-O1,CHECK-RESERVED-L1,CHECK-RESERVED-I1 + @g = common global [32 x i32] zeroinitializer, align 16 @h = common global [16 x i64] zeroinitializer, align 16 @@ -16,6 +25,10 @@ ; CHECK-NOT: %o6 ; CHECK-NOT: %i6 ; CHECK-NOT: %i7 +; CHECK-RESERVED-G1-NOT: %g1 +; CHECK-RESERVED-O1-NOT: %o1 +; CHECK-RESERVED-L1-NOT: %l1 +; CHECK-RESERVED-I1-NOT: %i1 ; CHECK: ret define void @use_all_i32_regs() { entry: @@ -100,6 +113,10 @@ entry: ; CHECK-NOT: %o7 ; CHECK-NOT: %i6 ; CHECK-NOT: %i7 +; CHECK-RESERVED-G1-NOT: %g1 +; CHECK-RESERVED-O1-NOT: %o1 +; CHECK-RESERVED-L1-NOT: %l1 +; CHECK-RESERVED-I1-NOT: %i1 ; CHECK: ret define void @use_all_i64_regs() { entry: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits