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 (MRI->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() || MRI->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 (MRI->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

554 if (&Lo == &Hi)

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.