LLVM: lib/Target/ARM/Thumb2SizeReduction.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

37#include

38#include

39#include

40#include

41#include

42

43using namespace llvm;

44

45#define DEBUG_TYPE "thumb2-reduce-size"

46#define THUMB2_SIZE_REDUCE_NAME "Thumb2 instruction size reduce pass"

47

48STATISTIC(NumNarrows, "Number of 32-bit instrs reduced to 16-bit ones");

49STATISTIC(Num2Addrs, "Number of 32-bit instrs reduced to 2addr 16-bit ones");

50STATISTIC(NumLdSts, "Number of 32-bit load / store reduced to 16-bit ones");

51

58

59namespace {

60

61

62

63 struct ReduceEntry {

64 uint16_t WideOpc;

65 uint16_t NarrowOpc1;

66 uint16_t NarrowOpc2;

67 uint8_t Imm1Limit;

68 uint8_t Imm2Limit;

69 unsigned LowRegs1 : 1;

70 unsigned LowRegs2 : 1;

71 unsigned PredCC1 : 2;

72

73

74 unsigned PredCC2 : 2;

75 unsigned PartFlag : 1;

76 unsigned Special : 1;

77 unsigned AvoidMovs: 1;

78 };

79

80 static const ReduceEntry ReduceTable[] = {

81

82 { ARM::t2ADCrr, 0, ARM::tADC, 0, 0, 0, 1, 0,0, 0,0,0 },

83 { ARM::t2ADDri, ARM::tADDi3, ARM::tADDi8, 3, 8, 1, 1, 0,0, 0,1,0 },

84 { ARM::t2ADDrr, ARM::tADDrr, ARM::tADDhirr, 0, 0, 1, 0, 0,1, 0,0,0 },

85 { ARM::t2ADDSri,ARM::tADDi3, ARM::tADDi8, 3, 8, 1, 1, 2,2, 0,1,0 },

86 { ARM::t2ADDSrr,ARM::tADDrr, 0, 0, 0, 1, 0, 2,0, 0,1,0 },

87 { ARM::t2ANDrr, 0, ARM::tAND, 0, 0, 0, 1, 0,0, 1,0,0 },

88 { ARM::t2ASRri, ARM::tASRri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },

89 { ARM::t2ASRrr, 0, ARM::tASRrr, 0, 0, 0, 1, 0,0, 1,0,1 },

90 { ARM::t2BICrr, 0, ARM::tBIC, 0, 0, 0, 1, 0,0, 1,0,0 },

91

92

93 { ARM::t2CMNzrr, ARM::tCMNz, 0, 0, 0, 1, 0, 2,0, 0,0,0 },

94 { ARM::t2CMPri, ARM::tCMPi8, 0, 8, 0, 1, 0, 2,0, 0,0,0 },

95 { ARM::t2CMPrr, ARM::tCMPhir, 0, 0, 0, 0, 0, 2,0, 0,1,0 },

96 { ARM::t2EORrr, 0, ARM::tEOR, 0, 0, 0, 1, 0,0, 1,0,0 },

97

98

99 { ARM::t2LSLri, ARM::tLSLri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },

100 { ARM::t2LSLrr, 0, ARM::tLSLrr, 0, 0, 0, 1, 0,0, 1,0,1 },

101 { ARM::t2LSRri, ARM::tLSRri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },

102 { ARM::t2LSRrr, 0, ARM::tLSRrr, 0, 0, 0, 1, 0,0, 1,0,1 },

103 { ARM::t2MOVi, ARM::tMOVi8, 0, 8, 0, 1, 0, 0,0, 1,0,0 },

104 { ARM::t2MOVi16,ARM::tMOVi8, 0, 8, 0, 1, 0, 0,0, 1,1,0 },

105

106 { ARM::t2MOVr,ARM::tMOVr, 0, 0, 0, 0, 0, 1,0, 0,0,0 },

107 { ARM::t2MUL, 0, ARM::tMUL, 0, 0, 0, 1, 0,0, 1,0,0 },

108 { ARM::t2MVNr, ARM::tMVN, 0, 0, 0, 1, 0, 0,0, 0,0,0 },

109 { ARM::t2ORRrr, 0, ARM::tORR, 0, 0, 0, 1, 0,0, 1,0,0 },

110 { ARM::t2REV, ARM::tREV, 0, 0, 0, 1, 0, 1,0, 0,0,0 },

111 { ARM::t2REV16, ARM::tREV16, 0, 0, 0, 1, 0, 1,0, 0,0,0 },

112 { ARM::t2REVSH, ARM::tREVSH, 0, 0, 0, 1, 0, 1,0, 0,0,0 },

113 { ARM::t2RORrr, 0, ARM::tROR, 0, 0, 0, 1, 0,0, 1,0,0 },

114 { ARM::t2RSBri, ARM::tRSB, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

115 { ARM::t2RSBSri,ARM::tRSB, 0, 0, 0, 1, 0, 2,0, 0,1,0 },

116 { ARM::t2SBCrr, 0, ARM::tSBC, 0, 0, 0, 1, 0,0, 0,0,0 },

117 { ARM::t2SUBri, ARM::tSUBi3, ARM::tSUBi8, 3, 8, 1, 1, 0,0, 0,0,0 },

118 { ARM::t2SUBrr, ARM::tSUBrr, 0, 0, 0, 1, 0, 0,0, 0,0,0 },

119 { ARM::t2SUBSri,ARM::tSUBi3, ARM::tSUBi8, 3, 8, 1, 1, 2,2, 0,0,0 },

120 { ARM::t2SUBSrr,ARM::tSUBrr, 0, 0, 0, 1, 0, 2,0, 0,0,0 },

121 { ARM::t2SXTB, ARM::tSXTB, 0, 0, 0, 1, 0, 1,0, 0,1,0 },

122 { ARM::t2SXTH, ARM::tSXTH, 0, 0, 0, 1, 0, 1,0, 0,1,0 },

123 { ARM::t2TEQrr, ARM::tEOR, 0, 0, 0, 1, 0, 2,0, 0,1,0 },

124 { ARM::t2TSTrr, ARM::tTST, 0, 0, 0, 1, 0, 2,0, 0,0,0 },

125 { ARM::t2UXTB, ARM::tUXTB, 0, 0, 0, 1, 0, 1,0, 0,1,0 },

126 { ARM::t2UXTH, ARM::tUXTH, 0, 0, 0, 1, 0, 1,0, 0,1,0 },

127

128

129

130 { ARM::t2LDRi12,ARM::tLDRi, ARM::tLDRspi, 5, 8, 1, 0, 0,0, 0,1,0 },

131 { ARM::t2LDRs, ARM::tLDRr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

132 { ARM::t2LDRBi12,ARM::tLDRBi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },

133 { ARM::t2LDRBs, ARM::tLDRBr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

134 { ARM::t2LDRHi12,ARM::tLDRHi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },

135 { ARM::t2LDRHs, ARM::tLDRHr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

136 { ARM::t2LDRSBs,ARM::tLDRSB, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

137 { ARM::t2LDRSHs,ARM::tLDRSH, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

138 { ARM::t2LDR_POST,ARM::tLDMIA_UPD,0, 0, 0, 1, 0, 0,0, 0,1,0 },

139 { ARM::t2STRi12,ARM::tSTRi, ARM::tSTRspi, 5, 8, 1, 0, 0,0, 0,1,0 },

140 { ARM::t2STRs, ARM::tSTRr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

141 { ARM::t2STRBi12,ARM::tSTRBi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },

142 { ARM::t2STRBs, ARM::tSTRBr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

143 { ARM::t2STRHi12,ARM::tSTRHi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },

144 { ARM::t2STRHs, ARM::tSTRHr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },

145 { ARM::t2STR_POST,ARM::tSTMIA_UPD,0, 0, 0, 1, 0, 0,0, 0,1,0 },

146

147 { ARM::t2LDMIA, ARM::tLDMIA, 0, 0, 0, 1, 1, 1,1, 0,1,0 },

148 { ARM::t2LDMIA_RET,0, ARM::tPOP_RET, 0, 0, 1, 1, 1,1, 0,1,0 },

149 { ARM::t2LDMIA_UPD,ARM::tLDMIA_UPD,ARM::tPOP,0, 0, 1, 1, 1,1, 0,1,0 },

150

151

152

153 { ARM::t2STMIA, ARM::tSTMIA_UPD, 0, 0, 0, 1, 1, 1,1, 0,1,0 },

154 { ARM::t2STMIA_UPD,ARM::tSTMIA_UPD, 0, 0, 0, 1, 1, 1,1, 0,1,0 },

155 { ARM::t2STMDB_UPD, 0, ARM::tPUSH, 0, 0, 1, 1, 1,1, 0,1,0 }

156 };

157

159 public:

160 static char ID;

161

162 const Thumb2InstrInfo *TII;

163 const ARMSubtarget *STI;

164

165 Thumb2SizeReduce(std::function<bool(const Function &)> Ftor = nullptr);

166

167 bool runOnMachineFunction(MachineFunction &MF) override;

168

169 MachineFunctionProperties getRequiredProperties() const override {

170 return MachineFunctionProperties().setNoVRegs();

171 }

172

173 StringRef getPassName() const override {

175 }

176

177 private:

178

179 DenseMap<unsigned, unsigned> ReduceOpcodeMap;

180

181 bool canAddPseudoFlagDep(MachineInstr *Use, bool IsSelfLoop);

182

183 bool VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,

185 bool LiveCPSR, bool &HasCC, bool &CCDead);

186

187 bool ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,

188 const ReduceEntry &Entry);

189

190 bool ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,

191 const ReduceEntry &Entry, bool LiveCPSR, bool IsSelfLoop);

192

193

194

195 bool ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,

196 const ReduceEntry &Entry, bool LiveCPSR,

197 bool IsSelfLoop);

198

199

200

201 bool ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,

202 const ReduceEntry &Entry, bool LiveCPSR,

203 bool IsSelfLoop);

204

205

206 bool ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI, bool LiveCPSR,

207 bool IsSelfLoop, bool SkipPrologueEpilogue);

208

209

210 bool ReduceMBB(MachineBasicBlock &MBB, bool SkipPrologueEpilogue);

211

212 bool OptimizeSize;

213 bool MinimizeSize;

214

215

216 MachineInstr *CPSRDef;

217

218

219 bool HighLatencyCPSR;

220

221 struct MBBInfo {

222

223 bool HighLatencyCPSR = false;

224

225 bool Visited = false;

226

227 MBBInfo() = default;

228 };

229

231

232 std::function<bool(const Function &)> PredicateFtor;

233 };

234

235 char Thumb2SizeReduce::ID = 0;

236

237}

238

240 false)

