Skip to content

Commit bd1561d

Browse files
authored
[RISCV][GISel] Add manual isel for s8/s16/s32 load/store for the GPR bank. (#161995)
GISel doesn't distinquish integer and FP loads and stores. We only know which it is after register bank selection. This results in s16/s32 loads/stores on the GPR register bank that need to be selected. This required extra isel patterns not needed for SDAG and adding i16 and i32 to the GPR register class. Having i16/i32 on the GPR register class makes type interfence in tablegen less effective, requiring explicit casts to be added to patterns. It also increases the size of RISCVGenDAGISel.inc by 2K. This patch removes the extra isel patterns and replaces it with custom instruction selection similar to what is done on AArch64. A future patch will remove i16 and i32 from the GPR register class.
1 parent 4ddc0f3 commit bd1561d

File tree

5 files changed

+99
-59
lines changed

5 files changed

+99
-59
lines changed

llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,45 @@ static void getOperandsForBranch(Register CondReg, RISCVCC::CondCode &CC,
675675
CC = getRISCVCCFromICmp(Pred);
676676
}
677677

678+
/// Select the RISC-V Zalasr opcode for the G_LOAD or G_STORE operation
679+
/// \p GenericOpc, appropriate for the GPR register bank and of memory access
680+
/// size \p OpSize.
681+
static unsigned selectZalasrLoadStoreOp(unsigned GenericOpc, unsigned OpSize) {
682+
const bool IsStore = GenericOpc == TargetOpcode::G_STORE;
683+
switch (OpSize) {
684+
default:
685+
llvm_unreachable("Unexpected memory size");
686+
case 8:
687+
return IsStore ? RISCV::SB_RL : RISCV::LB_AQ;
688+
case 16:
689+
return IsStore ? RISCV::SH_RL : RISCV::LH_AQ;
690+
case 32:
691+
return IsStore ? RISCV::SW_RL : RISCV::LW_AQ;
692+
case 64:
693+
return IsStore ? RISCV::SD_RL : RISCV::LD_AQ;
694+
}
695+
}
696+
697+
/// Select the RISC-V regimm opcode for the G_LOAD or G_STORE operation
698+
/// \p GenericOpc, appropriate for the GPR register bank and of memory access
699+
/// size \p OpSize. \returns \p GenericOpc if the combination is unsupported.
700+
static unsigned selectRegImmLoadStoreOp(unsigned GenericOpc, unsigned OpSize) {
701+
const bool IsStore = GenericOpc == TargetOpcode::G_STORE;
702+
switch (OpSize) {
703+
case 8:
704+
// Prefer unsigned due to no c.lb in Zcb.
705+
return IsStore ? RISCV::SB : RISCV::LBU;
706+
case 16:
707+
return IsStore ? RISCV::SH : RISCV::LH;
708+
case 32:
709+
return IsStore ? RISCV::SW : RISCV::LW;
710+
case 64:
711+
return IsStore ? RISCV::SD : RISCV::LD;
712+
}
713+
714+
return GenericOpc;
715+
}
716+
678717
bool RISCVInstructionSelector::select(MachineInstr &MI) {
679718
MachineIRBuilder MIB(MI);
680719

@@ -892,6 +931,59 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
892931
return selectImplicitDef(MI, MIB);
893932
case TargetOpcode::G_UNMERGE_VALUES:
894933
return selectUnmergeValues(MI, MIB);
934+
case TargetOpcode::G_LOAD:
935+
case TargetOpcode::G_STORE: {
936+
GLoadStore &LdSt = cast<GLoadStore>(MI);
937+
const Register ValReg = LdSt.getReg(0);
938+
const Register PtrReg = LdSt.getPointerReg();
939+
LLT PtrTy = MRI->getType(PtrReg);
940+
941+
const RegisterBank &RB = *RBI.getRegBank(ValReg, *MRI, TRI);
942+
if (RB.getID() != RISCV::GPRBRegBankID)
943+
return false;
944+
945+
#ifndef NDEBUG
946+
const RegisterBank &PtrRB = *RBI.getRegBank(PtrReg, *MRI, TRI);
947+
// Check that the pointer register is valid.
948+
assert(PtrRB.getID() == RISCV::GPRBRegBankID &&
949+
"Load/Store pointer operand isn't a GPR");
950+
assert(PtrTy.isPointer() && "Load/Store pointer operand isn't a pointer");
951+
#endif
952+
953+
// Can only handle AddressSpace 0.
954+
if (PtrTy.getAddressSpace() != 0)
955+
return false;
956+
957+
unsigned MemSize = LdSt.getMemSizeInBits().getValue();
958+
AtomicOrdering Order = LdSt.getMMO().getSuccessOrdering();
959+
960+
if (isStrongerThanMonotonic(Order)) {
961+
MI.setDesc(TII.get(selectZalasrLoadStoreOp(Opc, MemSize)));
962+
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
963+
}
964+
965+
const unsigned NewOpc = selectRegImmLoadStoreOp(MI.getOpcode(), MemSize);
966+
if (NewOpc == MI.getOpcode())
967+
return false;
968+
969+
// Check if we can fold anything into the addressing mode.
970+
auto AddrModeFns = selectAddrRegImm(MI.getOperand(1));
971+
if (!AddrModeFns)
972+
return false;
973+
974+
// Folded something. Create a new instruction and return it.
975+
auto NewInst = MIB.buildInstr(NewOpc, {}, {}, MI.getFlags());
976+
if (isa<GStore>(MI))
977+
NewInst.addUse(ValReg);
978+
else
979+
NewInst.addDef(ValReg);
980+
NewInst.cloneMemRefs(MI);
981+
for (auto &Fn : *AddrModeFns)
982+
Fn(NewInst);
983+
MI.eraseFromParent();
984+
985+
return constrainSelectedInstRegOperands(*NewInst, TII, TRI, RBI);
986+
}
895987
default:
896988
return false;
897989
}

llvm/lib/Target/RISCV/RISCVGISel.td

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -100,65 +100,11 @@ def : LdPat<load, LD, PtrVT>;
100100
def : StPat<store, SD, GPR, PtrVT>;
101101
}
102102

