LLVM: lib/Target/AArch64/AArch64RedundantCopyElimination.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

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

61

62using namespace llvm;

63

64#define DEBUG_TYPE "aarch64-copyelim"

65

66STATISTIC(NumCopiesRemoved, "Number of copies removed.");

67

68namespace {

72

73

74

75 LiveRegUnits DomBBClobberedRegs, DomBBUsedRegs;

76

77

78 LiveRegUnits OptBBClobberedRegs, OptBBUsedRegs;

79

80public:

81 static char ID;

83

84 struct RegImm {

86 int32_t Imm;

87 RegImm(MCPhysReg Reg, int32_t Imm) : Reg(Reg), Imm(Imm) {}

88 };

89

90 bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *MBB,

91 SmallVectorImpl &KnownRegs,

94 bool runOnMachineFunction(MachineFunction &MF) override;

95 MachineFunctionProperties getRequiredProperties() const override {

96 return MachineFunctionProperties().setNoVRegs();

97 }

98 StringRef getPassName() const override {

99 return "AArch64 Redundant Copy Elimination";

100 }

101};

102char AArch64RedundantCopyElimination::ID = 0;

103}

104

106 "AArch64 redundant copy elimination pass", false, false)

107

108

109

110

111

112

113

114

115

116

117

118

119

120bool AArch64RedundantCopyElimination::knownRegValInBlock(

123 unsigned Opc = CondBr.getOpcode();

124

125

126

127 if (((Opc == AArch64::CBZW || Opc == AArch64::CBZX) &&

128 MBB == CondBr.getOperand(1).getMBB()) ||

129 ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) &&

130 MBB != CondBr.getOperand(1).getMBB())) {

131 FirstUse = CondBr;

132 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));

133 return true;

134 }

135

136

137 if (Opc != AArch64::Bcc)

138 return false;

139

140

143 return false;

144

148 return false;

149

150

153 "Conditional branch not in predecessor block!");

154 if (CondBr == PredMBB->begin())

155 return false;

156

157

158

159 DomBBClobberedRegs.clear();

160 DomBBUsedRegs.clear();

161

162

165

166 bool IsCMN = false;

167 switch (PredI.getOpcode()) {

168 default:

169 break;

170

171

172 case AArch64::ADDSWri:

173 case AArch64::ADDSXri:

174 IsCMN = true;

175 [[fallthrough]];

176

177 case AArch64::SUBSWri:

178 case AArch64::SUBSXri: {

179

180 if (!PredI.getOperand(1).isReg())

181 return false;

182 MCPhysReg DstReg = PredI.getOperand(0).getReg();

183 MCPhysReg SrcReg = PredI.getOperand(1).getReg();

184

185 bool Res = false;

186

187

188

189

190 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.available(SrcReg) &&

191 SrcReg != DstReg) {

192

193 int32_t KnownImm = PredI.getOperand(2).getImm();

194 int32_t Shift = PredI.getOperand(3).getImm();

195 KnownImm <<= Shift;

196 if (IsCMN)

197 KnownImm = -KnownImm;

198 FirstUse = PredI;

199 KnownRegs.push_back(RegImm(SrcReg, KnownImm));

200 Res = true;

201 }

202

203

204

205 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)

206 return Res;

207

208

209

210 if (!DomBBClobberedRegs.available(DstReg))

211 return Res;

212

213 FirstUse = PredI;

214 KnownRegs.push_back(RegImm(DstReg, 0));

215 return true;

216 }

217

218

219

220 case AArch64::ADCSWr:

221 case AArch64::ADCSXr:

222 case AArch64::ADDSWrr:

223 case AArch64::ADDSWrs:

224 case AArch64::ADDSWrx:

225 case AArch64::ADDSXrr:

226 case AArch64::ADDSXrs:

227 case AArch64::ADDSXrx:

228 case AArch64::ADDSXrx64:

229 case AArch64::ANDSWri:

230 case AArch64::ANDSWrr:

231 case AArch64::ANDSWrs:

232 case AArch64::ANDSXri:

233 case AArch64::ANDSXrr:

234 case AArch64::ANDSXrs:

235 case AArch64::BICSWrr:

236 case AArch64::BICSWrs:

237 case AArch64::BICSXrs:

238 case AArch64::BICSXrr:

239 case AArch64::SBCSWr:

240 case AArch64::SBCSXr:

241 case AArch64::SUBSWrr:

242 case AArch64::SUBSWrs:

243 case AArch64::SUBSWrx:

244 case AArch64::SUBSXrr:

245 case AArch64::SUBSXrs:

246 case AArch64::SUBSXrx:

247 case AArch64::SUBSXrx64: {

248 MCPhysReg DstReg = PredI.getOperand(0).getReg();

249 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)

250 return false;

251

252

253

254 if (!DomBBClobberedRegs.available(DstReg))

255 return false;

256

257

258 FirstUse = PredI;

259 KnownRegs.push_back(RegImm(DstReg, 0));

260 return true;

261 }

262 }

263

264

265 if (PredI.definesRegister(AArch64::NZCV, nullptr))

266 return false;

267

268

271 }

272 return false;

273}

274

276

278 return false;

279

280

281

284 return false;

285

287 if (CondBr == PredMBB->end())

288 return false;

289

290

291

293

294

295

296

297

298 bool SeenFirstUse = false;

299

301

303 do {

304 --Itr;

305

306 if (!knownRegValInBlock(*Itr, MBB, KnownRegs, FirstUse))

307 continue;

308

309

310 OptBBClobberedRegs.clear();

311 OptBBUsedRegs.clear();

312

313

314

315 for (auto PredI = Itr;; --PredI) {

316 if (FirstUse == PredI)

317 SeenFirstUse = true;

318

319 if (PredI->isCopy()) {

320 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();

321 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();

322 for (auto &KnownReg : KnownRegs) {

323 if (!OptBBClobberedRegs.available(KnownReg.Reg))

324 continue;

325

326

327 if (CopySrcReg == KnownReg.Reg &&

328 OptBBClobberedRegs.available(CopyDstReg)) {

329 KnownRegs.push_back(RegImm(CopyDstReg, KnownReg.Imm));

330 if (SeenFirstUse)

331 FirstUse = PredI;

332 break;

333 }

334

335

336 if (CopyDstReg == KnownReg.Reg &&

337 OptBBClobberedRegs.available(CopySrcReg)) {

338 KnownRegs.push_back(RegImm(CopySrcReg, KnownReg.Imm));

339 if (SeenFirstUse)

340 FirstUse = PredI;

341 break;

342 }

343 }

344 }

345

346

347 if (PredI == PredMBB->begin())

348 break;

349

351 OptBBUsedRegs, TRI);

352

353 if (all_of(KnownRegs, [&](RegImm KnownReg) {

354 return !OptBBClobberedRegs.available(KnownReg.Reg);

355 }))

356 break;

357 }

358 break;

359

360 } while (Itr != PredMBB->begin() && Itr->isTerminator());

361

362

363 if (KnownRegs.empty())

364 return false;

365

367

368 SmallSetVector<unsigned, 4> UsedKnownRegs;

370

372 MachineInstr *MI = &*I;

373 ++I;

374 bool RemovedMI = false;

375 bool IsCopy = MI->isCopy();

376 bool IsMoveImm = MI->isMoveImmediate();

377 if (IsCopy || IsMoveImm) {

378 Register DefReg = MI->getOperand(0).getReg();

380 int64_t SrcImm = IsMoveImm ? MI->getOperand(1).getImm() : 0;

381 if (MRI->isReserved(DefReg) &&

382 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||

383 IsMoveImm)) {

384 for (RegImm &KnownReg : KnownRegs) {

385 if (KnownReg.Reg != DefReg &&

386 TRI->isSuperRegister(DefReg, KnownReg.Reg))

387 continue;

388

389

390 if (IsCopy && KnownReg.Imm != 0)

391 continue;

392

393 if (IsMoveImm) {

394

395

396 if (KnownReg.Imm != SrcImm)

397 continue;

398

399

400

402 if (any_of(MI->implicit_operands(), [CmpReg](MachineOperand &O) {

403 return !O.isDead() && O.isReg() && O.isDef() &&

404 O.getReg() != CmpReg;

405 }))

406 continue;

407

408

409

410 if (TRI->isSuperRegister(DefReg, KnownReg.Reg) && KnownReg.Imm < 0)

411 continue;

412 }

413

414 if (IsCopy)

416 else

418

419 MI->eraseFromParent();

421 LastChange = I;

422 NumCopiesRemoved++;

423 UsedKnownRegs.insert(KnownReg.Reg);

424 RemovedMI = true;

425 break;

426 }

427 }