241

244 OptimizeSize = MinimizeSize = false;

245 for (unsigned i = 0, e = std::size(ReduceTable); i != e; ++i) {

246 unsigned FromOpc = ReduceTable[i].WideOpc;

247 if (!ReduceOpcodeMap.insert(std::make_pair(FromOpc, i)).second)

249 }

250}

251

255

256

258 switch(Def->getOpcode()) {

259 case ARM::FMSTAT:

260 case ARM::tMUL:

261 return true;

262 }

263 return false;

264}

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283bool

284Thumb2SizeReduce::canAddPseudoFlagDep(MachineInstr *Use, bool FirstInSelfLoop) {

285

286 if (MinimizeSize || !STI->avoidCPSRPartialUpdate())

287 return false;

288

289 if (!CPSRDef)

290

291

292 return HighLatencyCPSR || FirstInSelfLoop;

293

294 SmallSet<unsigned, 2> Defs;

295 for (const MachineOperand &MO : CPSRDef->operands()) {

296 if (!MO.isReg() || MO.isUndef() || MO.isUse())

297 continue;

299 if (Reg == 0 || Reg == ARM::CPSR)

300 continue;

302 }

303

304 for (const MachineOperand &MO : Use->operands()) {

305 if (!MO.isReg() || MO.isUndef() || MO.isDef())

306 continue;

309 return false;

310 }

311

312

313 if (HighLatencyCPSR)

314 return true;

315

316

317

318 if (Use->getOpcode() == ARM::t2MOVi ||

319 Use->getOpcode() == ARM::t2MOVi16)

320 return false;

321

322

323 return true;

324}