103-
// Load and store patterns for i16, needed because Zfh makes s16 load/store
104-
// legal and regbank select may not constrain registers to FP.
105-
def : LdPat<load, LH, i16>;
106-
def : StPat<store, SH, GPR, i16>;
107-
108-
def : LdPat<extloadi8, LBU, i16>; // Prefer unsigned due to no c.lb in Zcb.
109-
def : StPat<truncstorei8, SB, GPR, i16>;
110-
111-
let Predicates = [HasAtomicLdSt] in {
112-
// Prefer unsigned due to no c.lb in Zcb.
113-
def : LdPat<relaxed_load<atomic_load_aext_8>, LBU, i16>;
114-
def : LdPat<relaxed_load<atomic_load_nonext_16>, LH, i16>;
115-
116-
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, i16>;
117-
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, i16>;
118-
}
119-
120-
let Predicates = [HasAtomicLdSt, IsRV64] in {
121-
// Load pattern is in RISCVInstrInfoA.td and shared with RV32.
122-
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, i32>;
123-
}
124-
125103
//===----------------------------------------------------------------------===//
126104
// RV64 i32 patterns not used by SelectionDAG
127105
//===----------------------------------------------------------------------===//
128106

129107
let Predicates = [IsRV64] in {
130-
def : LdPat<extloadi8, LBU, i32>; // Prefer unsigned due to no c.lb in Zcb.
131-
def : LdPat<extloadi16, LH, i32>;
132-
133-
def : StPat<truncstorei8, SB, GPR, i32>;
134-
def : StPat<truncstorei16, SH, GPR, i32>;
135-
136108
def : Pat<(sext_inreg (i64 (add GPR:$rs1, simm12_lo:$imm)), i32),
137109
(ADDIW GPR:$rs1, simm12_lo:$imm)>;
138110
}
139-
140-
//===----------------------------------------------------------------------===//
141-
// Zalasr patterns not used by SelectionDAG
142-
//===----------------------------------------------------------------------===//
143-
144-
let Predicates = [HasStdExtZalasr] in {
145-
// the sequentially consistent loads use
146-
// .aq instead of .aqrl to match the psABI/A.7
147-
def : PatLAQ<acquiring_load<atomic_load_aext_8>, LB_AQ, i16>;
148-
def : PatLAQ<seq_cst_load<atomic_load_aext_8>, LB_AQ, i16>;
149-
150-
def : PatLAQ<acquiring_load<atomic_load_nonext_16>, LH_AQ, i16>;
151-
def : PatLAQ<seq_cst_load<atomic_load_nonext_16>, LH_AQ, i16>;
152-
153-
def : PatSRL<releasing_store<atomic_store_8>, SB_RL, i16>;
154-
def : PatSRL<seq_cst_store<atomic_store_8>, SB_RL, i16>;
155-
156-
def : PatSRL<releasing_store<atomic_store_16>, SH_RL, i16>;
157-
def : PatSRL<seq_cst_store<atomic_store_16>, SH_RL, i16>;
158-
}
159-
160-
let Predicates = [HasStdExtZalasr, IsRV64] in {
161-
// Load pattern is in RISCVInstrInfoZalasr.td and shared with RV32.
162-
def : PatSRL<releasing_store<atomic_store_32>, SW_RL, i32>;
163-
def : PatSRL<seq_cst_store<atomic_store_32>, SW_RL, i32>;
164-
}

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,7 @@ def : LdPat<sextloadi8, LB>;
19801980
def : LdPat<extloadi8, LBU>; // Prefer unsigned due to no c.lb in Zcb.
19811981
def : LdPat<sextloadi16, LH>;
19821982
def : LdPat<extloadi16, LH>;
1983-
def : LdPat<load, LW, i32>;
1983+
def : LdPat<load, LW, i32>, Requires<[IsRV32]>;
19841984
def : LdPat<zextloadi8, LBU>;
19851985
def : LdPat<zextloadi16, LHU>;
19861986

