From fd0bae41e2c3ed791a6a73affc9e1709e21ff880 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 29 Nov 2023 08:08:29 +0700 Subject: [PATCH 1/7] [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 | 4 + 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, 419 insertions(+), 1 deletion(-) 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 f1687d823f6e0a..1bc21f24145688 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5794,6 +5794,18 @@ def mvis3 : Flag<["-"], "mvis3">, Group; def mno_vis3 : Flag<["-"], "mno-vis3">, Group; def mhard_quad_float : Flag<["-"], "mhard-quad-float">, Group; def msoft_quad_float : Flag<["-"], "msoft-quad-float">, Group; +foreach i = {1-7} in + def ffixed_g#i : Flag<["-"], "ffixed-g"#i>, Group, + HelpText<"Reserve the G"#i#" register (SPARC only)">; +foreach i = {0-5} in + def ffixed_o#i : Flag<["-"], "ffixed-o"#i>, Group, + HelpText<"Reserve the O"#i#" register (SPARC only)">; +foreach i = {0-7} in + def ffixed_l#i : Flag<["-"], "ffixed-l"#i>, Group, + HelpText<"Reserve the L"#i#" register (SPARC only)">; +foreach i = {0-5} in + def ffixed_i#i : Flag<["-"], "ffixed-i"#i>, 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 7b103395652433..f977f24466d091 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -72,6 +72,20 @@ def TuneSlowRDPC : SubtargetFeature<"slow-rdpc", "HasSlowRDPC", "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 78bdf3ae9a84ba..b42ff5989ddf0d 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 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 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().isGRegisterReserved(i)) { + Reserved.set(SP::G0 + i); + Reserved.set(SP::G0_G1 + i / 2); + } + if (MF.getSubtarget().isORegisterReserved(i)) { + Reserved.set(SP::O0 + i); + Reserved.set(SP::O0_O1 + i / 2); + } + if (MF.getSubtarget().isLRegisterReserved(i)) { + Reserved.set(SP::L0 + i); + Reserved.set(SP::L0_L1 + i / 2); + } + if (MF.getSubtarget().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 6b09904ca5e8e5..338194d406973a 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -50,6 +50,10 @@ SparcSubtarget::SparcSubtarget(const StringRef &CPU, const StringRef &TuneCPU, const StringRef &FS, const TargetMachine &TM, bool is64Bit) : SparcGenSubtargetInfo(TM.getTargetTriple(), CPU, TuneCPU, FS), + ReserveGRegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveORegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveLRegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveIRegister(SP::IntRegsRegClass.getNumRegs() / 4), TargetTriple(TM.getTargetTriple()), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index cdb210f67482c4..53b57ef374032d 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(); @@ -82,6 +88,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: From a11f306a92129b4c05f1850e6f4e3f187f13d2d0 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 21 Dec 2023 08:42:27 +0700 Subject: [PATCH 2/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- clang/include/clang/Driver/Options.td | 8 ++++---- llvm/lib/Target/Sparc/Sparc.td | 8 ++++---- llvm/lib/Target/Sparc/SparcISelLowering.cpp | 15 +++------------ llvm/lib/Target/Sparc/SparcRegisterInfo.cpp | 4 ++-- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1bc21f24145688..3095ba3ffc3e77 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5794,16 +5794,16 @@ def mvis3 : Flag<["-"], "mvis3">, Group; def mno_vis3 : Flag<["-"], "mno-vis3">, Group; def mhard_quad_float : Flag<["-"], "mhard-quad-float">, Group; def msoft_quad_float : Flag<["-"], "msoft-quad-float">, Group; -foreach i = {1-7} in +foreach i = 1 ... 7 in def ffixed_g#i : Flag<["-"], "ffixed-g"#i>, Group, HelpText<"Reserve the G"#i#" register (SPARC only)">; -foreach i = {0-5} in +foreach i = 0 ... 5 in def ffixed_o#i : Flag<["-"], "ffixed-o"#i>, Group, HelpText<"Reserve the O"#i#" register (SPARC only)">; -foreach i = {0-7} in +foreach i = 0 ... 7 in def ffixed_l#i : Flag<["-"], "ffixed-l"#i>, Group, HelpText<"Reserve the L"#i#" register (SPARC only)">; -foreach i = {0-5} in +foreach i = 0 ... 5 in def ffixed_i#i : Flag<["-"], "ffixed-i"#i>, Group, HelpText<"Reserve the I"#i#" register (SPARC only)">; } // let Flags = [TargetSpecific] diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index f977f24466d091..3fdaafa2b65e76 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -73,16 +73,16 @@ def TuneSlowRDPC : SubtargetFeature<"slow-rdpc", "HasSlowRDPC", "true", include "LeonFeatures.td" //==== Register allocation tweaks needed by some low-level software -foreach i = {1-7} in +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 +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 +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 +foreach i = 0 ... 5 in def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveIRegister["#i#"]", "true", "Reserve I"#i#", making it unavailable as a GPR">; diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index b42ff5989ddf0d..03db114cbca5ba 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1130,18 +1130,9 @@ 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; - } + const SparcRegisterInfo *TRI = Subtarget->getRegisterInfo(); + if (!TRI->isReservedReg(MF, Reg)) + Reg = 0; if (Reg) return Reg; diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index 233f1dfd3ecf2b..bdb296d47aceb7 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -128,10 +128,10 @@ bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF, bool SparcRegisterInfo::isAnyArgRegReserved(const MachineFunction &MF) const { bool Outgoing = - llvm::any_of(*SP::GPROutgoingArgRegClass.MC, + llvm::any_of(SP::GPROutgoingArgRegClass, [this, &MF](MCPhysReg r) { return isReservedReg(MF, r); }); bool Incoming = - llvm::any_of(*SP::GPRIncomingArgRegClass.MC, + llvm::any_of(SP::GPRIncomingArgRegClass, [this, &MF](MCPhysReg r) { return isReservedReg(MF, r); }); return Outgoing || Incoming; } From ee9b15e86e38e855ebcc9300a562764318473afe Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 24 Dec 2023 14:46:36 +0700 Subject: [PATCH 3/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- llvm/lib/Target/Sparc/SparcISelLowering.cpp | 37 +++++++++++++++++-- llvm/lib/Target/Sparc/SparcRegisterInfo.cpp | 20 ---------- llvm/lib/Target/Sparc/SparcRegisterInfo.h | 2 - .../test/CodeGen/SPARC/reserved-regs-named.ll | 13 +++++++ 4 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 llvm/test/CodeGen/SPARC/reserved-regs-named.ll diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 03db114cbca5ba..bdefb0841a124b 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -13,6 +13,7 @@ #include "SparcISelLowering.h" #include "MCTargetDesc/SparcMCExpr.h" +#include "MCTargetDesc/SparcMCTargetDesc.h" #include "SparcMachineFunctionInfo.h" #include "SparcRegisterInfo.h" #include "SparcTargetMachine.h" @@ -28,6 +29,7 @@ #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" @@ -729,6 +731,30 @@ SDValue SparcTargetLowering::LowerFormalArguments_64( return Chain; } +// Check whether any of the argument registers are reserved +static bool isAnyArgRegReserved(const SparcRegisterInfo *TRI, + const MachineFunction &MF) { + // The register window design means that outgoing parameters at O* + // will appear in the callee as I*. + // Be conservative and check both sides of the register names. + bool Outgoing = + llvm::any_of(SP::GPROutgoingArgRegClass, [TRI, &MF](MCPhysReg r) { + return TRI->isReservedReg(MF, r); + }); + bool Incoming = + llvm::any_of(SP::GPRIncomingArgRegClass, [TRI, &MF](MCPhysReg r) { + return TRI->isReservedReg(MF, r); + }); + return Outgoing || Incoming; +} + +static void emitReservedArgRegCallError(const MachineFunction &MF) { + const Function &F = MF.getFunction(); + F.getContext().diagnose(DiagnosticInfoUnsupported{ + F, ("SPARC doesn't support" + " function calls if any of the argument registers is reserved.")}); +} + SDValue SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { @@ -1057,8 +1083,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, ? TRI->getRTCallPreservedMask(CallConv) : TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv)); - if (TRI->isAnyArgRegReserved(MF)) - TRI->emitReservedArgRegCallError(MF); + if (isAnyArgRegReserved(TRI, MF)) + emitReservedArgRegCallError(MF); assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); @@ -1130,6 +1156,9 @@ 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); + // If we're directly referencing register names + // (e.g in GCC C extension `register int r asm("g1");`), + // make sure that said register is in the reserve list. const SparcRegisterInfo *TRI = Subtarget->getRegisterInfo(); if (!TRI->isReservedReg(MF, Reg)) Reg = 0; @@ -1383,8 +1412,8 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, : TRI->getCallPreservedMask(DAG.getMachineFunction(), CLI.CallConv)); - if (TRI->isAnyArgRegReserved(MF)) - TRI->emitReservedArgRegCallError(MF); + if (isAnyArgRegReserved(TRI, MF)) + 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 bdb296d47aceb7..49f12bb5d41d88 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -14,12 +14,10 @@ #include "Sparc.h" #include "SparcSubtarget.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #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" @@ -126,24 +124,6 @@ bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF, return getReservedRegs(MF)[Reg]; } -bool SparcRegisterInfo::isAnyArgRegReserved(const MachineFunction &MF) const { - bool Outgoing = - llvm::any_of(SP::GPROutgoingArgRegClass, - [this, &MF](MCPhysReg r) { return isReservedReg(MF, r); }); - bool Incoming = - llvm::any_of(SP::GPRIncomingArgRegClass, - [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 67c5d0c0fdac3d..58c85f33635f2d 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.h +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.h @@ -31,8 +31,6 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { 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/test/CodeGen/SPARC/reserved-regs-named.ll b/llvm/test/CodeGen/SPARC/reserved-regs-named.ll new file mode 100644 index 00000000000000..91808be156c559 --- /dev/null +++ b/llvm/test/CodeGen/SPARC/reserved-regs-named.ll @@ -0,0 +1,13 @@ +; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l0 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L0 + +;; Ensure explicit register references are catched as well. + +; CHECK-RESERVED-L0: %l0 +define void @set_reg(i32 zeroext %x) { +entry: + tail call void @llvm.write_register.i32(metadata !0, i32 %x) + ret void +} + +declare void @llvm.write_register.i32(metadata, i32) +!0 = !{!"l0"} From eb8204df7daf14cf48116604e018e520ba282d3a Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 11 Jan 2024 20:52:05 +0700 Subject: [PATCH 4/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- .../CodeGen/SPARC/reserved-regs-unavailable.ll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 llvm/test/CodeGen/SPARC/reserved-regs-unavailable.ll diff --git a/llvm/test/CodeGen/SPARC/reserved-regs-unavailable.ll b/llvm/test/CodeGen/SPARC/reserved-regs-unavailable.ll new file mode 100644 index 00000000000000..53ca045f100443 --- /dev/null +++ b/llvm/test/CodeGen/SPARC/reserved-regs-unavailable.ll @@ -0,0 +1,14 @@ +; RUN: not --crash llc -mtriple=sparc64-linux-gnu -o - %s 2>&1 | FileCheck %s --check-prefixes=CHECK-RESERVED-L0 + +;; Ensure explicit register references for non-reserved registers +;; are caught properly. + +; CHECK-RESERVED-L0: LLVM ERROR: Invalid register name global variable +define void @set_reg(i32 zeroext %x) { +entry: + tail call void @llvm.write_register.i32(metadata !0, i32 %x) + ret void +} + +declare void @llvm.write_register.i32(metadata, i32) +!0 = !{!"l0"} From a7e35eaa3a4c9a68bccb5773ca476a6194d5ecff Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 21 Jan 2024 15:57:17 +0700 Subject: [PATCH 5/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- llvm/lib/Target/Sparc/Sparc.td | 8 +++---- llvm/lib/Target/Sparc/SparcRegisterInfo.cpp | 23 +++++---------------- llvm/lib/Target/Sparc/SparcSubtarget.cpp | 5 +---- llvm/lib/Target/Sparc/SparcSubtarget.h | 20 ++++++++++-------- 4 files changed, 21 insertions(+), 35 deletions(-) diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index 3fdaafa2b65e76..d46a8a90921f25 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -74,16 +74,16 @@ 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", + def FeatureReserveG#i : SubtargetFeature<"reserve-g"#i, "ReserveRegister["#i#" + SP::G0 - SP::G0]", "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", + def FeatureReserveO#i : SubtargetFeature<"reserve-o"#i, "ReserveRegister["#i#" + SP::O0 - SP::G0]", "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", + def FeatureReserveL#i : SubtargetFeature<"reserve-l"#i, "ReserveRegister["#i#" + SP::L0 - SP::G0]", "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", + def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveRegister["#i#" + SP::I0 - SP::G0]", "true", "Reserve I"#i#", making it unavailable as a GPR">; //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index 49f12bb5d41d88..71a27f77d2c6bf 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -96,26 +96,13 @@ 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().isGRegisterReserved(i)) { - Reserved.set(SP::G0 + i); - Reserved.set(SP::G0_G1 + i / 2); - } - if (MF.getSubtarget().isORegisterReserved(i)) { - Reserved.set(SP::O0 + i); - Reserved.set(SP::O0_O1 + i / 2); - } - if (MF.getSubtarget().isLRegisterReserved(i)) { - Reserved.set(SP::L0 + i); - Reserved.set(SP::L0_L1 + i / 2); - } - if (MF.getSubtarget().isIRegisterReserved(i)) { - Reserved.set(SP::I0 + i); - Reserved.set(SP::I0_I1 + i / 2); - } + for (TargetRegisterClass::iterator i = SP::IntRegsRegClass.begin(); + i != SP::IntRegsRegClass.end(); ++i) { + if (MF.getSubtarget().isRegisterReserved(*i)) + markSuperRegs(Reserved, *i); } + assert(checkAllSuperRegsMarked(Reserved)); return Reserved; } diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp index 338194d406973a..b970fbf0541c66 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -50,10 +50,7 @@ SparcSubtarget::SparcSubtarget(const StringRef &CPU, const StringRef &TuneCPU, const StringRef &FS, const TargetMachine &TM, bool is64Bit) : SparcGenSubtargetInfo(TM.getTargetTriple(), CPU, TuneCPU, FS), - ReserveGRegister(SP::IntRegsRegClass.getNumRegs() / 4), - ReserveORegister(SP::IntRegsRegClass.getNumRegs() / 4), - ReserveLRegister(SP::IntRegsRegClass.getNumRegs() / 4), - ReserveIRegister(SP::IntRegsRegClass.getNumRegs() / 4), + ReserveRegister(SP::IntRegsRegClass.getNumRegs()), TargetTriple(TM.getTargetTriple()), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index 53b57ef374032d..62c542c34a329b 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -13,12 +13,14 @@ #ifndef LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H #define LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H +#include "MCTargetDesc/SparcMCTargetDesc.h" #include "SparcFrameLowering.h" #include "SparcISelLowering.h" #include "SparcInstrInfo.h" #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/TargetParser/Triple.h" #include @@ -29,11 +31,9 @@ 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; + // ReserveRegister[i] - Register #i is not available as a general purpose + // register. + BitVector ReserveRegister; Triple TargetTriple; virtual void anchor(); @@ -88,10 +88,12 @@ 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]; } + bool isRegisterReserved(MCPhysReg PhysReg) const { + if (PhysReg >= SP::G0 && PhysReg <= SP::O7) + return ReserveRegister[PhysReg - SP::G0]; + + llvm_unreachable("Invalid physical register passed!"); + } /// Given a actual stack size as determined by FrameInfo, this function /// returns adjusted framesize which includes space for register window From 30a4823d662a049bbcddd39049c03b6a15574879 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Feb 2024 08:54:39 +0700 Subject: [PATCH 6/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- llvm/lib/Target/Sparc/Sparc.td | 8 ++++---- llvm/lib/Target/Sparc/SparcSubtarget.cpp | 2 +- llvm/lib/Target/Sparc/SparcSubtarget.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index d46a8a90921f25..38a59e650f33c7 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -74,16 +74,16 @@ include "LeonFeatures.td" //==== Register allocation tweaks needed by some low-level software foreach i = 1 ... 7 in - def FeatureReserveG#i : SubtargetFeature<"reserve-g"#i, "ReserveRegister["#i#" + SP::G0 - SP::G0]", "true", + def FeatureReserveG#i : SubtargetFeature<"reserve-g"#i, "ReserveRegister["#i#" + SP::G0]", "true", "Reserve G"#i#", making it unavailable as a GPR">; foreach i = 0 ... 5 in - def FeatureReserveO#i : SubtargetFeature<"reserve-o"#i, "ReserveRegister["#i#" + SP::O0 - SP::G0]", "true", + def FeatureReserveO#i : SubtargetFeature<"reserve-o"#i, "ReserveRegister["#i#" + SP::O0]", "true", "Reserve O"#i#", making it unavailable as a GPR">; foreach i = 0 ... 7 in - def FeatureReserveL#i : SubtargetFeature<"reserve-l"#i, "ReserveRegister["#i#" + SP::L0 - SP::G0]", "true", + def FeatureReserveL#i : SubtargetFeature<"reserve-l"#i, "ReserveRegister["#i#" + SP::L0]", "true", "Reserve L"#i#", making it unavailable as a GPR">; foreach i = 0 ... 5 in - def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveRegister["#i#" + SP::I0 - SP::G0]", "true", + def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveRegister["#i#" + SP::I0]", "true", "Reserve I"#i#", making it unavailable as a GPR">; //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp index b970fbf0541c66..5b65e34e0f8a36 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -50,7 +50,7 @@ SparcSubtarget::SparcSubtarget(const StringRef &CPU, const StringRef &TuneCPU, const StringRef &FS, const TargetMachine &TM, bool is64Bit) : SparcGenSubtargetInfo(TM.getTargetTriple(), CPU, TuneCPU, FS), - ReserveRegister(SP::IntRegsRegClass.getNumRegs()), + ReserveRegister(TM.getMCRegisterInfo()->getNumRegs()), TargetTriple(TM.getTargetTriple()), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index 62c542c34a329b..81e0b236ffb5a4 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -90,7 +90,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { bool isRegisterReserved(MCPhysReg PhysReg) const { if (PhysReg >= SP::G0 && PhysReg <= SP::O7) - return ReserveRegister[PhysReg - SP::G0]; + return ReserveRegister[PhysReg]; llvm_unreachable("Invalid physical register passed!"); } From 90140f25f23eb94ed1aa9f95f55e78e4647426de Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Feb 2024 16:04:29 +0700 Subject: [PATCH 7/7] fixup! [SPARC] Support reserving arbitrary general purpose registers --- llvm/lib/Target/Sparc/SparcSubtarget.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index 81e0b236ffb5a4..fe4aca5195306a 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -89,10 +89,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { } bool isRegisterReserved(MCPhysReg PhysReg) const { - if (PhysReg >= SP::G0 && PhysReg <= SP::O7) - return ReserveRegister[PhysReg]; - - llvm_unreachable("Invalid physical register passed!"); + return ReserveRegister[PhysReg]; } /// Given a actual stack size as determined by FrameInfo, this function