LLVM: lib/Target/AArch64/AArch64LowerHomogeneousPrologEpilog.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

27#include

28#include

29

30using namespace llvm;

31

32#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME \

33 "AArch64 homogeneous prolog/epilog lowering pass"

34

37 cl::desc("The minimum number of instructions that are outlined in a frame "

38 "helper (default = 2)"));

39

40namespace {

41

42class AArch64LowerHomogeneousPE {

43public:

45

47 : M(M), MMI(MMI) {}

48

49 bool run();

51

52private:

55

59

60

61

62

65

66

67

70};

71

72class AArch64LowerHomogeneousPrologEpilog : public ModulePass {

73public:

74 static char ID;

75

76 AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {

79 }

85 }

87

90 }

91};

92

93}

94

95char AArch64LowerHomogeneousPrologEpilog::ID = 0;

96

98 "aarch64-lower-homogeneous-prolog-epilog",

100

101bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {

102 if (skipModule(M))

103 return false;

104

106 &getAnalysis().getMMI();

107 return AArch64LowerHomogeneousPE(&M, MMI).run();

108}

109

110bool AArch64LowerHomogeneousPE::run() {

111 bool Changed = false;

112 for (auto &F : *M) {

113 if (F.empty())

114 continue;

115

117 if (!MF)

118 continue;

119 Changed |= runOnMachineFunction(*MF);

120 }

121

122 return Changed;

123}

125

126

127

128

131 std::ostringstream RegStream;

132 switch (Type) {

134 RegStream << "OUTLINED_FUNCTION_PROLOG_";

135 break;

137 RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";

138 break;

140 RegStream << "OUTLINED_FUNCTION_EPILOG_";

141 break;

143 RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";

144 break;

145 }

146

147 for (auto Reg : Regs) {

148 if (Reg == AArch64::NoRegister)

149 continue;

151 }

152

153 return RegStream.str();

154}

155

156

157

163 assert(F == nullptr && "Function has been created before");

165 Function::ExternalLinkage, Name, M);

166 assert(F && "Function was null!");

167

168

170 F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);

171

172

173 F->addFnAttr(Attribute::NoInline);

174 F->addFnAttr(Attribute::MinSize);

175 F->addFnAttr(Attribute::Naked);

176

178

179 MF.getProperties().reset(MachineFunctionProperties::Property::TracksLiveness);

180 MF.getProperties().reset(MachineFunctionProperties::Property::IsSSA);

181 MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);

183

184

188

189

192

193 return MF;

194}

195

196

197

201 int Offset, bool IsPreDec) {

202 assert(Reg1 != AArch64::NoRegister);

203 const bool IsPaired = Reg2 != AArch64::NoRegister;

204 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);

205 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));

206 unsigned Opc;

207 if (IsPreDec) {

208 if (IsFloat)

209 Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;

210 else

211 Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;

212 } else {

213 if (IsFloat)

214 Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;

215 else

216 Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;

217 }

218

219 TypeSize Scale(0U, false), Width(0U, false);

220 int64_t MinOffset, MaxOffset;

221 [[maybe_unused]] bool Success =

224 Offset *= (8 / (int)Scale);

225

227 if (IsPreDec)

228 MIB.addDef(AArch64::SP);

229 if (IsPaired)

235}

236

237

238

242 int Offset, bool IsPostDec) {

243 assert(Reg1 != AArch64::NoRegister);

244 const bool IsPaired = Reg2 != AArch64::NoRegister;

245 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);

246 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));

247 unsigned Opc;

248 if (IsPostDec) {

249 if (IsFloat)

250 Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;

251 else

252 Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;

253 } else {

254 if (IsFloat)

255 Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;

256 else

257 Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;

258 }

259

260 TypeSize Scale(0U, false), Width(0U, false);

261 int64_t MinOffset, MaxOffset;

262 [[maybe_unused]] bool Success =

265 Offset *= (8 / (int)Scale);

266

268 if (IsPostDec)

269 MIB.addDef(AArch64::SP);

270 if (IsPaired)

276}

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

311 unsigned FpOffset = 0) {

314 auto *F = M->getFunction(Name);

315 if (F)

316 return F;

317

322

324 switch (Type) {

327

328 auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));

