[AArch64] Support reserving arbitrary general purpose registers

This is a follow up to D48580 and D48581 which allows reserving
arbitrary general purpose registers with the exception of registers
with special purpose (X8, X16-X18, X29, X30) and registers used by LLVM
(X0, X19). This change also generalizes some of the existing logic to
rely entirely on values generated from tablegen.

Differential Revision: https://reviews.llvm.org/D56305

llvm-svn: 353957
This commit is contained in:
Petr Hosek 2019-02-13 17:28:47 +00:00
parent 4423122ce4
commit 469dd5010d
7 changed files with 157 additions and 61 deletions

View File

@ -126,7 +126,7 @@ def FeatureStrictAlign : SubtargetFeature<"strict-align",
"Disallow all unaligned memory "
"access">;
foreach i = {1-7,18,20} in
foreach i = {1-7,9-15,18,20-28} in
def FeatureReserveX#i : SubtargetFeature<"reserve-x"#i, "ReserveXRegister["#i#"]", "true",
"Reserve X"#i#", making it unavailable "
"as a GPR">;

View File

@ -5211,50 +5211,20 @@ SDValue AArch64TargetLowering::LowerSPONENTRY(SDValue Op,
return DAG.getFrameIndex(FI, VT);
}
#define GET_REGISTER_MATCHER
#include "AArch64GenAsmMatcher.inc"
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned AArch64TargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
unsigned Reg = StringSwitch<unsigned>(RegName)
.Case("sp", AArch64::SP)
.Case("x1", AArch64::X1)
.Case("w1", AArch64::W1)
.Case("x2", AArch64::X2)
.Case("w2", AArch64::W2)
.Case("x3", AArch64::X3)
.Case("w3", AArch64::W3)
.Case("x4", AArch64::X4)
.Case("w4", AArch64::W4)
.Case("x5", AArch64::X5)
.Case("w5", AArch64::W5)
.Case("x6", AArch64::X6)
.Case("w6", AArch64::W6)
.Case("x7", AArch64::X7)
.Case("w7", AArch64::W7)
.Case("x18", AArch64::X18)
.Case("w18", AArch64::W18)
.Case("x20", AArch64::X20)
.Case("w20", AArch64::W20)
.Default(0);
if (((Reg == AArch64::X1 || Reg == AArch64::W1) &&
!Subtarget->isXRegisterReserved(1)) ||
((Reg == AArch64::X2 || Reg == AArch64::W2) &&
!Subtarget->isXRegisterReserved(2)) ||
((Reg == AArch64::X3 || Reg == AArch64::W3) &&
!Subtarget->isXRegisterReserved(3)) ||
((Reg == AArch64::X4 || Reg == AArch64::W4) &&
!Subtarget->isXRegisterReserved(4)) ||
((Reg == AArch64::X5 || Reg == AArch64::W5) &&
!Subtarget->isXRegisterReserved(5)) ||
((Reg == AArch64::X6 || Reg == AArch64::W6) &&
!Subtarget->isXRegisterReserved(6)) ||
((Reg == AArch64::X7 || Reg == AArch64::W7) &&
!Subtarget->isXRegisterReserved(7)) ||
((Reg == AArch64::X18 || Reg == AArch64::W18) &&
!Subtarget->isXRegisterReserved(18)) ||
((Reg == AArch64::X20 || Reg == AArch64::W20) &&
!Subtarget->isXRegisterReserved(20)))
Reg = 0;
unsigned Reg = MatchRegisterName(RegName);
if (AArch64::X1 <= Reg && Reg <= AArch64::X28) {
const MCRegisterInfo *MRI = Subtarget->getRegisterInfo();
unsigned DwarfRegNum = MRI->getDwarfRegNum(Reg, false);
if (!Subtarget->isXRegisterReserved(DwarfRegNum))
Reg = 0;
}
if (Reg)
return Reg;
report_fatal_error(Twine("Invalid register name \""

View File

@ -242,11 +242,13 @@ const RegisterBank &AArch64RegisterBankInfo::getRegBankFromRegClass(
case AArch64::GPR32RegClassID:
case AArch64::GPR32spRegClassID:
case AArch64::GPR32sponlyRegClassID:
case AArch64::GPR32argRegClassID:
case AArch64::GPR32allRegClassID:
case AArch64::GPR64commonRegClassID:
case AArch64::GPR64RegClassID:
case AArch64::GPR64spRegClassID:
case AArch64::GPR64sponlyRegClassID:
case AArch64::GPR64argRegClassID:
case AArch64::GPR64allRegClassID:
case AArch64::GPR64noipRegClassID:
case AArch64::GPR64common_and_GPR64noipRegClassID:

View File

@ -216,11 +216,8 @@ bool AArch64RegisterInfo::isReservedReg(const MachineFunction &MF,
}
bool AArch64RegisterInfo::isAnyArgRegReserved(const MachineFunction &MF) const {
// FIXME: Get the list of argument registers from TableGen.
static const MCPhysReg GPRArgRegs[] = { AArch64::X0, AArch64::X1, AArch64::X2,
AArch64::X3, AArch64::X4, AArch64::X5,
AArch64::X6, AArch64::X7 };
return std::any_of(std::begin(GPRArgRegs), std::end(GPRArgRegs),
return std::any_of(std::begin(*AArch64::GPR64argRegClass.MC),
std::end(*AArch64::GPR64argRegClass.MC),
[this, &MF](MCPhysReg r){return isReservedReg(MF, r);});
}

View File

@ -187,6 +187,10 @@ def GPR64z : RegisterOperand<GPR64> {
let GIZeroRegister = XZR;
}
// GPR argument registers.
def GPR32arg : RegisterClass<"AArch64", [i32], 32, (sequence "W%u", 0, 7)>;
def GPR64arg : RegisterClass<"AArch64", [i64], 64, (sequence "X%u", 0, 7)>;
// GPR register classes which include WZR/XZR AND SP/WSP. This is not a
// constraint used by any instructions, it is used as a common super-class.
def GPR32all : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WZR, WSP)>;

View File

@ -1,7 +1,5 @@
; RUN: llc -mtriple=arm64-apple-ios -mattr=+reserve-x18 -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X18
; RUN: llc -mtriple=arm64-freebsd-gnu -mattr=+reserve-x18 -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X18
; RUN: llc -mtriple=aarch64-fuchsia -mattr=+reserve-x20 -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X20
; RUN: llc -mtriple=aarch64-fuchsia -mattr=+reserve-x18,+reserve-x20 -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X18 --check-prefix=CHECK-RESERVE-X20
; RUN: llc -mtriple=arm64-linux-gnu -o - %s | FileCheck %s
; RUN: llc -mtriple=aarch64-linux-android -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X18
; RUN: llc -mtriple=aarch64-fuchsia -o - %s | FileCheck %s --check-prefix=CHECK-RESERVE --check-prefix=CHECK-RESERVE-X18
@ -15,6 +13,22 @@
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x5 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X5
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x6 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X6
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x7 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X7
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x9 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X9
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x10 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X10
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x11 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X11
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x12 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X12
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x13 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X13
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x14 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X14
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x15 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X15
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x20 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X20
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x21 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X21
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x22 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X22
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x23 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X23
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x24 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X24
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x25 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X25
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x26 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X26
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x27 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X27
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x28 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X28
; Test multiple of reserve-x# options together.
; RUN: llc -mtriple=arm64-linux-gnu \
@ -36,8 +50,23 @@
; RUN: -mattr=+reserve-x5 \
; RUN: -mattr=+reserve-x6 \
; RUN: -mattr=+reserve-x7 \
; RUN: -mattr=+reserve-x9 \
; RUN: -mattr=+reserve-x10 \
; RUN: -mattr=+reserve-x11 \
; RUN: -mattr=+reserve-x12 \
; RUN: -mattr=+reserve-x13 \
; RUN: -mattr=+reserve-x14 \
; RUN: -mattr=+reserve-x15 \
; RUN: -mattr=+reserve-x18 \
; RUN: -mattr=+reserve-x20 \
; RUN: -mattr=+reserve-x21 \
; RUN: -mattr=+reserve-x22 \
; RUN: -mattr=+reserve-x23 \
; RUN: -mattr=+reserve-x24 \
; RUN: -mattr=+reserve-x25 \
; RUN: -mattr=+reserve-x26 \
; RUN: -mattr=+reserve-x27 \
; RUN: -mattr=+reserve-x28 \
; RUN: -o - %s | FileCheck %s \
; RUN: --check-prefix=CHECK-RESERVE \
; RUN: --check-prefix=CHECK-RESERVE-X1 \
@ -47,8 +76,23 @@
; RUN: --check-prefix=CHECK-RESERVE-X5 \
; RUN: --check-prefix=CHECK-RESERVE-X6 \
; RUN: --check-prefix=CHECK-RESERVE-X7 \
; RUN: --check-prefix=CHECK-RESERVE-X9 \
; RUN: --check-prefix=CHECK-RESERVE-X10 \
; RUN: --check-prefix=CHECK-RESERVE-X11 \
; RUN: --check-prefix=CHECK-RESERVE-X12 \
; RUN: --check-prefix=CHECK-RESERVE-X13 \
; RUN: --check-prefix=CHECK-RESERVE-X14 \
; RUN: --check-prefix=CHECK-RESERVE-X15 \
; RUN: --check-prefix=CHECK-RESERVE-X18 \
; RUN: --check-prefix=CHECK-RESERVE-X20
; RUN: --check-prefix=CHECK-RESERVE-X20 \
; RUN: --check-prefix=CHECK-RESERVE-X21 \
; RUN: --check-prefix=CHECK-RESERVE-X22 \
; RUN: --check-prefix=CHECK-RESERVE-X23 \
; RUN: --check-prefix=CHECK-RESERVE-X24 \
; RUN: --check-prefix=CHECK-RESERVE-X25 \
; RUN: --check-prefix=CHECK-RESERVE-X26 \
; RUN: --check-prefix=CHECK-RESERVE-X27 \
; RUN: --check-prefix=CHECK-RESERVE-X28
; x18 is reserved as a platform register on Darwin but not on other
; systems. Create loads of register pressure and make sure this is respected.
@ -73,8 +117,23 @@ define void @keep_live() {
; CHECK-RESERVE-X5-NOT: ldr x5,
; CHECK-RESERVE-X6-NOT: ldr x6,
; CHECK-RESERVE-X7-NOT: ldr x7,
; CHECK-RESERVE-X9-NOT: ldr x9,
; CHECK-RESERVE-X10-NOT: ldr x10,
; CHECK-RESERVE-X11-NOT: ldr x11,
; CHECK-RESERVE-X12-NOT: ldr x12,
; CHECK-RESERVE-X13-NOT: ldr x13,
; CHECK-RESERVE-X14-NOT: ldr x14,
; CHECK-RESERVE-X15-NOT: ldr x15,
; CHECK-RESERVE-X18-NOT: ldr x18
; CHECK-RESERVE-X20-NOT: ldr x20
; CHECK-RESERVE-X21-NOT: ldr x21
; CHECK-RESERVE-X22-NOT: ldr x22
; CHECK-RESERVE-X23-NOT: ldr x23
; CHECK-RESERVE-X24-NOT: ldr x24
; CHECK-RESERVE-X25-NOT: ldr x25
; CHECK-RESERVE-X26-NOT: ldr x26
; CHECK-RESERVE-X27-NOT: ldr x27
; CHECK-RESERVE-X28-NOT: ldr x28
; CHECK-RESERVE: Spill
; CHECK-RESERVE-NOT: ldr fp
; CHECK-RESERVE-X1-NOT: ldr x1,
@ -84,8 +143,23 @@ define void @keep_live() {
; CHECK-RESERVE-X5-NOT: ldr x5,
; CHECK-RESERVE-X6-NOT: ldr x6,
; CHECK-RESERVE-X7-NOT: ldr x7,
; CHECK-RESERVE-X9-NOT: ldr x9,
; CHECK-RESERVE-X10-NOT: ldr x10,
; CHECK-RESERVE-X11-NOT: ldr x11,
; CHECK-RESERVE-X12-NOT: ldr x12,
; CHECK-RESERVE-X13-NOT: ldr x13,
; CHECK-RESERVE-X14-NOT: ldr x14,
; CHECK-RESERVE-X15-NOT: ldr x15,
; CHECK-RESERVE-X18-NOT: ldr x18
; CHECK-RESERVE-X20-NOT: ldr x20
; CHECK-RESERVE-X21-NOT: ldr x21
; CHECK-RESERVE-X22-NOT: ldr x22
; CHECK-RESERVE-X23-NOT: ldr x23
; CHECK-RESERVE-X24-NOT: ldr x24
; CHECK-RESERVE-X25-NOT: ldr x25
; CHECK-RESERVE-X26-NOT: ldr x26
; CHECK-RESERVE-X27-NOT: ldr x27
; CHECK-RESERVE-X28-NOT: ldr x28
; CHECK-RESERVE: ret
ret void
}

View File

@ -1,13 +1,34 @@
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 \
; RUN: -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x9 -mattr=+call-saved-x9 -o - %s | FileCheck %s --check-prefixes=CHECK-X9
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x9 -mattr=+call-saved-x9 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X9
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x9 -mattr=+call-saved-x9 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X9
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 \
; RUN: -global-isel \
; RUN: -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x10 -mattr=+call-saved-x10 -o - %s | FileCheck %s --check-prefixes=CHECK-X10
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x10 -mattr=+call-saved-x10 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X10
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x10 -mattr=+call-saved-x10 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X10
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 \
; RUN: -fast-isel \
; RUN: -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x11 -mattr=+call-saved-x11 -o - %s | FileCheck %s --check-prefixes=CHECK-X11
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x11 -mattr=+call-saved-x11 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X11
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x11 -mattr=+call-saved-x11 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X11
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x12 -mattr=+call-saved-x12 -o - %s | FileCheck %s --check-prefixes=CHECK-X12
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x12 -mattr=+call-saved-x12 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X12
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x12 -mattr=+call-saved-x12 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X12
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x13 -mattr=+call-saved-x13 -o - %s | FileCheck %s --check-prefixes=CHECK-X13
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x13 -mattr=+call-saved-x13 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X13
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x13 -mattr=+call-saved-x13 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X13
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x14 -mattr=+call-saved-x14 -o - %s | FileCheck %s --check-prefixes=CHECK-X14
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x14 -mattr=+call-saved-x14 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X14
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x14 -mattr=+call-saved-x14 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X14
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x15 -mattr=+call-saved-x15 -o - %s | FileCheck %s --check-prefixes=CHECK-X15
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x15 -mattr=+call-saved-x15 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X15
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x15 -mattr=+call-saved-x15 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X15
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 -o - %s | FileCheck %s --check-prefixes=CHECK-X18
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 -global-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X18
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x18 -mattr=+call-saved-x18 -fast-isel -o - %s | FileCheck %s --check-prefixes=CHECK-X18
; Used to exhaust the supply of GPRs.
@var = global [30 x i64] zeroinitializer
@ -15,14 +36,42 @@
; If a register is specified to be both reserved and callee-saved, then it
; should not be allocated and should not be spilled onto the stack.
define void @foo() {
; CHECK-NOT: str x18, [sp
; CHECK-X9-NOT: str x9, [sp
; CHECK-X10-NOT: str x10, [sp
; CHECK-X11-NOT: str x11, [sp
; CHECK-X12-NOT: str x12, [sp
; CHECK-X13-NOT: str x13, [sp
; CHECK-X14-NOT: str x14, [sp
; CHECK-X15-NOT: str x15, [sp
; CHECK-X18-NOT: str x18, [sp
%val = load volatile [30 x i64], [30 x i64]* @var
store volatile [30 x i64] %val, [30 x i64]* @var
; CHECK-NOT: ldr x18
; CHECK-NOT: str x18
; CHECK-X9-NOT: ldr x9
; CHECK-X10-NOT: ldr x10
; CHECK-X11-NOT: ldr x11
; CHECK-X12-NOT: ldr x12
; CHECK-X13-NOT: ldr x13
; CHECK-X14-NOT: ldr x14
; CHECK-X15-NOT: ldr x15
; CHECK-X18-NOT: ldr x18
; CHECK-X9-NOT: str x9
; CHECK-X10-NOT: str x10
; CHECK-X11-NOT: str x11
; CHECK-X12-NOT: str x12
; CHECK-X13-NOT: str x13
; CHECK-X14-NOT: str x14
; CHECK-X15-NOT: str x15
; CHECK-X18-NOT: str x18
; CHECK-NOT: ldr x18, [sp
; CHECK-X9-NOT: ldr x9, [sp
; CHECK-X10-NOT: ldr x10, [sp
; CHECK-X11-NOT: ldr x11, [sp
; CHECK-X12-NOT: ldr x12, [sp
; CHECK-X13-NOT: ldr x13, [sp
; CHECK-X14-NOT: ldr x14, [sp
; CHECK-X15-NOT: ldr x15, [sp
; CHECK-X18-NOT: ldr x18, [sp
ret void
}