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 bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,

76 bool tryConvertToMIPSLdStPair(MachineFunction *MF,

79

80

81

82

84 bool &MergeForward);

85

89

90

91 bool fixInvalidRegPairOp(MachineBasicBlock &MBB,

94 void splitLdSdIntoTwo(MachineBasicBlock &MBB,

96

97private:

99 MachineRegisterInfo *MRI;

100 const RISCVInstrInfo *TII;

101 const RISCVRegisterInfo *TRI;

102 LiveRegUnits ModifiedRegUnits, UsedRegUnits;

103};

104}

105

106char RISCVLoadStoreOpt::ID = 0;

108 false)

109

111 if (skipFunction(Fn.getFunction()))

112 return false;

114

115 bool MadeChange = false;

116 TII = Subtarget.getInstrInfo();

117 TRI = Subtarget.getRegisterInfo();

118 MRI = &Fn.getRegInfo();

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

120 ModifiedRegUnits.init(*TRI);

121 UsedRegUnits.init(*TRI);

122

123 if (Subtarget.useMIPSLoadStorePairs() || Subtarget.hasVendorXqcilsm()) {

124 for (MachineBasicBlock &MBB : Fn) {

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

126

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

128 MBBI != E;) {

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

130 tryToPairLdStInst(MBBI))

131 MadeChange = true;

132 else

133 ++MBBI;

134 }

135 }

136 }

137

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

139 for (auto &MBB : Fn) {

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

141 if (fixInvalidRegPairOp(MBB, MBBI)) {

142 MadeChange = true;

143

144 } else {

145 ++MBBI;

146 }

147 }

148 }

149 }

150

151 return MadeChange;

152}

153

154

155

157 MachineInstr &MI = *MBBI;

158

159

160 if (MI.hasOrderedMemoryRef())

161 return false;

162

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

164 return false;

165

166

168 bool MergeForward;

170 if (Paired != E) {

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

172 return true;

173 }

174 return false;

175}

176

177bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(

180 unsigned Opc = First->getOpcode();

181 if ((Opc != RISCV::LW && Opc != RISCV::SW) || Second->getOpcode() != Opc)

182 return false;

183

184 const auto &FirstOp1 = First->getOperand(1);

185 const auto &SecondOp1 = Second->getOperand(1);

186 const auto &FirstOp2 = First->getOperand(2);

187 const auto &SecondOp2 = Second->getOperand(2);

188

189

190 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||

191 !SecondOp2.isImm())

192 return false;

193

194 Register Base1 = FirstOp1.getReg();

195 Register Base2 = SecondOp1.getReg();

196

197 if (Base1 != Base2)

198 return false;

199

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

202

203 if (MMOAlign < Align(4))

204 return false;

205

206 auto &FirstOp0 = First->getOperand(0);

207 auto &SecondOp0 = Second->getOperand(0);

208

209 int64_t Off1 = FirstOp2.getImm();

210 int64_t Off2 = SecondOp2.getImm();

211

212 if (Off2 < Off1) {

215 }

216

217 Register StartReg = FirstOp0.getReg();

218 Register NextReg = SecondOp0.getReg();

219

220 if (StartReg == RISCV::X0 || NextReg == RISCV::X0)

221 return false;

222

223

224 if (Opc == RISCV::LW && (StartReg == Base1 || NextReg == Base1))

225 return false;

226

228 return false;

229

230 if (NextReg != StartReg + 1)

231 return false;

232

233 unsigned XqciOpc = (Opc == RISCV::LW) ? RISCV::QC_LWMI : RISCV::QC_SWMI;

234

237 auto NextRegState =

238 (Opc == RISCV::LW)

241

243 First->getDebugLoc() ? First->getDebugLoc() : Second->getDebugLoc();

244 MachineInstrBuilder MIB = BuildMI(*MF, DL, TII->get(XqciOpc));

245 MIB.addReg(StartReg, StartRegState)

250 .addReg(NextReg, NextRegState);

251

253 First->removeFromParent();

254 Second->removeFromParent();

255

256 return true;

257}

258

259bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(

262

263

264 unsigned PairOpc;

265 Align RequiredAlignment;

266 switch (First->getOpcode()) {

267 default:

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

269 case RISCV::SW:

270 PairOpc = RISCV::MIPS_SWP;

271 RequiredAlignment = Align(8);

272 break;

273 case RISCV::LW:

274 PairOpc = RISCV::MIPS_LWP;

275 RequiredAlignment = Align(8);

276 break;

277 case RISCV::SD:

278 PairOpc = RISCV::MIPS_SDP;

279 RequiredAlignment = Align(16);

280 break;

281 case RISCV::LD:

282 PairOpc = RISCV::MIPS_LDP;

283 RequiredAlignment = Align(16);

284 break;

285 }

286

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

289

290 if (MMOAlign < RequiredAlignment)

291 return false;

292

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

295 return false;

296

297 MachineInstrBuilder MIB = BuildMI(

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

299 TII->get(PairOpc));

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

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

305

307

308 First->removeFromParent();

309 Second->removeFromParent();

310

311 return true;

312}

