LLVM: lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

35

36using namespace llvm;

37

38#define DEBUG_TYPE "riscv-load-store-opt"

39#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"

40

41

42

45STATISTIC(NumLD2LW, "Number of LD instructions split back to LW");

46STATISTIC(NumSD2SW, "Number of SD instructions split back to SW");

47

48namespace {

49

51 static char ID;

53

55

56 MachineFunctionProperties getRequiredProperties() const override {

57 return MachineFunctionProperties().setNoVRegs();

58 }

59

60 void getAnalysisUsage(AnalysisUsage &AU) const override {

63 }

64

66

67

69

70

73

74

75

76

78 bool &MergeForward);

79

83

84

85 bool fixInvalidRegPairOp(MachineBasicBlock &MBB,

88 void splitLdSdIntoTwo(MachineBasicBlock &MBB,

90

91private:

93 MachineRegisterInfo *MRI;

94 const RISCVInstrInfo *TII;

95 const RISCVRegisterInfo *TRI;

96 LiveRegUnits ModifiedRegUnits, UsedRegUnits;

97};

98}

99

100char RISCVLoadStoreOpt::ID = 0;

102 false)

103

105 if (skipFunction(Fn.getFunction()))

106 return false;

108

109 bool MadeChange = false;

110 TII = Subtarget.getInstrInfo();

111 TRI = Subtarget.getRegisterInfo();

112 MRI = &Fn.getRegInfo();

113 AA = &getAnalysis().getAAResults();

114 ModifiedRegUnits.init(*TRI);

115 UsedRegUnits.init(*TRI);

116

117 if (Subtarget.useMIPSLoadStorePairs()) {

118 for (MachineBasicBlock &MBB : Fn) {

119 LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");

120

121 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();

122 MBBI != E;) {

123 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&

124 tryToPairLdStInst(MBBI))

125 MadeChange = true;

126 else

127 ++MBBI;

128 }

129 }

130 }

131

132 if (!Subtarget.is64Bit() && Subtarget.hasStdExtZilsd()) {

133 for (auto &MBB : Fn) {

134 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {

135 if (fixInvalidRegPairOp(MBB, MBBI)) {

136 MadeChange = true;

137

138 } else {

139 ++MBBI;

140 }

141 }

142 }

143 }

144

145 return MadeChange;

146}

147

148

149

151 MachineInstr &MI = *MBBI;

152

153

154 if (MI.hasOrderedMemoryRef())

155 return false;

156

157 if (TII->isLdStSafeToPair(MI, TRI))

158 return false;

159

160

162 bool MergeForward;

164 if (Paired != E) {

165 MBBI = mergePairedInsns(MBBI, Paired, MergeForward);

166 return true;

167 }

168 return false;

169}

170

171

172

173

174

175

176

177bool RISCVLoadStoreOpt::tryConvertToLdStPair(

179 unsigned PairOpc;

180 Align RequiredAlignment;

181 switch (First->getOpcode()) {

182 default:

183 llvm_unreachable("Unsupported load/store instruction for pairing");

184 case RISCV::SW:

185 PairOpc = RISCV::MIPS_SWP;

186 RequiredAlignment = Align(8);

187 break;

188 case RISCV::LW:

189 PairOpc = RISCV::MIPS_LWP;

190 RequiredAlignment = Align(8);

191 break;

192 case RISCV::SD:

193 PairOpc = RISCV::MIPS_SDP;

194 RequiredAlignment = Align(16);

195 break;

196 case RISCV::LD:

197 PairOpc = RISCV::MIPS_LDP;

198 RequiredAlignment = Align(16);

199 break;

200 }

201

202 MachineFunction *MF = First->getMF();

203 const MachineMemOperand *MMO = *First->memoperands_begin();

205

206 if (MMOAlign < RequiredAlignment)

207 return false;

208

209 int64_t Offset = First->getOperand(2).getImm();

211 return false;

212

213 MachineInstrBuilder MIB = BuildMI(

214 *MF, First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc(),

216 MIB.add(First->getOperand(0))

217 .add(Second->getOperand(0))

221

223

224 First->removeFromParent();

225 Second->removeFromParent();

226

227 return true;

228}

229

234 if (MIa.mayAlias(AA, *MIb, false))

235 return true;

236

237 return false;

238}

239

240

241

242

243

244

245