329

330

331

332 if (LRIdx != Size - 2) {

333 assert(Regs[Size - 2] != AArch64::LR);

335 LRIdx - Size + 2, true);

336 }

337

338

339 for (int I = Size - 3; I >= 0; I -= 2) {

340

341 if (Regs[I - 1] == AArch64::LR)

342 continue;

344 false);

345 }

353

355 .addReg(AArch64::LR);

356 break;

357 }

361

363 .addDef(AArch64::X16)

364 .addReg(AArch64::XZR)

367

368 for (int I = 0; I < Size - 2; I += 2)

370 false);

371

373 true);

374

377 break;

378 }

379

380 return M->getFunction(Name);

381}

382

383

384

385

386

387

388

389

395 auto RegCount = Regs.size();

396 assert(RegCount > 0 && (RegCount % 2 == 0));

397

398 int InstCount = RegCount / 2;

399

400

402 return false;

403

404 switch (Type) {

406

407 InstCount--;

408 break;

410

411 break;

412 }

414

415

416 for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {

417 if (NextMI->readsRegister(AArch64::W16, TRI))

418 return false;

419 }

420

422 if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))

423 return false;

424 }

425

426 break;

428

429 if (NextMBBI == MBB.end())

430 return false;

431 if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)

432 return false;

433 InstCount++;

434 break;

435 }

436 }

437

439}

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463bool AArch64LowerHomogeneousPE::lowerEpilog(

468

471 bool HasUnpairedReg = false;

472 for (auto &MO : MI.operands())

473 if (MO.isReg()) {

474 if (!MO.getReg().isValid()) {

475

476

477 assert(!HasUnpairedReg);

478 HasUnpairedReg = true;

479 }

481 }

482 (void)HasUnpairedReg;

484 if (Size == 0)

485 return false;

486

488 assert(MI.getOpcode() == AArch64::HOM_Epilog);

489

490 auto Return = NextMBBI;

492

493 auto *EpilogTailHelper =

501 NextMBBI = std::next(Return);

502 Return->removeFromParent();

505

506 auto *EpilogHelper =

512 } else {

513

514 for (int I = 0; I < Size - 2; I += 2)

516

518 }

519

521 return true;

522}

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546bool AArch64LowerHomogeneousPE::lowerProlog(

551

554 bool HasUnpairedReg = false;

555 int LRIdx = 0;

556 std::optional FpOffset;

557 for (auto &MO : MI.operands()) {

558 if (MO.isReg()) {

559 if (MO.getReg().isValid()) {

560 if (MO.getReg() == AArch64::LR)

561 LRIdx = Regs.size();

562 } else {

563

564

565 assert(!HasUnpairedReg);

566 HasUnpairedReg = true;

567 }

569 } else if (MO.isImm()) {

570 FpOffset = MO.getImm();

571 }

572 }

573 (void)HasUnpairedReg;

575 if (Size == 0)

576 return false;

577

579 assert(MI.getOpcode() == AArch64::HOM_Prolog);

580

581 if (FpOffset &&

583

584 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);

595

596 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);

597 auto *PrologHelper =

603 } else {

604

606 for (int I = Size - 3; I >= 0; I -= 2)

608 if (FpOffset) {

615 }

616 }

617

619 return true;

620}

621

622

623

624

625

626

631 unsigned Opcode = MI.getOpcode();

632 switch (Opcode) {

633 default:

634 break;

635 case AArch64::HOM_Prolog:

636 return lowerProlog(MBB, MBBI, NextMBBI);

637 case AArch64::HOM_Epilog:

638 return lowerEpilog(MBB, MBBI, NextMBBI);

639 }

640 return false;

641}

642

645

647 while (MBBI != E) {

650 MBBI = NMBBI;

651 }

652

654}

655

656bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {

658

660 for (auto &MBB : MF)

663}

664

666 return new AArch64LowerHomogeneousPrologEpilog();

667}

static Function * getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI, SmallVectorImpl< unsigned > &Regs, FrameHelperType Type, unsigned FpOffset=0)

Return a unique function if a helper can be formed with the given Regs and frame type.