325

326bool

327Thumb2SizeReduce::VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,

329 bool LiveCPSR, bool &HasCC, bool &CCDead) {

330 if ((is2Addr && Entry.PredCC2 == 0) ||

331 (!is2Addr && Entry.PredCC1 == 0)) {

333

334 if (!HasCC) {

335

336

337

338 if (!LiveCPSR) {

339 HasCC = true;

340 CCDead = true;

341 return true;

342 }

343 return false;

344 }

345 } else {

346

347 if (HasCC)

348 return false;

349 }

350 } else if ((is2Addr && Entry.PredCC2 == 2) ||

351 (!is2Addr && Entry.PredCC1 == 2)) {

352

353 if (HasCC)

354 return true;

355

356

358 return false;

359 HasCC = true;

360 } else {

361

362 if (HasCC)

363 return false;

364 }

365

366 return true;

367}

368

370 unsigned Opc = MI->getOpcode();

371 bool isPCOk = (Opc == ARM::t2LDMIA_RET || Opc == ARM::t2LDMIA_UPD);

372 bool isLROk = (Opc == ARM::t2STMDB_UPD);

373 bool isSPOk = isPCOk || isLROk;

374 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {

377 continue;

379 if (Reg == 0 || Reg == ARM::CPSR)

380 continue;

381 if (isPCOk && Reg == ARM::PC)

382 continue;

383 if (isLROk && Reg == ARM::LR)

384 continue;

385 if (Reg == ARM::SP) {

386 if (isSPOk)

387 continue;

388 if (i == 1 && (Opc == ARM::t2LDRi12 || Opc == ARM::t2STRi12))

389

390 continue;

391 }

393 return false;

394 }

395 return true;

396}

397

398bool

399Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,

