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();

50 bool runOnMachineFunction(MachineFunction &Fn);

51

52private:

54 MachineModuleInfo *MMI;

55

56 bool runOnMBB(MachineBasicBlock &MBB);

59

60

61

62

65

66

67

70};

71

72class AArch64LowerHomogeneousPrologEpilog : public ModulePass {

73public:

74 static char ID;

75

76 AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {}

77 void getAnalysisUsage(AnalysisUsage &AU) const override {

78 AU.addRequired();

79 AU.addPreserved();

81 ModulePass::getAnalysisUsage(AU);

82 }

83 bool runOnModule(Module &M) override;

84

85 StringRef getPassName() const override {

87 }

88};

89

90}

91

92char AArch64LowerHomogeneousPrologEpilog::ID = 0;

93

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

97

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

99 if (skipModule(M))

100 return false;

101

103 &getAnalysis().getMMI();

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

105}

106

107bool AArch64LowerHomogeneousPE::run() {

109 for (auto &F : *M) {

110 if (F.empty())

111 continue;

112

114 if (!MF)

115 continue;

116 Changed |= runOnMachineFunction(*MF);

117 }

118

120}

122

123

124

125

128 std::ostringstream RegStream;

129 switch (Type) {

131 RegStream << "OUTLINED_FUNCTION_PROLOG_";

132 break;

134 RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";

135 break;

137 RegStream << "OUTLINED_FUNCTION_EPILOG_";

138 break;

140 RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";

141 break;

142 }

143

144 for (auto Reg : Regs) {

145 if (Reg == AArch64::NoRegister)

146 continue;

148 }

149

150 return RegStream.str();

151}

152

153

154

159 Function *F = M->getFunction(Name);

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

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

164

165

168

169

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

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

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

173

175

176 MF.getProperties().resetTracksLiveness().resetIsSSA().setNoVRegs();

178

179

182 Builder.CreateRetVoid();

183

184

187

188 return MF;

189}

190

191

192

196 int Offset, bool IsPreDec) {

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

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

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

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

201 unsigned Opc;

202 if (IsPreDec) {

203 if (IsFloat)

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

205 else

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

207 } else {

208 if (IsFloat)

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

210 else

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

212 }

213

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

215 int64_t MinOffset, MaxOffset;

216 [[maybe_unused]] bool Success =

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

220

222 if (IsPreDec)

223 MIB.addDef(AArch64::SP);

224 if (IsPaired)

230}

231

232

233

237 int Offset, bool IsPostDec) {

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

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

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

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

242 unsigned Opc;

243 if (IsPostDec) {

244 if (IsFloat)

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

246 else

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

248 } else {

249 if (IsFloat)

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

251 else

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

253 }

254

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

256 int64_t MinOffset, MaxOffset;

257 [[maybe_unused]] bool Success =

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

261

263 if (IsPostDec)

264 MIB.addDef(AArch64::SP);

265 if (IsPaired)

271}

272

273

274

275

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

306 unsigned FpOffset = 0) {

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

310 if (F)

311 return F;

312

317

319 switch (Type) {

322

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

324

325

326

327 if (LRIdx != Size - 2) {

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

330 LRIdx - Size + 2, true);

331 }

332

333

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

335

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

337 continue;

339 false);

340 }

348

350 .addReg(AArch64::LR);

351 break;

352 }

356

358 .addDef(AArch64::X16)

359 .addReg(AArch64::XZR)

362

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

365 false);

366

368 true);

369

372 break;

373 }

374

375 return M->getFunction(Name);

376}

377

378

379

380

381

382

383

384

389 const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();

390 auto RegCount = Regs.size();

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

392

393 int InstCount = RegCount / 2;

394

395

397 return false;

398

399 switch (Type) {

401

402 InstCount--;

403 break;

405

406 break;

407 }

409

410

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

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

413 return false;

414 }

415

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

418 return false;

419 }

420

421 break;

423

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

425 return false;

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

427 return false;

428 InstCount++;

429 break;

430 }

431 }

432

434}

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458bool AArch64LowerHomogeneousPE::lowerEpilog(

462 MachineInstr &MI = *MBBI;

463

465 SmallVector<unsigned, 8> Regs;

466 bool HasUnpairedReg = false;

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

468 if (MO.isReg()) {

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

470

471

472 assert(!HasUnpairedReg);

473 HasUnpairedReg = true;

474 }

476 }

477 (void)HasUnpairedReg;

479 if (Size == 0)

480 return false;

481

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