248 bool &MergeForward) {

251 MachineInstr &FirstMI = *I;

253

258 int64_t OffsetStride = (*FirstMI.memoperands_begin())->getSize().getValue();

259

260 MergeForward = false;

261

262

263

264 ModifiedRegUnits.clear();

265 UsedRegUnits.clear();

266

267

268 SmallVector<MachineInstr *, 4> MemInsns;

269

272 MachineInstr &MI = *MBBI;

273

274

275

276 if (MI.isTransient())

278

279 if (MI.getOpcode() == FirstMI.getOpcode() &&

280 TII->isLdStSafeToPair(MI, TRI)) {

281 Register MIBaseReg = MI.getOperand(1).getReg();

282 int64_t MIOffset = MI.getOperand(2).getImm();

283

284 if (BaseReg == MIBaseReg) {

285 if ((Offset != MIOffset + OffsetStride) &&

286 (Offset + OffsetStride != MIOffset)) {

290 continue;

291 }

292

293

294

295 if (MayLoad &&

296 TRI->isSuperOrSubRegisterEq(Reg, MI.getOperand(0).getReg())) {

300 continue;

301 }

302

303

304 if (!ModifiedRegUnits.available(BaseReg))

305 return E;

306

307

308

309

310

311 if (ModifiedRegUnits.available(MI.getOperand(0).getReg()) &&

312 !(MI.mayLoad() &&

313 !UsedRegUnits.available(MI.getOperand(0).getReg())) &&

315

316 MergeForward = false;

318 }

319

320

321

322

323

324 if (!(MayLoad &&

326 mayAlias(FirstMI, MemInsns, AA)) {

327

329 MergeForward = true;

331 }

332 }

333

334

335 }

336 }

337

338

339

340 if (MI.isCall())

341 return E;

342

343

345

346

347

348 if (!ModifiedRegUnits.available(BaseReg))

349 return E;

350

351

352 if (MI.mayLoadOrStore())

354 }

355 return E;

356}

357

361 bool MergeForward) {

364

365

366

367

368 if (NextI == Paired)

370

371

372

375 int Offset = I->getOperand(2).getImm();

376 int PairedOffset = Paired->getOperand(2).getImm();

377 bool InsertAfter = (Offset < PairedOffset) ^ MergeForward;

378

379 if (!MergeForward)

380 Paired->getOperand(1).setIsKill(false);

381

382

383 if (I->getOperand(0).isUse()) {

384 if (!MergeForward) {

385

386

387 MachineOperand &PairedRegOp = Paired->getOperand(0);

388 if (PairedRegOp.isKill()) {

389 for (auto It = std::next(I); It != Paired; ++It) {

390 if (It->readsRegister(PairedRegOp.getReg(), TRI)) {

392 break;

393 }

394 }

395 }

396 } else {

397

398

400 for (MachineInstr &MI : make_range(std::next(I), std::next(Paired)))

401 MI.clearRegisterKills(Reg, TRI);

402 }

403 }

404

405 MachineInstr *ToInsert = DeletionPoint->removeFromParent();

406 MachineBasicBlock &MBB = *InsertionPoint->getParent();

408

409 if (!InsertAfter) {

411 Second = InsertionPoint;

412 } else {

414 First = InsertionPoint;

415 }

416

417 if (tryConvertToLdStPair(First, Second)) {

420 }

421

422 return NextI;

423}

424

425

426

427

428

430

431

432

433

434

435

436 if (First == RISCV::X0)

437 return Second == RISCV::X0;

438

439

440 unsigned FirstNum = TRI->getEncodingValue(First);

441 unsigned SecondNum = TRI->getEncodingValue(Second);

442

443

444 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);

445}

446

447void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,

449 bool IsLoad) {

450 MachineInstr *MI = &*MBBI;

452

453 const MachineOperand &FirstOp = MI->getOperand(0);

454 const MachineOperand &SecondOp = MI->getOperand(1);

455 const MachineOperand &BaseOp = MI->getOperand(2);

459

460

461 const MachineOperand &OffsetOp = MI->getOperand(3);

462 int BaseOffset;

464 BaseOffset = OffsetOp.getImm();

465 else

466

467 BaseOffset = OffsetOp.getOffset();

468

469 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;

470 MachineInstrBuilder MIB1, MIB2;

471

472

473 if (IsLoad) {

474

475

476

477

478

479

480

481

482

483 if (FirstReg == BaseReg) {

492

493 } else {

498

503 }

504

505 ++NumLD2LW;

506 LLVM_DEBUG(dbgs() << "Split LD back to two LW instructions\n");

507 } else {

509 FirstReg != SecondReg &&

510 "First register and second register is impossible to be same register");

514

518

519 ++NumSD2SW;

520 LLVM_DEBUG(dbgs() << "Split SD back to two SW instructions\n");

521 }

522

523

526 MIB2.addImm(BaseOffset + 4);

527 else if (OffsetOp.isGlobal())

533 else if (OffsetOp.isBlockAddress())

536

537

538

539

542

543

545}

546

547bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &MBB,

549 MachineInstr *MI = &*MBBI;

550 unsigned Opcode = MI->getOpcode();

551

552

553 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)

554 return false;

555

556 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;

557

558 const MachineOperand &FirstOp = MI->getOperand(0);

559 const MachineOperand &SecondOp = MI->getOperand(1);

562

563 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {

564

565 splitLdSdIntoTwo(MBB, MBBI, IsLoad);

566 return true;

567 }

568

569

570 const MachineOperand &BaseOp = MI->getOperand(2);

573

574 const MachineOperand &OffsetOp = MI->getOperand(3);

575

576 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;

577

578

579 unsigned RegPair = TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,

580 &RISCV::GPRPairRegClass);

581

583

584 if (IsLoad) {

585

588 } else {

589

591 }

592

596

597 LLVM_DEBUG(dbgs() << "Converted pseudo to real instruction: " << *MIB

598 << "\n");

599

600

602

603 return true;

604}

605

606

608 return new RISCVLoadStoreOpt();

609}

unsigned const MachineRegisterInfo * MRI

static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)

static cl::opt< unsigned > LdStLimit("aarch64-load-store-scan-limit", cl::init(20), cl::Hidden)

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

const TargetInstrInfo & TII

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

MachineBasicBlock MachineBasicBlock::iterator MBBI

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

std::pair< Instruction::BinaryOps, Value * > OffsetOp

Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.

Register const TargetRegisterInfo * TRI

Promote Memory to Register

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

#define RISCV_LOAD_STORE_OPT_NAME

Definition RISCVLoadStoreOptimizer.cpp:39

static cl::opt< unsigned > LdStLimit("riscv-load-store-scan-limit", cl::init(128), cl::Hidden)

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

AnalysisUsage & addRequired()

FunctionPass class - This class is used to implement most global optimizations.

static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)

For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...

bool available(MCRegister Reg) const

Returns true if no part of physical register Reg is live.

void clear()

Clears the set.

const MCInstrDesc & get(unsigned Opcode) const

Return the machine instruction descriptor that corresponds to the specified instruction opcode.

LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)

Insert MI into the instruction list before I, possibly inside a bundle.

LLVM_ABI instr_iterator erase(instr_iterator I)

Remove an instruction from the instruction list and delete it.

iterator insertAfter(iterator I, MachineInstr *MI)

Insert MI into the instruction list after I.

MachineInstrBundleIterator< MachineInstr > iterator

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.

const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const

const MachineInstrBuilder & add(const MachineOperand &MO) const

const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const

const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const

const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const

Add a new virtual register operand.

const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const

Representation of each machine instruction.

unsigned getOpcode() const

Returns the opcode of this MachineInstr.

const MachineBasicBlock * getParent() const

LLVM_ABI bool mayAlias(BatchAAResults *AA, const MachineInstr &Other, bool UseTBAA) const

Returns true if this instruction's memory access aliases the memory access of Other.

bool mayLoad(QueryType Type=AnyInBundle) const

Return true if this instruction could possibly read memory.

mmo_iterator memoperands_begin() const

Access to memory operands of the instruction.

const MachineOperand & getOperand(unsigned i) const

LLVM_ABI Align getAlign() const

Return the minimum known alignment in bytes of the actual memory reference.

void setIsKill(bool Val=true)

Register getReg() const

getReg - Returns the register number.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

Abstract Attribute helper functions.

constexpr char Align[]

Key for Kernel::Arg::Metadata::mAlign.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ Define

Register definition.

initializer< Ty > init(const Ty &Val)

BaseReg

Stack frame base register. Bit 0 of FREInfo.Info.

This is an optimization pass for GlobalISel generic memory operations.

IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)

Increment It, then continue incrementing it while it points to a debug instruction.

FunctionPass * createRISCVLoadStoreOptPass()

Definition RISCVLoadStoreOptimizer.cpp:607

MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)

Builder interface. Specify how to create the initial instruction itself.

iterator_range< T > make_range(T x, T y)

Convenience function for iterating over sub-ranges.

unsigned getDeadRegState(bool B)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

FunctionAddr VTableAddr Count

constexpr bool isUInt(uint64_t x)

Checks if an unsigned integer fits into the given bit width.

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

unsigned getKillRegState(bool B)

AAResults AliasAnalysis

Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.

IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)

Decrement It, then continue decrementing it while it points to a debug instruction.