400 const ReduceEntry &Entry) {

402 return false;

403

404 unsigned Scale = 1;

405 bool HasImmOffset = false;

406 bool HasShift = false;

407 bool HasOffReg = true;

408 bool isLdStMul = false;

409 unsigned Opc = Entry.NarrowOpc1;

410 unsigned OpNum = 3;

411 uint8_t ImmLimit = Entry.Imm1Limit;

412

413 switch (Entry.WideOpc) {

414 default:

416 case ARM::t2LDRi12:

417 case ARM::t2STRi12:

418 if (MI->getOperand(1).getReg() == ARM::SP) {

420 ImmLimit = Entry.Imm2Limit;

421 }

422

423 Scale = 4;

424 HasImmOffset = true;

425 HasOffReg = false;

426 break;

427 case ARM::t2LDRBi12:

428 case ARM::t2STRBi12:

429 HasImmOffset = true;

430 HasOffReg = false;

431 break;

432 case ARM::t2LDRHi12:

433 case ARM::t2STRHi12:

434 Scale = 2;

435 HasImmOffset = true;

436 HasOffReg = false;

437 break;

438 case ARM::t2LDRs:

439 case ARM::t2LDRBs:

440 case ARM::t2LDRHs:

441 case ARM::t2LDRSBs:

442 case ARM::t2LDRSHs:

443 case ARM::t2STRs:

444 case ARM::t2STRBs:

445 case ARM::t2STRHs:

446 HasShift = true;

447 OpNum = 4;

448 break;

449 case ARM::t2LDR_POST:

450 case ARM::t2STR_POST: {

451 if (!MinimizeSize)

452 return false;

453

454 if (MI->hasOneMemOperand() ||

455 (*MI->memoperands_begin())->getAlign() < Align(4))

456 return false;

457

458

459

460

461 bool IsStore = Entry.WideOpc == ARM::t2STR_POST;

462 Register Rt = MI->getOperand(IsStore ? 1 : 0).getReg();

463 Register Rn = MI->getOperand(IsStore ? 0 : 1).getReg();

464 unsigned Offset = MI->getOperand(3).getImm();

465 unsigned PredImm = MI->getOperand(4).getImm();

466 Register PredReg = MI->getOperand(5).getReg();

469

471 return false;

472

473

481

482

484

485

487

488

489 MI->eraseFromBundle();

490 ++NumLdSts;

491 return true;

492 }

493 case ARM::t2LDMIA: {

496

497

498

499 bool isOK = false;

500 for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 3)) {

501 if (MO.getReg() == BaseReg) {

502 isOK = true;

503 break;

504 }

505 }

506

507 if (!isOK)

508 return false;

509

510 OpNum = 0;

511 isLdStMul = true;

512 break;

513 }

514 case ARM::t2STMIA: {

515

516

517

518 if (MI->getOperand(0).isKill())

519 return false;

520

521

522

523

526 if (MO.getReg() == BaseReg)

527 return false;

528

529 break;

530 }

531 case ARM::t2LDMIA_RET: {

533 if (BaseReg != ARM::SP)

534 return false;

535 Opc = Entry.NarrowOpc2;

536 OpNum = 2;

537 isLdStMul = true;

538 break;

539 }

540 case ARM::t2LDMIA_UPD:

541 case ARM::t2STMIA_UPD:

542 case ARM::t2STMDB_UPD: {

543 OpNum = 0;

544

546 if (BaseReg == ARM::SP &&

547 (Entry.WideOpc == ARM::t2LDMIA_UPD ||

548 Entry.WideOpc == ARM::t2STMDB_UPD)) {

549 Opc = Entry.NarrowOpc2;

550 OpNum = 2;

552 (Entry.WideOpc != ARM::t2LDMIA_UPD &&

553 Entry.WideOpc != ARM::t2STMIA_UPD)) {

554 return false;

555 }

556

557 isLdStMul = true;

558 break;

559 }

560 }

561

562 unsigned OffsetReg = 0;

563 bool OffsetKill = false;

564 bool OffsetInternal = false;

565 if (HasShift) {

566 OffsetReg = MI->getOperand(2).getReg();

567 OffsetKill = MI->getOperand(2).isKill();

568 OffsetInternal = MI->getOperand(2).isInternalRead();

569

570 if (MI->getOperand(3).getImm())

571

572 return false;

573 }

574

575 unsigned OffsetImm = 0;

576 if (HasImmOffset) {

577 OffsetImm = MI->getOperand(2).getImm();

578 unsigned MaxOffset = ((1 << ImmLimit) - 1) * Scale;

579

580 if ((OffsetImm & (Scale - 1)) || OffsetImm > MaxOffset)

581

582 return false;

583 }

584

585

588

589

590

591 if (Entry.WideOpc == ARM::t2STMIA)

593

