[SPARC] Support reserving arbitrary general purpose registers (#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.
This commit is contained in:
Koakuma
2024-02-11 14:04:18 +07:00
committed by GitHub
parent 2c3ba9f622
commit c2f9885a8a
14 changed files with 428 additions and 2 deletions

View File

@@ -5829,6 +5829,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

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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, "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]", "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]", "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]", "true",
"Reserve I"#i#", making it unavailable as a GPR">;
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//

View File

@@ -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<SDValue> &InVals) const {
@@ -805,6 +831,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 +1082,10 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
((hasReturnsTwice)
? TRI->getRTCallPreservedMask(CallConv)
: TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv));
if (isAnyArgRegReserved(TRI, MF))
emitReservedArgRegCallError(MF);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
@@ -1125,6 +1156,13 @@ 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;
if (Reg)
return Reg;
@@ -1189,6 +1227,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 +1411,10 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CLI.CallConv)
: TRI->getCallPreservedMask(DAG.getMachineFunction(),
CLI.CallConv));
if (isAnyArgRegReserved(TRI, MF))
emitReservedArgRegCallError(MF);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));

View File

@@ -12,10 +12,8 @@
#include "SparcRegisterInfo.h"
#include "Sparc.h"
#include "SparcMachineFunctionInfo.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"
@@ -98,9 +96,21 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
for (unsigned n = 0; n < 31; n++)
Reserved.set(SP::ASR1 + n);
for (TargetRegisterClass::iterator i = SP::IntRegsRegClass.begin();
i != SP::IntRegsRegClass.end(); ++i) {
if (MF.getSubtarget<SparcSubtarget>().isRegisterReserved(*i))
markSuperRegs(Reserved, *i);
}
assert(checkAllSuperRegsMarked(Reserved));
return Reserved;
}
bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF,
MCRegister Reg) const {
return getReservedRegs(MF)[Reg];
}
const TargetRegisterClass*
SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const {

View File

@@ -30,6 +30,7 @@ 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;
const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const override;

View File

@@ -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

View File

@@ -50,6 +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(TM.getMCRegisterInfo()->getNumRegs()),
TargetTriple(TM.getTargetTriple()), Is64Bit(is64Bit),
InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)),
TLInfo(TM, *this), FrameLowering(*this) {}

View File

@@ -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 <string>
@@ -29,6 +31,10 @@ namespace llvm {
class StringRef;
class SparcSubtarget : public SparcGenSubtargetInfo {
// ReserveRegister[i] - Register #i is not available as a general purpose
// register.
BitVector ReserveRegister;
Triple TargetTriple;
virtual void anchor();
@@ -82,6 +88,10 @@ public:
return is64Bit() ? 2047 : 0;
}
bool isRegisterReserved(MCPhysReg PhysReg) const {
return ReserveRegister[PhysReg];
}
/// Given a actual stack size as determined by FrameInfo, this function
/// returns adjusted framesize which includes space for register window
/// spills and arguments.

View File

@@ -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)

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -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: