LLVM: lib/Target/RISCV/RISCVMergeBaseOffset.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
21#include
22using namespace llvm;
23
24#define DEBUG_TYPE "riscv-merge-base-offset"
25#define RISCV_MERGE_BASE_OFFSET_NAME "RISC-V Merge Base Offset"
26namespace {
27
31
32public:
33 static char ID;
36
44
46
48
51 }
52
53 void getAnalysisUsage(AnalysisUsage &AU) const override {
56 }
57
58 StringRef getPassName() const override {
60 }
61};
62}
63
64char RISCVMergeBaseOffsetOpt::ID = 0;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
86 auto HiOpc = Hi.getOpcode();
87 if (HiOpc != RISCV::LUI && HiOpc != RISCV::AUIPC &&
88 HiOpc != RISCV::PseudoMovAddr)
89 return false;
90
92 unsigned ExpectedFlags =
95 return false;
96
99 return false;
100
101 if (HiOpc == RISCV::PseudoMovAddr) {
102
103
105 } else {
106 Register HiDestReg = Hi.getOperand(0).getReg();
107 if (->hasOneUse(HiDestReg))
108 return false;
109
110 Lo = &*MRI->use_instr_begin(HiDestReg);
111 if (Lo->getOpcode() != RISCV::ADDI)
112 return false;
113 }
114
116 if (HiOpc == RISCV::LUI || HiOpc == RISCV::PseudoMovAddr) {
120 return false;
121 } else {
122 assert(HiOpc == RISCV::AUIPC);
125 return false;
126 }
127
129 LLVM_DEBUG(dbgs() << " Found lowered global address: "
130 << *HiOp1.getGlobal() << "\n");
132 LLVM_DEBUG(dbgs() << " Found lowered basic address: "
133 << *HiOp1.getBlockAddress() << "\n");
134 } else if (HiOp1.isCPI()) {
135 LLVM_DEBUG(dbgs() << " Found lowered constant pool: " << HiOp1.getIndex()
136 << "\n");
137 }
138
139 return true;
140}
141
142
143
144
148
149
150
151
152 auto HiOpc = Hi.getOpcode();
153 if (HiOpc == RISCV::AUIPC && Hi.getOperand(1).isGlobal()) {
154 const GlobalValue *GV = Hi.getOperand(1).getGlobal();
158 return false;
159 }
160
161
162 Hi.getOperand(1).setOffset(Offset);
163 if (HiOpc != RISCV::AUIPC)
164 Lo.getOperand(2).setOffset(Offset);
165
166 Register LoOp0Reg = Lo.getOperand(0).getReg();
167 Register TailOp0Reg = Tail.getOperand(0).getReg();
168 MRI->constrainRegClass(LoOp0Reg, MRI->getRegClass(TailOp0Reg));
169 MRI->replaceRegWith(TailOp0Reg, LoOp0Reg);
170 Tail.eraseFromParent();
172 << " " << Hi << " " << Lo;);
173 return true;
174}
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196bool RISCVMergeBaseOffsetOpt::foldLargeOffset(MachineInstr &Hi,
197 MachineInstr &Lo,
198 MachineInstr &TailAdd,
200 assert((TailAdd.getOpcode() == RISCV::ADD) && "Expected ADD instruction!");
204
205
207 return false;
208
209 MachineInstr &OffsetTail = *MRI->getVRegDef(Reg);
210 auto OffsetTailOpc = OffsetTail.getOpcode();
211 if (OffsetTailOpc == RISCV::ADDI || OffsetTailOpc == RISCV::ADDIW) {
212
213
214 MachineOperand &AddiImmOp = OffsetTail.getOperand(2);
216 return false;
218 int64_t OffLo = AddiImmOp.getImm();
219
220
221 if (AddiReg == RISCV::X0) {
222 LLVM_DEBUG(dbgs() << " Offset Instrs: " << OffsetTail);
223 if (!foldOffset(Hi, Lo, TailAdd, OffLo))
224 return false;
226 return true;
227 }
228
229 MachineInstr &OffsetLui = *MRI->getVRegDef(AddiReg);
230 MachineOperand &LuiImmOp = OffsetLui.getOperand(1);
231 if (OffsetLui.getOpcode() != RISCV::LUI ||
234 return false;
237
238 if (!ST->is64Bit() || OffsetTailOpc == RISCV::ADDIW)
240
242 return false;
243 LLVM_DEBUG(dbgs() << " Offset Instrs: " << OffsetTail
244 << " " << OffsetLui);
245 if (!foldOffset(Hi, Lo, TailAdd, Offset))
246 return false;
249 return true;
250 } else if (OffsetTailOpc == RISCV::LUI) {
251
252
253 LLVM_DEBUG(dbgs() << " Offset Instr: " << OffsetTail);
255 if (!foldOffset(Hi, Lo, TailAdd, Offset))
256 return false;
258 return true;
259 }
260 return false;
261}
262
263
264
265
266
267
268
269
270
271
272
273
274bool RISCVMergeBaseOffsetOpt::foldShiftedOffset(MachineInstr &Hi,
275 MachineInstr &Lo,
276 MachineInstr &TailShXAdd,
279 TailShXAdd.getOpcode() == RISCV::SH2ADD ||
280 TailShXAdd.getOpcode() == RISCV::SH3ADD) &&
281 "Expected SHXADD instruction!");
282
284 return false;
285
286
288
289
290 if (!Rs1.isVirtual() || ->hasOneUse(Rs1))
291 return false;
292
293 MachineInstr &OffsetTail = *MRI->getVRegDef(Rs1);
294 if (OffsetTail.getOpcode() != RISCV::ADDI)
295 return false;
299 return false;
300
303
304 unsigned ShAmt;
305 switch (TailShXAdd.getOpcode()) {
307 case RISCV::SH1ADD: ShAmt = 1; break;
308 case RISCV::SH2ADD: ShAmt = 2; break;
309 case RISCV::SH3ADD: ShAmt = 3; break;
310 }
311
313
314 LLVM_DEBUG(dbgs() << " Offset Instr: " << OffsetTail);
315 if (!foldOffset(Hi, Lo, TailShXAdd, Offset))
316 return false;
318 return true;
319}
320
321bool RISCVMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi,
322 MachineInstr &Lo) {
323 Register DestReg = Lo.getOperand(0).getReg();
324
325
326
327
328 if (->hasOneUse(DestReg))
329 return false;
330
331
332 MachineInstr &Tail = *MRI->use_instr_begin(DestReg);
333 switch (Tail.getOpcode()) {
334 default:
335 LLVM_DEBUG(dbgs() << "Don't know how to get offset from this instr:"
337 break;
338 case RISCV::ADDI: {
339
340 int64_t Offset = Tail.getOperand(2).getImm();
341
342
343 Register TailDestReg = Tail.getOperand(0).getReg();
344 if (MRI->hasOneUse(TailDestReg)) {
345 MachineInstr &TailTail = *MRI->use_instr_begin(TailDestReg);
346 if (TailTail.getOpcode() == RISCV::ADDI) {
349 if (!foldOffset(Hi, Lo, TailTail, Offset))
350 return false;
351 Tail.eraseFromParent();
352 return true;
353 }
354 }
355
358 }
359 case RISCV::ADD:
360
361
362
363
364
365
366
367
368 return foldLargeOffset(Hi, Lo, Tail, DestReg);
369 case RISCV::SH1ADD:
370 case RISCV::SH2ADD:
371 case RISCV::SH3ADD:
372
373
374
375 return foldShiftedOffset(Hi, Lo, Tail, DestReg);
376 }
377
378 return false;
379}
380
381bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
382 MachineInstr &Lo) {
383 Register DestReg = Lo.getOperand(0).getReg();
384
385
386
387
388
389
390
391
392
393
394
395
396
397 std::optional<int64_t> CommonOffset;
398 DenseMap<const MachineInstr *, SmallVector>
399 InlineAsmMemoryOpIndexesMap;
400 for (const MachineInstr &UseMI : MRI->use_instructions(DestReg)) {
401 switch (UseMI.getOpcode()) {
402 default:
404 return false;
405 case RISCV::LB:
406 case RISCV::LH:
407 case RISCV::LH_INX:
408 case RISCV::LW:
409 case RISCV::LW_INX:
410 case RISCV::LBU:
411 case RISCV::LHU:
412 case RISCV::LWU:
413 case RISCV::LD:
414 case RISCV::LD_RV32:
415 case RISCV::FLH:
416 case RISCV::FLW:
417 case RISCV::FLD:
418 case RISCV::SB:
419 case RISCV::SH:
420 case RISCV::SH_INX:
421 case RISCV::SW:
422 case RISCV::SW_INX:
423 case RISCV::SD:
424 case RISCV::SD_RV32:
425 case RISCV::FSH:
426 case RISCV::FSW:
427 case RISCV::FSD: {
428 if (UseMI.getOperand(1).isFI())
429 return false;
430
431 if (DestReg == UseMI.getOperand(0).getReg())
432 return false;
434 "Expected base address use");
435
436 int64_t Offset = UseMI.getOperand(2).getImm();
437 if (CommonOffset && Offset != CommonOffset)
438 return false;
439 CommonOffset = Offset;
440 break;
441 }
442 case RISCV::INLINEASM:
443 case RISCV::INLINEASM_BR: {
444 SmallVector InlineAsmMemoryOpIndexes;
448 const MachineOperand &FlagsMO = UseMI.getOperand(I);
449
450 if (!FlagsMO.isImm())
451 continue;
452
453 const InlineAsm::Flag Flags(FlagsMO.getImm());
455
456
458
459
460 for (unsigned J = 0; J < NumOps; ++J) {
461 const MachineOperand &MO = UseMI.getOperand(I + 1 + J);
462 if (MO.isReg() && MO.getReg() == DestReg)
463 return false;
464 }
465 continue;
466 }
467
468
469
470 if (Flags.getMemoryConstraintID() == InlineAsm::ConstraintCode::A)
471 return false;
472
473 const MachineOperand &AddrMO = UseMI.getOperand(I + 1);
474 if (!AddrMO.isReg() || AddrMO.getReg() != DestReg)
475 continue;
476
477 const MachineOperand &OffsetMO = UseMI.getOperand(I + 2);
478 if (!OffsetMO.isImm())
479 continue;
480
481
483 if (CommonOffset && Offset != CommonOffset)
484 return false;
485 CommonOffset = Offset;
486 InlineAsmMemoryOpIndexes.push_back(I + 1);
487 }
488 InlineAsmMemoryOpIndexesMap.insert(
489 std::make_pair(&UseMI, InlineAsmMemoryOpIndexes));
490 break;
491 }
492 }
493 }
494
495
496
497
498
499 int64_t NewOffset = Hi.getOperand(1).getOffset() + *CommonOffset;
500
503
505 return false;
506
507 Hi.getOperand(1).setOffset(NewOffset);
508 MachineOperand &ImmOp = Lo.getOperand(2);
509 auto HiOpc = Hi.getOpcode();
510
511 if (HiOpc == RISCV::PseudoMovAddr) {
513 Hi.setDesc(TII->get(RISCV::LUI));
514 Hi.removeOperand(2);
515 }
516
517 if (HiOpc != RISCV::AUIPC)
519
520
521 for (MachineInstr &UseMI :
523 if (UseMI.getOpcode() == RISCV::INLINEASM ||
524 UseMI.getOpcode() == RISCV::INLINEASM_BR) {
525 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&UseMI];
526 for (unsigned I : InlineAsmMemoryOpIndexes) {
527 MachineOperand &MO = UseMI.getOperand(I + 1);
528 switch (ImmOp.getType()) {
532 break;
536 break;
540 break;
541 default:
543 break;
544 }
545 }
546 } else {
547 UseMI.removeOperand(2);
548 UseMI.addOperand(ImmOp);
549 }
550 }
551
552
553
555 return true;
556
557 MRI->replaceRegWith(Lo.getOperand(0).getReg(), Hi.getOperand(0).getReg());
558 Lo.eraseFromParent();
559 return true;
560}
561
562bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
564 return false;
565
567
568 bool MadeChange = false;
570 for (MachineBasicBlock &MBB : Fn) {
572 for (MachineInstr &Hi : MBB) {
573 MachineInstr *Lo = nullptr;
574 if (!detectFoldable(Hi, Lo))
575 continue;
576 MadeChange |= detectAndFoldOffset(Hi, *Lo);
577 MadeChange |= foldIntoMemoryOps(Hi, *Lo);
578 }
579 }
580
581 return MadeChange;
582}
583
584
586 return new RISCVMergeBaseOffsetOpt();
587}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
#define RISCV_MERGE_BASE_OFFSET_NAME
Definition RISCVMergeBaseOffset.cpp:25
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
LLVM_ABI TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
FunctionPass class - This class is used to implement most global optimizations.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this global belongs to.
Type * getValueType() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
LLVM_ABI void ChangeToMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
ChangeToMCSymbol - Replace this operand with a new MC symbol operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
LLVM_ABI void ChangeToBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
ChangeToBA - Replace this operand with a new block address operand.
const BlockAddress * getBlockAddress() const
void setOffset(int64_t Offset)
unsigned getTargetFlags() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
MCSymbol * getMCSymbol() const
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const RISCVInstrInfo * getInstrInfo() const override
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
FunctionPass * createRISCVMergeBaseOffsetOptPass()
Returns an instance of the Merge Base Offset Optimization pass.
Definition RISCVMergeBaseOffset.cpp:585
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.