594 if (!isLdStMul) {

595 MIB.add(MI->getOperand(0));

596 MIB.add(MI->getOperand(1));

597

598 if (HasImmOffset)

599 MIB.addImm(OffsetImm / Scale);

600

601 assert((!HasShift || OffsetReg) && "Invalid so_reg load / store address!");

602

603 if (HasOffReg)

606 }

607

608

609 for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), OpNum))

610 MIB.add(MO);

611

612

614

615

617

619 << " to 16-bit: " << *MIB);

620

622 ++NumLdSts;

623 return true;

624}

625

626bool

627Thumb2SizeReduce::ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,

628 const ReduceEntry &Entry,

629 bool LiveCPSR, bool IsSelfLoop) {

630 unsigned Opc = MI->getOpcode();

631 if (Opc == ARM::t2ADDri) {

632

633

634 if (MI->getOperand(1).getReg() != ARM::SP) {

635 if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))

636 return true;

637 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

638 }

639

640 unsigned Imm = MI->getOperand(2).getImm();

641

642

643

644 if (Imm & 3 || Imm > 1020)

645 return false;

647 return false;

648 if (MI->getOperand(3).getImm() != ARMCC::AL)

649 return false;

650 const MCInstrDesc &MCID = MI->getDesc();

652 MI->getOperand(MCID.getNumOperands()-1).getReg() == ARM::CPSR)

653 return false;

654

655 MachineInstrBuilder MIB =

657 TII->get(ARM::tADDrSPi))

658 .add(MI->getOperand(0))

659 .add(MI->getOperand(1))

660 .addImm(Imm / 4)

662

663

665

667 << " to 16-bit: " << *MIB);

668

670 ++NumNarrows;

671 return true;

672 }

673

675 return false;

676

677 if (MI->mayLoadOrStore())

678 return ReduceLoadStore(MBB, MI, Entry);

679

680 switch (Opc) {

681 default: break;

682 case ARM::t2ADDSri:

683 case ARM::t2ADDSrr: {

686 switch (Opc) {

687 default: break;

688 case ARM::t2ADDSri:

689 if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))

690 return true;

691 [[fallthrough]];

692 case ARM::t2ADDSrr:

693 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

694 }

695 }

696 break;

697 }

698 case ARM::t2RSBri:

699 case ARM::t2RSBSri:

700 case ARM::t2SXTB:

701 case ARM::t2SXTH:

702 case ARM::t2UXTB:

703 case ARM::t2UXTH:

704 if (MI->getOperand(2).getImm() == 0)

705 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

706 break;

707 case ARM::t2MOVi16:

708

709

710 if (MI->getOperand(1).isImm())

711 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

712 break;

713 case ARM::t2CMPrr: {

714

715

716

717

718

719 static const ReduceEntry NarrowEntry =

720 { ARM::t2CMPrr,ARM::tCMPr, 0, 0, 0, 1, 1,2, 0, 0,1,0 };

721 if (ReduceToNarrow(MBB, MI, NarrowEntry, LiveCPSR, IsSelfLoop))

722 return true;

723 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

724 }

725 case ARM::t2TEQrr: {

727

729 break;

730

731

732 if (MI->getOperand(0).isKill())

733 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

734 }

735 }

736 return false;

737}

738

739bool

740Thumb2SizeReduce::ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,

741 const ReduceEntry &Entry,

742 bool LiveCPSR, bool IsSelfLoop) {

744 return false;

745

746 if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())

747

748

749 return false;

750

751 Register Reg0 = MI->getOperand(0).getReg();

752 Register Reg1 = MI->getOperand(1).getReg();

753

754 if (MI->getOpcode() == ARM::t2MUL) {

755

756 if (!MinimizeSize && STI->avoidMULS())

757 return false;

758 Register Reg2 = MI->getOperand(2).getReg();

759

762 return false;

763 if (Reg0 != Reg2) {

764

765

766 if (Reg1 != Reg0)

767 return false;

768

770 if (!CommutedMI)

771 return false;

772 }

773 } else if (Reg0 != Reg1) {

774

775 unsigned CommOpIdx1 = 1;

778 MI->getOperand(CommOpIdx2).getReg() != Reg0)

779 return false;

780 MachineInstr *CommutedMI =

782 if (!CommutedMI)

783 return false;

784 }

786 return false;

787 if (Entry.Imm2Limit) {

788 unsigned Imm = MI->getOperand(2).getImm();

789 unsigned Limit = (1 << Entry.Imm2Limit) - 1;

790 if (Imm > Limit)

791 return false;

792 } else {

793 Register Reg2 = MI->getOperand(2).getReg();

795 return false;

796 }

797

798

799 const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc2);

802 bool SkipPred = false;

805

806 return false;

807 } else {

809 }

810

811 bool HasCC = false;

812 bool CCDead = false;

813 const MCInstrDesc &MCID = MI->getDesc();

816 HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);

