LLVM 18.0.0git
RISCVInstructionSelector.cpp
Go to the documentation of this file.
1//===-- RISCVInstructionSelector.cpp -----------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements the targeting of the InstructionSelector class for
10/// RISC-V.
11/// \todo This should be generated by TableGen.
12//===----------------------------------------------------------------------===//
13
16#include "RISCVSubtarget.h"
17#include "RISCVTargetMachine.h"
21#include "llvm/IR/IntrinsicsRISCV.h"
22#include "llvm/Support/Debug.h"
23
24#define DEBUG_TYPE "riscv-isel"
25
26using namespace llvm;
27
28#define GET_GLOBALISEL_PREDICATE_BITSET
29#include "RISCVGenGlobalISel.inc"
30#undef GET_GLOBALISEL_PREDICATE_BITSET
31
32namespace {
33
34class RISCVInstructionSelector : public InstructionSelector {
35public:
36 RISCVInstructionSelector(const RISCVTargetMachine &TM,
37 const RISCVSubtarget &STI,
38 const RISCVRegisterBankInfo &RBI);
39
40 bool select(MachineInstr &MI) override;
41 static const char *getName() { return DEBUG_TYPE; }
42
43private:
45 getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;
46
47 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
49 bool selectConstant(MachineInstr &MI, MachineIRBuilder &MIB,
51 bool selectSExtInreg(MachineInstr &MI, MachineIRBuilder &MIB) const;
52
53 bool earlySelectShift(unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
55
56 ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
57
58 // Custom renderers for tablegen
59 void renderNegImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
60 int OpIdx) const;
61
62 const RISCVSubtarget &STI;
63 const RISCVInstrInfo &TII;
65 const RISCVRegisterBankInfo &RBI;
66
67 // FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel
68 // uses "STI." in the code generated by TableGen. We need to unify the name of
69 // Subtarget variable.
70 const RISCVSubtarget *Subtarget = &STI;
71
72#define GET_GLOBALISEL_PREDICATES_DECL
73#include "RISCVGenGlobalISel.inc"
74#undef GET_GLOBALISEL_PREDICATES_DECL
75
76#define GET_GLOBALISEL_TEMPORARIES_DECL
77#include "RISCVGenGlobalISel.inc"
78#undef GET_GLOBALISEL_TEMPORARIES_DECL
79};
80
81} // end anonymous namespace
82
83#define GET_GLOBALISEL_IMPL
84#include "RISCVGenGlobalISel.inc"
85#undef GET_GLOBALISEL_IMPL
86
87RISCVInstructionSelector::RISCVInstructionSelector(
88 const RISCVTargetMachine &TM, const RISCVSubtarget &STI,
89 const RISCVRegisterBankInfo &RBI)
90 : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI),
91
93#include "RISCVGenGlobalISel.inc"
96#include "RISCVGenGlobalISel.inc"
98{
99}
100
102RISCVInstructionSelector::selectShiftMask(MachineOperand &Root) const {
103 // TODO: Also check if we are seeing the result of an AND operation which
104 // could be bypassed since we only check the lower log2(xlen) bits.
105 return {{[=](MachineInstrBuilder &MIB) { MIB.add(Root); }}};
106}
107
108// Tablegen doesn't allow us to write SRLIW/SRAIW/SLLIW patterns because the
109// immediate Operand has type XLenVT. GlobalISel wants it to be i32.
110bool RISCVInstructionSelector::earlySelectShift(
111 unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
112 const MachineRegisterInfo &MRI) {
113 if (!Subtarget->is64Bit())
114 return false;
115
116 LLT Ty = MRI.getType(I.getOperand(0).getReg());
117 if (!Ty.isScalar() || Ty.getSizeInBits() != 32)
118 return false;
119
120 std::optional<int64_t> CstVal =
121 getIConstantVRegSExtVal(I.getOperand(2).getReg(), MRI);
122 if (!CstVal || !isUInt<5>(*CstVal))
123 return false;
124
125 auto NewI = MIB.buildInstr(Opc, {I.getOperand(0).getReg()},
126 {I.getOperand(1).getReg()})
127 .addImm(*CstVal);
128 I.eraseFromParent();
129 return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
130}
131
132bool RISCVInstructionSelector::select(MachineInstr &MI) {
133 unsigned Opc = MI.getOpcode();
134 MachineBasicBlock &MBB = *MI.getParent();
137 MachineIRBuilder MIB(MI);
138
139 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
140 if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI) {
141 const Register DefReg = MI.getOperand(0).getReg();
142 const LLT DefTy = MRI.getType(DefReg);
143
144 const RegClassOrRegBank &RegClassOrBank =
145 MRI.getRegClassOrRegBank(DefReg);
146
147 const TargetRegisterClass *DefRC =
148 RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
149 if (!DefRC) {
150 if (!DefTy.isValid()) {
151 LLVM_DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n");
152 return false;
153 }
154
155 const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>();
156 DefRC = getRegClassForTypeOnBank(DefTy, RB);
157 if (!DefRC) {
158 LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
159 return false;
160 }
161 }
162
163 MI.setDesc(TII.get(TargetOpcode::PHI));
164 return RBI.constrainGenericRegister(DefReg, *DefRC, MRI);
165 }
166
167 // Certain non-generic instructions also need some special handling.
168 if (MI.isCopy())
169 return selectCopy(MI, MRI);
170
171 return true;
172 }
173
174 switch (Opc) {
175 case TargetOpcode::G_ADD: {
176 // Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
177 // type for RV64 in SelectionDAG. Manually select it here.
178 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
179 if (Subtarget->is64Bit() && Ty.isScalar() && Ty.getSizeInBits() == 32) {
180 std::optional<int64_t> CstVal =
181 getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
182 if (CstVal && isInt<12>(*CstVal)) {
183 auto NewI = MIB.buildInstr(RISCV::ADDIW, {MI.getOperand(0).getReg()},
184 {MI.getOperand(1).getReg()})
185 .addImm(*CstVal);
186 MI.eraseFromParent();
187 return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
188 }
189 }
190 break;
191 }
192 case TargetOpcode::G_SUB: {
193 // Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
194 // type for RV64 in SelectionDAG. Manually select it here.
195 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
196 if (Subtarget->is64Bit() && Ty.isScalar() && Ty.getSizeInBits() == 32) {
197 std::optional<int64_t> CstVal =
198 getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
199 if (CstVal && ((isInt<12>(*CstVal) && *CstVal != -2048) || *CstVal == 2048)) {
200 auto NewI = MIB.buildInstr(RISCV::ADDIW, {MI.getOperand(0).getReg()},
201 {MI.getOperand(1).getReg()})
202 .addImm(-*CstVal);
203 MI.eraseFromParent();
204 return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
205 }
206 }
207 break;
208 }
209 case TargetOpcode::G_ASHR:
210 if (earlySelectShift(RISCV::SRAIW, MI, MIB, MRI))
211 return true;
212 break;
213 case TargetOpcode::G_LSHR:
214 if (earlySelectShift(RISCV::SRLIW, MI, MIB, MRI))
215 return true;
216 break;
217 case TargetOpcode::G_SHL:
218 if (earlySelectShift(RISCV::SLLIW, MI, MIB, MRI))
219 return true;
220 break;
221 }
222
223 if (selectImpl(MI, *CoverageInfo))
224 return true;
225
226 switch (Opc) {
227 case TargetOpcode::G_ANYEXT:
228 case TargetOpcode::G_TRUNC:
229 return selectCopy(MI, MRI);
230 case TargetOpcode::G_CONSTANT:
231 return selectConstant(MI, MIB, MRI);
232 case TargetOpcode::G_BRCOND: {
233 // TODO: Fold with G_ICMP.
234 auto Bcc =
235 MIB.buildInstr(RISCV::BNE, {}, {MI.getOperand(0), Register(RISCV::X0)})
236 .addMBB(MI.getOperand(1).getMBB());
237 MI.eraseFromParent();
238 return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI);
239 }
240 case TargetOpcode::G_SEXT_INREG:
241 return selectSExtInreg(MI, MIB);
242 default:
243 return false;
244 }
245}
246
247void RISCVInstructionSelector::renderNegImm(MachineInstrBuilder &MIB,
248 const MachineInstr &MI,
249 int OpIdx) const {
250 assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
251 "Expected G_CONSTANT");
252 int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue();
253 MIB.addImm(-CstVal);
254}
255
256const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
257 LLT Ty, const RegisterBank &RB) const {
258 if (RB.getID() == RISCV::GPRRegBankID) {
259 if (Ty.getSizeInBits() <= 32 || (STI.is64Bit() && Ty.getSizeInBits() == 64))
260 return &RISCV::GPRRegClass;
261 }
262
263 // TODO: Non-GPR register classes.
264 return nullptr;
265}
266
267bool RISCVInstructionSelector::selectCopy(MachineInstr &MI,
268 MachineRegisterInfo &MRI) const {
269 Register DstReg = MI.getOperand(0).getReg();
270
271 if (DstReg.isPhysical())
272 return true;
273
274 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(
275 MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI));
276 assert(DstRC &&
277 "Register class not available for LLT, register bank combination");
278
279 // No need to constrain SrcReg. It will get constrained when
280 // we hit another of its uses or its defs.
281 // Copies do not have constraints.
282 if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
283 LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(MI.getOpcode())
284 << " operand\n");
285 return false;
286 }
287
288 MI.setDesc(TII.get(RISCV::COPY));
289 return true;
290}
291
292bool RISCVInstructionSelector::selectConstant(MachineInstr &MI,
293 MachineIRBuilder &MIB,
294 MachineRegisterInfo &MRI) const {
295 assert(MI.getOpcode() == TargetOpcode::G_CONSTANT);
296 Register FinalReg = MI.getOperand(0).getReg();
297 int64_t Imm = MI.getOperand(1).getCImm()->getSExtValue();
298
299 if (Imm == 0) {
300 MI.getOperand(1).ChangeToRegister(RISCV::X0, false);
301 RBI.constrainGenericRegister(FinalReg, RISCV::GPRRegClass, MRI);
302 MI.setDesc(TII.get(TargetOpcode::COPY));
303 return true;
304 }
305
307 RISCVMatInt::generateInstSeq(Imm, Subtarget->getFeatureBits());
308 unsigned NumInsts = Seq.size();
309 Register SrcReg = RISCV::X0;
310
311 for (unsigned i = 0; i < NumInsts; i++) {
312 Register DstReg = i < NumInsts - 1
313 ? MRI.createVirtualRegister(&RISCV::GPRRegClass)
314 : FinalReg;
315 const RISCVMatInt::Inst &I = Seq[i];
317
318 switch (I.getOpndKind()) {
319 case RISCVMatInt::Imm:
320 // clang-format off
321 Result = MIB.buildInstr(I.getOpcode())
322 .addDef(DstReg)
323 .addImm(I.getImm());
324 // clang-format on
325 break;
327 Result = MIB.buildInstr(I.getOpcode())
328 .addDef(DstReg)
329 .addReg(SrcReg)
330 .addReg(RISCV::X0);
331 break;
333 Result = MIB.buildInstr(I.getOpcode())
334 .addDef(DstReg)
335 .addReg(SrcReg)
336 .addReg(SrcReg);
337 break;
339 Result = MIB.buildInstr(I.getOpcode())
340 .addDef(DstReg)
341 .addReg(SrcReg)
342 .addImm(I.getImm());
343 break;
344 }
345
346 if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
347 return false;
348
349 SrcReg = DstReg;
350 }
351
352 MI.eraseFromParent();
353 return true;
354}
355
356bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,
357 MachineIRBuilder &MIB) const {
358 if (!STI.isRV64())
359 return false;
360
361 const MachineOperand &Size = MI.getOperand(2);
362 // Only Size == 32 (i.e. shift by 32 bits) is acceptable at this point.
363 if (!Size.isImm() || Size.getImm() != 32)
364 return false;
365
366 const MachineOperand &Src = MI.getOperand(1);
367 const MachineOperand &Dst = MI.getOperand(0);
368 // addiw rd, rs, 0 (i.e. sext.w rd, rs)
369 MachineInstr *NewMI =
370 MIB.buildInstr(RISCV::ADDIW, {Dst.getReg()}, {Src.getReg()}).addImm(0U);
371
372 if (!constrainSelectedInstRegOperands(*NewMI, TII, TRI, RBI))
373 return false;
374
375 MI.eraseFromParent();
376 return true;
377}
378
379namespace llvm {
382 RISCVSubtarget &Subtarget,
384 return new RISCVInstructionSelector(TM, Subtarget, RBI);
385}
386} // end namespace llvm
unsigned const MachineRegisterInfo * MRI
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
MachineBasicBlock & MBB
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Size
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
This file declares the MachineIRBuilder class.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const char LLVMTargetMachineRef TM
static StringRef getName(Value *V)
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
This file declares the targeting of the RegisterBankInfo class for RISC-V.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::optional< SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > > ComplexRendererFns
virtual bool select(MachineInstr &I)=0
Select the (possibly generic) instruction I to only use target-specific opcodes.
constexpr bool isScalar() const
Definition: LowLevelType.h:139
constexpr bool isValid() const
Definition: LowLevelType.h:137
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:175
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
Definition: MachineInstr.h:68
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
A discriminated union of two or more pointer types, with the discriminator in the low bit of the poin...
Definition: PointerUnion.h:118
T get() const
Returns the value of the specified pointer type.
Definition: PointerUnion.h:155
T dyn_cast() const
Returns the current pointer if it is of the specified pointer type, otherwise returns null.
Definition: PointerUnion.h:162
This class provides the information for the target register banks.
This class implements the register bank concept.
Definition: RegisterBank.h:28
unsigned getID() const
Get the identifier of this register bank.
Definition: RegisterBank.h:46
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition: Register.h:95
size_t size() const
Definition: SmallVector.h:91
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
InstSeq generateInstSeq(int64_t Val, const FeatureBitset &ActiveFeatures)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
Definition: Utils.cpp:152
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Definition: TargetOpcodes.h:30
std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
Definition: Utils.cpp:304
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
InstructionSelector * createRISCVInstructionSelector(const RISCVTargetMachine &TM, RISCVSubtarget &Subtarget, RISCVRegisterBankInfo &RBI)