static bool shouldUseFrameHelper(MachineBasicBlock &MBB, MachineBasicBlock::iterator &NextMBBI, SmallVectorImpl< unsigned > &Regs, FrameHelperType Type)

This function checks if a frame helper should be used for HOM_Prolog/HOM_Epilog pseudo instruction ex...

static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)

Emit a load-pair instruction for frame-destroy.

#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME

cl::opt< int > FrameHelperSizeThreshold("frame-helper-size-threshold", cl::init(2), cl::Hidden, cl::desc("The minimum number of instructions that are outlined in a frame " "helper (default = 2)"))

static std::string getFrameHelperName(SmallVectorImpl< unsigned > &Regs, FrameHelperType Type, unsigned FpOffset)

Return a frame helper name with the given CSRs and the helper type.

static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPreDec)

Emit a store-pair instruction for frame-setup.

static MachineFunction & createFrameHelperMachineFunction(Module *M, MachineModuleInfo *MMI, StringRef Name)

Create a Function for the unique frame helper with the given name.

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

MachineBasicBlock MachineBasicBlock::iterator MBBI

const HexagonInstrInfo * TII

Module.h This file contains the declarations for the Module class.

unsigned const TargetRegisterInfo * TRI

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

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)

static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)

static bool getMemOpInfo(unsigned Opcode, TypeSize &Scale, TypeSize &Width, int64_t &MinOffset, int64_t &MaxOffset)

Returns true if opcode Opc is a memory operation.

Represent the analysis usage information of a pass.

AnalysisUsage & addRequired()

AnalysisUsage & addPreserved()

Add the specified Pass class to the set of analyses preserved by this pass.

void setPreservesAll()

Set by analyses that do not transform their input at all.

LLVM Basic Block Representation.

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)

@ LinkOnceODRLinkage

Same, but only replaced by something equivalent.

ReturnInst * CreateRetVoid()

Create a 'ret void' instruction.

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

This is an important class for using LLVM in a threaded context.

const MachineFunction * getParent() const

Return the MachineFunction containing this basic block.

iterator_range< succ_iterator > successors()

MachineBasicBlock * removeFromParent()

This method unlinks 'this' from the containing function, and returns it, but does not delete it.

MachineFunctionProperties & set(Property P)

MachineFunctionProperties & reset(Property P)

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.

const MachineFunctionProperties & getProperties() const

Get the function properties.

MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)

CreateMachineBasicBlock - Allocate a new MachineBasicBlock.

void insert(iterator MBBI, MachineBasicBlock *MBB)

const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

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 & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const

Add a virtual register use operand.

const MachineInstrBuilder & copyImplicitOps(const MachineInstr &OtherMI) const

Copy all the implicit operands from OtherMI onto this one.

const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const

Add a virtual register definition operand.

Representation of each machine instruction.

This class contains meta information specific to a module.

MachineFunction & getOrCreateMachineFunction(Function &F)

Returns the MachineFunction constructed for the IR function F.

void freezeReservedRegs()

freezeReservedRegs - Called by the register allocator to freeze the set of reserved registers before ...

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

virtual bool runOnModule(Module &M)=0

runOnModule - Virtual method overriden by subclasses to process the module being operated on.

A Module instance is used to store all the information related to an LLVM module.

static PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

virtual void getAnalysisUsage(AnalysisUsage &) const

getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...

virtual StringRef getPassName() const

getPassName - Return a nice clean name for a pass.

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

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

TargetInstrInfo - Interface to description of machine instruction set.

TargetSubtargetInfo - Generic base class for all target subtargets.

virtual const TargetRegisterInfo * getRegisterInfo() const

getRegisterInfo - If register information is available, return it.

virtual const TargetInstrInfo * getInstrInfo() const

The instances of the Type class are immutable: once they are created, they are never changed.

static Type * getVoidTy(LLVMContext &C)

@ C

The default llvm calling convention, compatible with C.

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)

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

This is an optimization pass for GlobalISel generic memory operations.

auto find(R &&Range, const T &Val)

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

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

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

void initializeAArch64LowerHomogeneousPrologEpilogPass(PassRegistry &)

unsigned getDefRegState(bool B)

ModulePass * createAArch64LowerHomogeneousPrologEpilogPass()

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

Returns true if Element is found in Range.