817 if (HasCC && MI->getOperand(NumOps-1).isDead())

818 CCDead = true;

819 }

820 if (!VerifyPredAndCC(MI, Entry, true, Pred, LiveCPSR, HasCC, CCDead))

821 return false;

822

823

824

826 canAddPseudoFlagDep(MI, IsSelfLoop))

827 return false;

828

829

831 MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);

832 MIB.add(MI->getOperand(0));

835

836

838 for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {

839 if (i < NumOps && MCID.operands()[i].isOptionalDef())

840 continue;

841 if (SkipPred && MCID.operands()[i].isPredicate())

842 continue;

843 MIB.add(MI->getOperand(i));

844 }

845

846

848

850 << " to 16-bit: " << *MIB);

851

853 ++Num2Addrs;

854 return true;

855}

856

857bool

858Thumb2SizeReduce::ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,

859 const ReduceEntry &Entry,

860 bool LiveCPSR, bool IsSelfLoop) {

862 return false;

863

864 if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())

865

866

867 return false;

868

869 unsigned Limit = ~0U;

870 if (Entry.Imm1Limit)

871 Limit = (1 << Entry.Imm1Limit) - 1;

872

873 const MCInstrDesc &MCID = MI->getDesc();

874 for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {

875 if (MCID.operands()[i].isPredicate())

876 continue;

877 const MachineOperand &MO = MI->getOperand(i);

878 if (MO.isReg()) {

880 if (Reg || Reg == ARM::CPSR)

881 continue;

883 return false;

884 } else if (MO.isImm() && !MCID.operands()[i].isPredicate()) {

885 if (((unsigned)MO.getImm()) > Limit)

886 return false;

887 }

888 }

889

890

891 const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc1);

894 bool SkipPred = false;

897

898 return false;

899 } else {

901 }

902

903 bool HasCC = false;

904 bool CCDead = false;

907 HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);

908 if (HasCC && MI->getOperand(NumOps-1).isDead())

909 CCDead = true;

910 }

911 if (!VerifyPredAndCC(MI, Entry, false, Pred, LiveCPSR, HasCC, CCDead))

912 return false;

913

914

915

917 canAddPseudoFlagDep(MI, IsSelfLoop))

918 return false;

919

920

922 MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);

923

924

925

926

927 if (MCID.getOpcode() == ARM::t2TEQrr) {

928 MIB.add(MI->getOperand(0));

932

935 MIB.add(MI->getOperand(0));

936 } else {

937 MIB.add(MI->getOperand(0));

940 }

941

942

944 for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {

945 if (i < NumOps && MCID.operands()[i].isOptionalDef())

946 continue;

947 if ((MCID.getOpcode() == ARM::t2RSBSri ||

948 MCID.getOpcode() == ARM::t2RSBri ||

949 MCID.getOpcode() == ARM::t2SXTB ||

950 MCID.getOpcode() == ARM::t2SXTH ||

951 MCID.getOpcode() == ARM::t2UXTB ||

952 MCID.getOpcode() == ARM::t2UXTH) && i == 2)

953

954 continue;

955 bool isPred = (i < NumOps && MCID.operands()[i].isPredicate());

956 if (SkipPred && isPred)

957 continue;

958 const MachineOperand &MO = MI->getOperand(i);

960

961

962 continue;

963 MIB.add(MO);

964 }

967

968

970

972 << " to 16-bit: " << *MIB);

973

975 ++NumNarrows;

976 return true;

977}

978

980 bool HasDef = false;

983 continue;

984 if (MO.getReg() != ARM::CPSR)

985 continue;

986

987 DefCPSR = true;

989 HasDef = true;

990 }

991

992 return HasDef || LiveCPSR;

993}

994

998 continue;

999 if (MO.getReg() != ARM::CPSR)

1000 continue;

1001 assert(LiveCPSR && "CPSR liveness tracking is wrong!");

1003 LiveCPSR = false;

1004 break;

1005 }

1006 }

1007

1008 return LiveCPSR;

1009}

1010

1011bool Thumb2SizeReduce::ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI,

1012 bool LiveCPSR, bool IsSelfLoop,

1013 bool SkipPrologueEpilogue) {

1014 unsigned Opcode = MI->getOpcode();

1015 DenseMap<unsigned, unsigned>::iterator OPI = ReduceOpcodeMap.find(Opcode);

1016 if (OPI == ReduceOpcodeMap.end())

1017 return false;

1020 return false;

1021 const ReduceEntry &Entry = ReduceTable[OPI->second];

1022

1023

1024 if (Entry.Special)

1025 return ReduceSpecial(MBB, MI, Entry, LiveCPSR, IsSelfLoop);

1026

1027

1028 if (Entry.NarrowOpc2 &&

1029 ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))

1030 return true;

1031

1032