@@ -1994,7 +1994,7 @@ class StPat<PatFrag StoreOp, RVInst Inst, RegisterClass StTy,
19941994

19951995
def : StPat<truncstorei8, SB, GPR, XLenVT>;
19961996
def : StPat<truncstorei16, SH, GPR, XLenVT>;
1997-
def : StPat<store, SW, GPR, i32>;
1997+
def : StPat<store, SW, GPR, i32>, Requires<[IsRV32]>;
19981998

19991999
/// Fences
20002000

llvm/lib/Target/RISCV/RISCVInstrInfoA.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,9 @@ let Predicates = [HasAtomicLdSt] in {
174174
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, XLenVT>;
175175
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, XLenVT>;
176176
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, XLenVT>;
177+
}
177178

178-
// Used by GISel for RV32 and RV64.
179+
let Predicates = [HasAtomicLdSt, IsRV32] in {
179180
def : LdPat<relaxed_load<atomic_load_nonext_32>, LW, i32>;
180181
}
181182

llvm/lib/Target/RISCV/RISCVInstrInfoZalasr.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,12 @@ let Predicates = [HasStdExtZalasr] in {
9494

9595
def : PatSRL<releasing_store<atomic_store_32>, SW_RL>;
9696
def : PatSRL<seq_cst_store<atomic_store_32>, SW_RL>;
97+
}
9798

98-
// Used by GISel for RV32 and RV64.
99+
let Predicates = [HasStdExtZalasr, IsRV32] in {
99100
def : PatLAQ<acquiring_load<atomic_load_nonext_32>, LW_AQ, i32>;
100101
def : PatLAQ<seq_cst_load<atomic_load_nonext_32>, LW_AQ, i32>;
101-
} // Predicates = [HasStdExtZalasr]
102+
} // Predicates = [HasStdExtZalasr, IsRV32]
102103

103104
let Predicates = [HasStdExtZalasr, IsRV64] in {
104105
def : PatLAQ<acquiring_load<atomic_load_asext_32>, LW_AQ, i64>;

0 commit comments

Comments
 (0)