484

485 auto Return = NextMBBI;

486 MachineInstr *HelperCall = nullptr;

488

489 auto *EpilogTailHelper =

497 NextMBBI = std::next(Return);

498 Return->removeFromParent();

501

502 auto *EpilogHelper =

508 } else {

509

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

512

514 }

515

516

517

518 if (HelperCall)

519 for (auto &Def : MBBI->defs())

523 return true;

524}

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548bool AArch64LowerHomogeneousPE::lowerProlog(

552 MachineInstr &MI = *MBBI;

553

555 SmallVector<unsigned, 8> Regs;

556 bool HasUnpairedReg = false;

557 int LRIdx = 0;

558 std::optional FpOffset;

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

560 if (MO.isReg()) {

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

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

563 LRIdx = Regs.size();

564 } else {

565

566

567 assert(!HasUnpairedReg);

568 HasUnpairedReg = true;

569 }

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

572 FpOffset = MO.getImm();

573 }

574 }

575 (void)HasUnpairedReg;

577 if (Size == 0)

578 return false;

579

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

582

583 if (FpOffset &&

585

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

597

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

599 auto *PrologHelper =

605 } else {

606

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

610 if (FpOffset) {

617 }

618 }

619

621 return true;

622}

623

624

625

626

627

628

629bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB,

632 MachineInstr &MI = *MBBI;

633 unsigned Opcode = MI.getOpcode();

634 switch (Opcode) {

635 default:

636 break;

637 case AArch64::HOM_Prolog:

638 return lowerProlog(MBB, MBBI, NextMBBI);

639 case AArch64::HOM_Epilog:

640 return lowerEpilog(MBB, MBBI, NextMBBI);

641 }

642 return false;

643}

644

645bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) {

647

649 while (MBBI != E) {

652 MBBI = NMBBI;

653 }

654

656}

657

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

659 TII = MF.getSubtarget().getInstrInfo();

660

662 for (auto &MBB : MF)

665}

666

668 return new AArch64LowerHomogeneousPrologEpilog();

669}

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.

Definition AArch64LowerHomogeneousPrologEpilog.cpp:303

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...

Definition AArch64LowerHomogeneousPrologEpilog.cpp:385

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.

Definition AArch64LowerHomogeneousPrologEpilog.cpp:234

#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME

Definition AArch64LowerHomogeneousPrologEpilog.cpp:32

static 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.

Definition AArch64LowerHomogeneousPrologEpilog.cpp:126

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.

Definition AArch64LowerHomogeneousPrologEpilog.cpp:193

FrameHelperType

Definition AArch64LowerHomogeneousPrologEpilog.cpp:121

@ EpilogTail

Definition AArch64LowerHomogeneousPrologEpilog.cpp:121

@ PrologFrame

Definition AArch64LowerHomogeneousPrologEpilog.cpp:121

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

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

Definition AArch64LowerHomogeneousPrologEpilog.cpp:155

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

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

Machine Check Debug Module

Register const TargetRegisterInfo * TRI

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

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.

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 LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)

This static method is the primary way of constructing a FunctionType.

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

@ ExternalLinkage

Externally visible function.

@ LinkOnceODRLinkage

Same, but only replaced by something equivalent.

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.

MachineInstrBundleIterator< MachineInstr > iterator

LLVM_ABI MachineBasicBlock * removeFromParent()

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

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)

CreateMachineInstr - Allocate a new MachineInstr.

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.

LLVM_ABI void addRegisterDefined(Register Reg, const TargetRegisterInfo *RegInfo=nullptr)

We have determined MI defines a register.

This class contains meta information specific to a module.

LLVM_ABI MachineFunction & getOrCreateMachineFunction(Function &F)

Returns the MachineFunction constructed for the IR function F.

LLVM_ABI MachineFunction * getMachineFunction(const Function &F) const

Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.

LLVM_ABI void freezeReservedRegs()

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

const TargetRegisterInfo * getTargetRegisterInfo() const

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

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

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

void push_back(const T &Elt)

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 TargetInstrInfo * getInstrInfo() const

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

static LLVM_ABI Type * getVoidTy(LLVMContext &C)

@ C

The default llvm calling convention, compatible with C.

@ 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.

NodeAddr< DefNode * > Def

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.

unsigned getDefRegState(bool B)

ModulePass * createAArch64LowerHomogeneousPrologEpilogPass()

Definition AArch64LowerHomogeneousPrologEpilog.cpp:667

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

Returns true if Element is found in Range.