1033 if (Entry.NarrowOpc1 &&

1034 ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop))

1035 return true;

1036

1037 return false;

1038}

1039

1040bool Thumb2SizeReduce::ReduceMBB(MachineBasicBlock &MBB,

1041 bool SkipPrologueEpilogue) {

1043

1044

1045 bool LiveCPSR = MBB.isLiveIn(ARM::CPSR);

1046 MachineInstr *BundleMI = nullptr;

1047

1048 CPSRDef = nullptr;

1049 HighLatencyCPSR = false;

1050

1051

1053 const MBBInfo &PInfo = BlockInfo[Pred->getNumber()];

1054 if (!PInfo.Visited) {

1055

1056 continue;

1057 }

1058 if (PInfo.HighLatencyCPSR) {

1059 HighLatencyCPSR = true;

1060 break;

1061 }

1062 }

1063

1064

1065

1069 for (; MII != E; MII = NextMII) {

1070 NextMII = std::next(MII);

1071

1072 MachineInstr *MI = &*MII;

1073 if (MI->isBundle()) {

1074 BundleMI = MI;

1075 continue;

1076 }

1077 if (MI->isDebugInstr())

1078 continue;

1079

1081

1082

1083 bool NextInSameBundle = NextMII != E && NextMII->isBundledWithPred();

1084

1085 if (ReduceMI(MBB, MI, LiveCPSR, IsSelfLoop, SkipPrologueEpilogue)) {

1088 MI = &*I;

1089

1090

1091 if (NextInSameBundle && !NextMII->isBundledWithPred())

1092 NextMII->bundleWithPred();

1093 }

1094

1095 if (BundleMI && !NextInSameBundle && MI->isInsideBundle()) {

1096

1097

1098

1099

1100 if (BundleMI->killsRegister(ARM::CPSR, nullptr))

1101 LiveCPSR = false;

1102 MachineOperand *MO =

1104 if (MO && !MO->isDead())

1105 LiveCPSR = true;

1107 if (MO && !MO->isKill())

1108 LiveCPSR = true;

1109 }

1110

1111 bool DefCPSR = false;

1113 if (MI->isCall()) {

1114

1115 CPSRDef = nullptr;

1116 HighLatencyCPSR = false;

1117 IsSelfLoop = false;

1118 } else if (DefCPSR) {

1119

1120 CPSRDef = MI;

1122 IsSelfLoop = false;

1123 }

1124 }

1125

1127 Info.HighLatencyCPSR = HighLatencyCPSR;

1128 Info.Visited = true;

1130}

1131

1132bool Thumb2SizeReduce::runOnMachineFunction(MachineFunction &MF) {

1133 if (PredicateFtor && !PredicateFtor(MF.getFunction()))

1134 return false;

1135

1137 if (STI->isThumb1Only() || STI->prefers32BitThumb())

1138 return false;

1139

1140 TII = static_cast<const Thumb2InstrInfo *>(STI->getInstrInfo());

1141

1142

1145

1146 BlockInfo.clear();

1148

1149

1150

1151 ReversePostOrderTraversal<MachineFunction*> RPOT(&MF);

1155 for (MachineBasicBlock *MBB : RPOT)

1156 Modified |= ReduceMBB(*MBB, NeedsWinCFI);

1158}

1159

1160

1161

1163 std::function<bool(const Function &)> Ftor) {

1164 return new Thumb2SizeReduce(std::move(Ftor));

1165}

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

const TargetInstrInfo & TII

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

Analysis containing CSE Info

This file defines the DenseMap class.

const size_t AbstractManglingParser< Derived, Alloc >::NumOps

Promote Memory to Register

static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)

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

This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.

dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"

This file defines the SmallSet class.

This file defines the SmallVector class.

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

#define STATISTIC(VARNAME, DESC)

static cl::opt< int > ReduceLimit("t2-reduce-limit", cl::init(-1), cl::Hidden)

static cl::opt< int > ReduceLimitLdSt("t2-reduce-limit3", cl::init(-1), cl::Hidden)

static cl::opt< int > ReduceLimit2Addr("t2-reduce-limit2", cl::init(-1), cl::Hidden)

static bool HasImplicitCPSRDef(const MCInstrDesc &MCID)

Definition Thumb2SizeReduction.cpp:252

static bool isHighLatencyCPSR(MachineInstr *Def)

Definition Thumb2SizeReduction.cpp:257

static bool UpdateCPSRUse(MachineInstr &MI, bool LiveCPSR)

Definition Thumb2SizeReduction.cpp:995

static bool VerifyLowRegs(MachineInstr *MI)

Definition Thumb2SizeReduction.cpp:369

#define THUMB2_SIZE_REDUCE_NAME

Definition Thumb2SizeReduction.cpp:46

static bool UpdateCPSRDef(MachineInstr &MI, bool LiveCPSR, bool &DefCPSR)