428 }

429

430

431 if (RemovedMI)

432 continue;

433

434

435 for (unsigned RI = 0; RI < KnownRegs.size();)

436 if (MI->modifiesRegister(KnownRegs[RI].Reg, TRI)) {

437 std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);

438 KnownRegs.pop_back();

439

440

441 } else {

442 ++RI;

443 }

444

445

446 if (KnownRegs.empty())

447 break;

448 }

449

451 return false;

452

453

454

455 for (MCPhysReg KnownReg : UsedKnownRegs)

458

459

460

461 LLVM_DEBUG(dbgs() << "Clearing kill flags.\n\tFirstUse: " << *FirstUse

462 << "\tLastChange: ";

463 if (LastChange == MBB->end()) dbgs() << "\n";

464 else dbgs() << *LastChange);

465 for (MachineInstr &MMI : make_range(FirstUse, PredMBB->end()))

466 MMI.clearKillInfo();

468 MMI.clearKillInfo();

469

470 return true;

471}

472

473bool AArch64RedundantCopyElimination::runOnMachineFunction(

474 MachineFunction &MF) {

476 return false;

480

481

482

483 DomBBClobberedRegs.init(*TRI);

484 DomBBUsedRegs.init(*TRI);

485 OptBBClobberedRegs.init(*TRI);

486 OptBBUsedRegs.init(*TRI);

487

489 for (MachineBasicBlock &MBB : MF) {

492 }

494}

495

497 return new AArch64RedundantCopyElimination();

498}

unsigned const MachineRegisterInfo * MRI

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

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

const HexagonInstrInfo * TII

Register const TargetRegisterInfo * TRI

Promote Memory to Register

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

static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)

This file implements a set that has insertion order iteration characteristics.

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

#define STATISTIC(VARNAME, DESC)

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

A set of register units used to track register liveness.

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 init(const TargetRegisterInfo &TRI)

Initialize and clear the set.

void clear()

Clears the set.

unsigned pred_size() const

unsigned succ_size() const

pred_iterator pred_begin()

LLVM_ABI iterator getLastNonDebugInstr(bool SkipPseudoOp=true)

Returns an iterator to the last non-debug instruction in the basic block, or end().

MachineInstrBundleIterator< MachineInstr, true > reverse_iterator

void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())

Adds the specified register as a live in.

const MachineFunction * getParent() const

Return the MachineFunction containing this basic block.

MachineInstrBundleIterator< MachineInstr > iterator

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.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

Function & getFunction()

Return the LLVM function that this machine code represents.

Representation of each machine instruction.

MachineRegisterInfo - Keep track of information for virtual and physical registers,...

bool insert(const value_type &X)

Insert a new element into the SetVector.

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

TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...

virtual const TargetInstrInfo * getInstrInfo() const

virtual const TargetRegisterInfo * getRegisterInfo() const =0

Return the target's register information.

This provides a very simple, boring adaptor for a begin and end iterator into a range type.

unsigned ID

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

This is an optimization pass for GlobalISel generic memory operations.

bool all_of(R &&range, UnaryPredicate P)

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

FunctionPass * createAArch64RedundantCopyEliminationPass()

Definition AArch64RedundantCopyElimination.cpp:496

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

Convenience function for iterating over sub-ranges.

bool any_of(R &&range, UnaryPredicate P)

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

MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)

LLVM_ABI raw_ostream & dbgs()

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

class LLVM_GSL_OWNER SmallVector

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

uint16_t MCPhysReg

An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...

bool optimizeTerminators(MachineBasicBlock *MBB, const TargetInstrInfo &TII)

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

Implement std::swap in terms of BitVector swap.