313

314

315

316

317

318

319bool RISCVLoadStoreOpt::tryConvertToLdStPair(

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

322 const RISCVSubtarget &STI = MF->getSubtarget();

323

324

325 if (!STI.is64Bit() && STI.hasVendorXqcilsm())

326 return tryConvertToXqcilsmLdStPair(MF, First, Second);

327

328

329 return tryConvertToMIPSLdStPair(MF, First, Second);

330}

331

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

337 return true;

338

339 return false;

340}

341

342

343

344

345

346

347

350 bool &MergeForward) {

353 MachineInstr &FirstMI = *I;

355

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

361

362 MergeForward = false;

363

364

365

366 ModifiedRegUnits.clear();

367 UsedRegUnits.clear();

368

369

370 SmallVector<MachineInstr *, 4> MemInsns;

371

374 MachineInstr &MI = *MBBI;

375

376

377

378 if (MI.isTransient())

380

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

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

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

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

385

386 if (BaseReg == MIBaseReg) {

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

388 (Offset + OffsetStride != MIOffset)) {

392 continue;

393 }

394

395

396

397 if (MayLoad &&

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

402 continue;

403 }

404

405

406 if (!ModifiedRegUnits.available(BaseReg))

407 return E;

408

409

410

411

412

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

414 !(MI.mayLoad() &&

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

417

418 MergeForward = false;

420 }

421

422

423

424

425

426 if (!(MayLoad &&

428 mayAlias(FirstMI, MemInsns, AA)) {

429

431 MergeForward = true;

433 }

434 }

435

436

437 }

438 }

439

440

441

442 if (MI.isCall())

443 return E;

444

445

447

448

449

450 if (!ModifiedRegUnits.available(BaseReg))

451 return E;

452

453

454 if (MI.mayLoadOrStore())

456 }

457 return E;

458}

459

463 bool MergeForward) {

466

467

468

469

470 if (NextI == Paired)

472

473

474

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

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

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

480

481 if (!MergeForward)

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

483

484

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

486 if (!MergeForward) {

487

488

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

490 if (PairedRegOp.isKill()) {

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

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

494 break;

495 }

496 }

497 }

498 } else {

499

500

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

503 MI.clearRegisterKills(Reg, TRI);

504 }

505 }

506

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

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

510

511 if (!InsertAfter) {

513 Second = InsertionPoint;

514 } else {

516 First = InsertionPoint;

517 }

518

519 if (tryConvertToLdStPair(First, Second)) {

522 }

523

524 return NextI;

525}

526

527

528

529

530

532

533

534

535

536

537

538 if (First == RISCV::X0)

539 return Second == RISCV::X0;

540

541

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

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

544

545

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

547}

548

549void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &MBB,

551 bool IsLoad) {

552 MachineInstr *MI = &*MBBI;

554

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

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

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

561

562

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

564 int BaseOffset;

566 BaseOffset = OffsetOp.getImm();

567 else

568

569 BaseOffset = OffsetOp.getOffset();

570

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

572 MachineInstrBuilder MIB1, MIB2;

573

574

575 if (IsLoad) {

576

577

578

579

580

581

582

583

584

585 if (FirstReg == BaseReg) {

594

595 } else {

600

605 }

606

607 ++NumLD2LW;

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

609 } else {

611 FirstReg != SecondReg &&

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

616

620

621 ++NumSD2SW;

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

623 }

624

625

628 MIB2.addImm(BaseOffset + 4);

629 else if (OffsetOp.isGlobal())

635 else if (OffsetOp.isBlockAddress())

638

639

640

641

644

645

647}

648

649bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &MBB,

651 MachineInstr *MI = &*MBBI;

652 unsigned Opcode = MI->getOpcode();

653

654

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

656 return false;

657

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

659

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

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

664

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

666

667 splitLdSdIntoTwo(MBB, MBBI, IsLoad);

668 return true;

669 }

670

671

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

675

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

677

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

679

680

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

682 &RISCV::GPRPairRegClass);

683

685

686 if (IsLoad) {

687

690 } else {

691

693 }

694

698

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

700 << "\n");

701

702

704

705 return true;

706}

707

708

710 return new RISCVLoadStoreOpt();

711}

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!")

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

MachineBasicBlock MachineBasicBlock::iterator MBBI

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

const HexagonInstrInfo * TII

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.

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 TargetSubtargetInfo & getSubtarget() const

getSubtarget - Return the subtarget for which this machine code is being compiled.

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.

@ Implicit

Not emitted register (e.g. carry, or temporary result).

@ 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:709

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.

constexpr bool isShiftedUInt(uint64_t x)

Checks if a unsigned integer is an N bit number shifted left by S.

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.