Definition Thumb2SizeReduction.cpp:979

const ARMBaseInstrInfo * getInstrInfo() const override

bool isThumb1Only() const

iterator find(const_arg_type_t< KeyT > Val)

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

bool hasOptSize() const

Optimize this function for size (-Os) or minimum size (-Oz).

bool needsUnwindTableEntry() const

True if this function needs an unwind table.

bool usesWindowsCFI() const

Describe properties that are true of each instruction in the target description file.

unsigned getNumOperands() const

Return the number of declared MachineOperands for this MachineInstruction.

ArrayRef< MCOperandInfo > operands() const

bool hasOptionalDef() const

Set if this instruction has an optional definition, e.g.

bool isPredicable() const

Return true if this instruction has a predicate operand that controls execution.

unsigned getOpcode() const

Return the opcode number for this descriptor.

const MCInstrDesc & get(unsigned Opcode) const

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

instr_iterator instr_begin()

instr_iterator erase_instr(MachineInstr *I)

Remove an instruction from the instruction list and delete it.

int getNumber() const

MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...

Instructions::iterator instr_iterator

instr_iterator instr_end()

LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const

Return true if the specified MBB is a successor of this block.

iterator_range< pred_iterator > predecessors()

LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const

Return true if the specified register is in the live in set.

MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...

const TargetSubtargetInfo & getSubtarget() const

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

Function & getFunction()

Return the LLVM function that this machine code represents.

unsigned getNumBlockIDs() const

getNumBlockIDs - Return the number of MBB ID's allocated.

const TargetMachine & getTarget() const

getTarget - Return the target machine this machine code is compiled with

const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & add(const MachineOperand &MO) const

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

Add a new virtual register operand.

const MachineInstrBuilder & setMIFlags(unsigned Flags) const

Representation of each machine instruction.

bool killsRegister(Register Reg, const TargetRegisterInfo *TRI) const

Return true if the MachineInstr kills the specified register.

MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)

Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...

const MachineOperand & getOperand(unsigned i) const

MachineOperand * findRegisterDefOperand(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false)

Wrapper for findRegisterDefOperandIdx, it returns a pointer to the MachineOperand rather than an inde...

MachineOperand class - Representation of each machine instruction operand.

bool isReg() const

isReg - Tests if this is a MO_Register operand.

void setIsDead(bool Val=true)

bool isImm() const

isImm - Tests if this is a MO_Immediate operand.

void setIsKill(bool Val=true)

Register getReg() const

getReg - Returns the register number.

LLVM_ABI void setIsDef(bool Val=true)

Change a def to a use, or a use to a def.

Wrapper class representing virtual and physical registers.

size_type count(const T &V) const

count - Return 1 if the element is in the set, 0 otherwise.

std::pair< const_iterator, bool > insert(const T &V)

insert - Insert an element into the set if it isn't already there.

virtual bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const

Returns true iff the routine could find two commutable operands in the given machine instruction.

MachineInstr * commuteInstruction(MachineInstr &MI, bool NewMI=false, unsigned OpIdx1=CommuteAnyOperandIndex, unsigned OpIdx2=CommuteAnyOperandIndex) const

This method commutes the operands of the given machine instruction MI.

static const unsigned CommuteAnyOperandIndex

const MCAsmInfo * getMCAsmInfo() const

Return target specific asm information.

A Use represents the edge between a Value definition and its users.

#define llvm_unreachable(msg)

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

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)

NodeAddr< UseNode * > Use

BaseReg

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

This is an optimization pass for GlobalISel generic memory operations.

auto drop_begin(T &&RangeOrContainer, size_t N=1)

Return a range covering RangeOrContainer with the first N elements excluded.

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

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

static bool isARMLowRegister(MCRegister Reg)

isARMLowRegister - Returns true if the register is a low register (r0-r7).

static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)

Get the operands corresponding to the given Pred value.

LLVM_ABI raw_ostream & dbgs()

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

unsigned getInternalReadRegState(bool B)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

unsigned getKillRegState(bool B)

ARMCC::CondCodes getInstrPredicate(const MachineInstr &MI, Register &PredReg)

getInstrPredicate - If instruction is predicated, returns its predicate condition,...

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

static MachineOperand t1CondCodeOp(bool isDead=false)

Get the operand corresponding to the conditional code result for Thumb1.

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

static MachineOperand condCodeOp(unsigned CCReg=0)

Get the operand corresponding to the conditional code result.

FunctionPass * createThumb2SizeReductionPass(std::function< bool(const Function &)> Ftor=nullptr)

createThumb2SizeReductionPass - Returns an instance of the Thumb2 size reduction pass.

Definition Thumb2SizeReduction.cpp:1162

Implement std::hash so that hash_code can be used in STL containers.