Skip to content

Commit

Permalink
[RISCV] Don't include X1 in the X0_PD register pair
Browse files Browse the repository at this point in the history
Zdinx on RV32 defines the D instructions as taking even register pairs,
and specifies that if using X0 when as a destination then X1 won't be
written, and if using X0 as a source then the value is still all 0s
(i.e. X1 isn't read). Therefore, it's incorrect to model X0_PD as having
X1 as a subregister. This will also be the case for register pairs in
Zacas and the P extension (and this patch takes the same approach as
D95588 does).

This patch introduces a dummy register that is solely used as a subreg
alongside X0 in X0_PD. An earlier version of the patch had a minor
effect on register allocation in some tests, which is now avoided by:
1) Adding RISCV::DUMMY_REG_PAIR_WITH_X0 to RISCVRegisterInfo::getReservedRegs
2) Defining a new register class that includes DUMMY_REG_PAIR_WITH_X0

Differential Revision: https://reviews.llvm.org/D153974
  • Loading branch information
asb committed Jul 20, 2023
1 parent d483824 commit 48a749e
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
4 changes: 4 additions & 0 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
Expand Up @@ -103,6 +103,10 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
if (TFI->hasBP(MF))
markSuperRegs(Reserved, RISCVABI::getBPReg()); // bp

// Additionally reserve dummy register used to form the register pair
// beginning with 'x0' for instructions that take register pairs.
markSuperRegs(Reserved, RISCV::DUMMY_REG_PAIR_WITH_X0);

// V registers for code generation. We handle them manually.
markSuperRegs(Reserved, RISCV::VL);
markSuperRegs(Reserved, RISCV::VTYPE);
Expand Down
17 changes: 16 additions & 1 deletion llvm/lib/Target/RISCV/RISCVRegisterInfo.td
Expand Up @@ -535,8 +535,23 @@ def GPRF16 : RegisterClass<"RISCV", [f16], 16, (add GPR)>;
def GPRF32 : RegisterClass<"RISCV", [f32], 32, (add GPR)>;
} // RegInfos = XLenRI

// Dummy zero register for use in the register pair containing X0 (as X1 is
// not read to or written when the X0 register pair is used).
def DUMMY_REG_PAIR_WITH_X0 : RISCVReg<0, "0">;

// Must add DUMMY_REG_PAIR_WITH_X0 to a separate register class to prevent the
// register's existence from changing codegen (due to the regPressureSetLimit
// for the GPR register class being altered).
def GPRAll : GPRRegisterClass<(add GPR, DUMMY_REG_PAIR_WITH_X0)>;

let RegAltNameIndices = [ABIRegAltName] in {
foreach I = 0-15 in {
def X0_PD : RISCVRegWithSubRegs<0, X0.AsmName,
[X0, DUMMY_REG_PAIR_WITH_X0],
X0.AltNames> {
let SubRegIndices = [sub_32, sub_32_hi];
let CoveredBySubRegs = 1;
}
foreach I = 1-15 in {
defvar Index = !shl(I, 1);
defvar Reg = !cast<Register>("X"#Index);
defvar RegP1 = !cast<Register>("X"#!add(Index,1));
Expand Down

0 comments on commit 48a749e

Please sign in to comment.