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

52

53

54

55

68

69using namespace llvm;

70

71#define DEBUG_TYPE "aarch64-machine-sme-abi"

72

73namespace {

74

75

76

77

78

80

81 ANY = 0,

82

83

84 ACTIVE,

85

86

87

88 ACTIVE_ZT0_SAVED,

89

90

91

92 LOCAL_SAVED,

93

94

95

96

97 LOCAL_COMMITTED,

98

99

101

102

103 OFF,

104

105

106 NUM_ZA_STATE

107};

108

109

110

113 NZCV = 1 << 0,

114 W0 = 1 << 1,

115 W0_HI = 1 << 2,

116 X0 = W0 | W0_HI,

118};

119

120

121struct PhysRegSave {

123 Register StatusFlags = AArch64::NoRegister;

124 Register X0Save = AArch64::NoRegister;

125};

126

127

128

129struct InstInfo {

130 ZAState NeededState{ZAState::ANY};

132 LiveRegs PhysLiveRegs = LiveRegs::None;

133};

134

135

136

137struct BlockInfo {

139 ZAState FixedEntryState{ZAState::ANY};

140 ZAState DesiredIncomingState{ZAState::ANY};

141 ZAState DesiredOutgoingState{ZAState::ANY};

142 LiveRegs PhysLiveRegsAtEntry = LiveRegs::None;

143 LiveRegs PhysLiveRegsAtExit = LiveRegs::None;

144};

145

146

147struct FunctionInfo {

149 std::optionalMachineBasicBlock::iterator AfterSMEProloguePt;

150 LiveRegs PhysLiveRegsAfterSMEPrologue = LiveRegs::None;

151};

152

153

154

155class EmitContext {

156public:

157 EmitContext() = default;

158

159

161 if (TPIDR2BlockFI)

162 return *TPIDR2BlockFI;

165 return *TPIDR2BlockFI;

166 }

167

168

170 if (AgnosticZABufferPtr != AArch64::NoRegister)

171 return AgnosticZABufferPtr;

174 AgnosticZABufferPtr =

175 BufferPtr != AArch64::NoRegister

176 ? BufferPtr

178 return AgnosticZABufferPtr;

179 }

180

182 if (ZT0SaveFI)

183 return *ZT0SaveFI;

186 return *ZT0SaveFI;

187 }

188

189

190

191 bool needsSaveBuffer() const {

192 assert(!(TPIDR2BlockFI && AgnosticZABufferPtr) &&

193 "Cannot have both a TPIDR2 block and agnostic ZA buffer");

194 return TPIDR2BlockFI || AgnosticZABufferPtr != AArch64::NoRegister;

195 }

196

197private:

198 std::optional ZT0SaveFI;

199 std::optional TPIDR2BlockFI;

200 Register AgnosticZABufferPtr = AArch64::NoRegister;

201};

202

203

204

205

206

207

208static bool isLegalEdgeBundleZAState(ZAState State) {

209 switch (State) {

210 case ZAState::ACTIVE:

211 case ZAState::ACTIVE_ZT0_SAVED:

212 case ZAState::LOCAL_SAVED:

213 case ZAState::LOCAL_COMMITTED:

214 return true;

215 default:

216 return false;

217 }

218}

219

220StringRef getZAStateString(ZAState State) {

221#define MAKE_CASE(V) \

222 case V: \

223 return #V;

224 switch (State) {

227 MAKE_CASE(ZAState::ACTIVE_ZT0_SAVED)

229 MAKE_CASE(ZAState::LOCAL_COMMITTED)

232 default:

234 }

235#undef MAKE_CASE

236}

237

241 return false;

243 return AArch64::MPR128RegClass.contains(SR) ||

244 AArch64::ZTRRegClass.contains(SR);

245 });

246}

247

248

249

250static std::pair<ZAState, MachineBasicBlock::iterator>

254

255

256

257

258

259

260 if (MI.getOpcode() == AArch64::InOutZAUsePseudo)

261 return {ZAState::ACTIVE, std::prev(InsertPt)};

262

263

264 if (MI.getOpcode() == AArch64::RequiresZASavePseudo)

265 return {ZAState::LOCAL_SAVED, std::prev(InsertPt)};

266

267

268

269

270

271

272

273

274 if (MI.getOpcode() == AArch64::RequiresZT0SavePseudo) {

275 return {SMEFnAttrs.hasZAState() ? ZAState::ACTIVE_ZT0_SAVED

276 : ZAState::LOCAL_COMMITTED,

277 std::prev(InsertPt)};

278 }

279

280 if (MI.isReturn()) {

282 return {ZAOffAtReturn ? ZAState::OFF : ZAState::ACTIVE, InsertPt};

283 }

284

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

286 if (isZAorZTRegOp(TRI, MO))

287 return {ZAState::ACTIVE, InsertPt};

288 }

289

290 return {ZAState::ANY, InsertPt};

291}

292

294 inline static char ID = 0;

295

298

300

301 StringRef getPassName() const override { return "Machine SME ABI pass"; }

302

303 void getAnalysisUsage(AnalysisUsage &AU) const override {

309 }

310

311

312

313 FunctionInfo collectNeededZAStates(SMEAttrs SMEFnAttrs);

314

315

316

318 const FunctionInfo &FnInfo);

319

320

321

322 void insertStateChanges(EmitContext &, const FunctionInfo &FnInfo,

325

326

327

328

329 void propagateDesiredStates(FunctionInfo &FnInfo, bool Forwards = true);

330

333

334

345 bool ClearTPIDR2, bool On);

346

347

351

352

353

356 LiveRegs PhysLiveRegs, bool IsSave);

360

361

362

363

364 std::pair<MachineBasicBlock::iterator, LiveRegs>

369 ZAState To, LiveRegs PhysLiveRegs);

370

371

374 if (AFI->getSMEFnAttrs().hasAgnosticZAInterface())

375 return emitFullZASaveRestore(Context, MBB, MBBI, PhysLiveRegs,

376 true);

377 return emitSetupLazySave(Context, MBB, MBBI);

378 }

381 if (AFI->getSMEFnAttrs().hasAgnosticZAInterface())

382 return emitFullZASaveRestore(Context, MBB, MBBI, PhysLiveRegs,

383 false);

384 return emitRestoreLazySave(Context, MBB, MBBI, PhysLiveRegs);

385 }

389 if (AFI->getSMEFnAttrs().hasAgnosticZAInterface())

390 return emitAllocateFullZASaveBuffer(Context, MBB, MBBI, PhysLiveRegs);

391 return emitAllocateLazySaveBuffer(Context, MBB, MBBI);

392 }

393

394

397

400

401private:

403

411};

412

414 LiveRegs PhysLiveRegs = LiveRegs::None;

415 if (!LiveUnits.available(AArch64::NZCV))

416 PhysLiveRegs |= LiveRegs::NZCV;

417

418

419 if (!LiveUnits.available(AArch64::W0))

420 PhysLiveRegs |= LiveRegs::W0;

421 if (!LiveUnits.available(AArch64::W0_HI))

422 PhysLiveRegs |= LiveRegs::W0_HI;

423 return PhysLiveRegs;

424}

425

427 if (PhysLiveRegs & LiveRegs::NZCV)

428 LiveUnits.addReg(AArch64::NZCV);

429 if (PhysLiveRegs & LiveRegs::W0)

430 LiveUnits.addReg(AArch64::W0);

431 if (PhysLiveRegs & LiveRegs::W0_HI)

432 LiveUnits.addReg(AArch64::W0_HI);

433}

434

435[[maybe_unused]] bool isCallStartOpcode(unsigned Opc) {

436 switch (Opc) {

437 case AArch64::TLSDESC_CALLSEQ:

438 case AArch64::TLSDESC_AUTH_CALLSEQ:

439 case AArch64::ADJCALLSTACKDOWN:

440 return true;

441 default:

442 return false;

443 }

444}

445

446FunctionInfo MachineSMEABI::collectNeededZAStates(SMEAttrs SMEFnAttrs) {

449 "Expected function to have ZA/ZT0 state!");

450

452 LiveRegs PhysLiveRegsAfterSMEPrologue = LiveRegs::None;

453 std::optionalMachineBasicBlock::iterator AfterSMEProloguePt;

454

456 BlockInfo &Block = Blocks[MBB.getNumber()];

457

458 if (MBB.isEntryBlock()) {

459

460 Block.FixedEntryState = ZAState::ENTRY;

461 } else if (MBB.isEHPad()) {

462

463 Block.FixedEntryState = ZAState::LOCAL_COMMITTED;

464 }

465

468

469 Block.PhysLiveRegsAtExit = getPhysLiveRegs(LiveUnits);

470 auto FirstTerminatorInsertPt = MBB.getFirstTerminator();

471 auto FirstNonPhiInsertPt = MBB.getFirstNonPHI();

475 LiveRegs PhysLiveRegs = getPhysLiveRegs(LiveUnits);

476

477

478

479

480 if (MI.getOpcode() == AArch64::SMEStateAllocPseudo) {

481 AfterSMEProloguePt = MBBI;

482 PhysLiveRegsAfterSMEPrologue = PhysLiveRegs;

483 }

484

485 auto [NeededState, InsertPt] = getInstNeededZAState(*TRI, MI, SMEFnAttrs);

486 assert((InsertPt == MBBI || isCallStartOpcode(InsertPt->getOpcode())) &&

487 "Unexpected state change insertion point!");

488

489 if (MBBI == FirstTerminatorInsertPt)

490 Block.PhysLiveRegsAtExit = PhysLiveRegs;

491 if (MBBI == FirstNonPhiInsertPt)

492 Block.PhysLiveRegsAtEntry = PhysLiveRegs;

493 if (NeededState != ZAState::ANY)

494 Block.Insts.push_back({NeededState, InsertPt, PhysLiveRegs});

495 }

496

497

498 std::reverse(Block.Insts.begin(), Block.Insts.end());

499

500

501

502 if (Block.Insts.empty()) {

503 Block.DesiredIncomingState = Block.Insts.front().NeededState;

504 Block.DesiredOutgoingState = Block.Insts.back().NeededState;

505 }

506 }

507

508 return FunctionInfo{std::move(Blocks), AfterSMEProloguePt,

509 PhysLiveRegsAfterSMEPrologue};

510}

511

512void MachineSMEABI::propagateDesiredStates(FunctionInfo &FnInfo,

513 bool Forwards) {

514

515

516

517 auto GetBlockState = [](BlockInfo &Block, bool Incoming) -> ZAState & {

518 return Incoming ? Block.DesiredIncomingState : Block.DesiredOutgoingState;

519 };

520

522 for (auto [BlockID, BlockInfo] : enumerate(FnInfo.Blocks)) {

523 if (!isLegalEdgeBundleZAState(GetBlockState(BlockInfo, Forwards)))

525 }

526

527 while (!Worklist.empty()) {

529 BlockInfo &Block = FnInfo.Blocks[MBB->getNumber()];

530

531

532

533 int StateCounts[ZAState::NUM_ZA_STATE] = {0};

536 BlockInfo &PredOrSuccBlock = FnInfo.Blocks[PredOrSucc->getNumber()];

537 ZAState ZAState = GetBlockState(PredOrSuccBlock, !Forwards);

538 if (isLegalEdgeBundleZAState(ZAState))

539 StateCounts[ZAState]++;

540 }

541

542 ZAState PropagatedState = ZAState(max_element(StateCounts) - StateCounts);

543 ZAState &CurrentState = GetBlockState(Block, Forwards);

544 if (PropagatedState != CurrentState) {

545 CurrentState = PropagatedState;

546 ZAState &OtherState = GetBlockState(Block, !Forwards);

547

548 if (OtherState == ZAState::ANY)

549 OtherState = PropagatedState;

550

551

554 BlockInfo &SuccOrPredBlock = FnInfo.Blocks[SuccOrPred->getNumber()];

555 if (!isLegalEdgeBundleZAState(GetBlockState(SuccOrPredBlock, Forwards)))

557 }

558 }

559 }

560}

561

562

563

565MachineSMEABI::assignBundleZAStates(const EdgeBundles &Bundles,

566 const FunctionInfo &FnInfo) {

569 LLVM_DEBUG(dbgs() << "Assigning ZA state for edge bundle: " << I << '\n');

570

571

572

573

574 int EdgeStateCounts[ZAState::NUM_ZA_STATE] = {0};

575 for (unsigned BlockID : Bundles.getBlocks(I)) {

577

578 const BlockInfo &Block = FnInfo.Blocks[BlockID];

579 bool InEdge = Bundles.getBundle(BlockID, false) == I;

580 bool OutEdge = Bundles.getBundle(BlockID, true) == I;

581

582 bool LegalInEdge =

583 InEdge && isLegalEdgeBundleZAState(Block.DesiredIncomingState);

584 bool LegalOutEgde =

585 OutEdge && isLegalEdgeBundleZAState(Block.DesiredOutgoingState);

586 if (LegalInEdge) {

588 << getZAStateString(Block.DesiredIncomingState));

589 EdgeStateCounts[Block.DesiredIncomingState]++;

590 }

591 if (LegalOutEgde) {

593 << getZAStateString(Block.DesiredOutgoingState));

594 EdgeStateCounts[Block.DesiredOutgoingState]++;

595 }

596 if (!LegalInEdge && !LegalOutEgde)

599 }

600

601 ZAState BundleState =

602 ZAState(max_element(EdgeStateCounts) - EdgeStateCounts);

603

604 if (BundleState == ZAState::ANY)

605 BundleState = ZAState::ACTIVE;

606

608 dbgs() << "Chosen ZA state: " << getZAStateString(BundleState) << '\n'

609 << "Edge counts:";

610 for (auto [State, Count] : enumerate(EdgeStateCounts))

611 dbgs() << " " << getZAStateString(ZAState(State)) << ": " << Count;

612 dbgs() << "\n\n";

613 });

614

615 BundleStates[I] = BundleState;

616 }

617

618 return BundleStates;

619}

620

621std::pair<MachineBasicBlock::iterator, LiveRegs>

622MachineSMEABI::findStateChangeInsertionPoint(

627 if (Inst != Block.Insts.end()) {

628 InsertPt = Inst->InsertPt;

629 PhysLiveRegs = Inst->PhysLiveRegs;

630 } else {

631 InsertPt = MBB.getFirstTerminator();

632 PhysLiveRegs = Block.PhysLiveRegsAtExit;

633 }

634

635 if (PhysLiveRegs == LiveRegs::None)

636 return {InsertPt, PhysLiveRegs};

637

638

640 if (Inst == Block.Insts.begin()) {

641 PrevStateChangeI = MBB.begin();

642 } else {

643

644

645

646

647 PrevStateChangeI = std::prev(Inst)->InsertPt;

648 }

649

650

652 setPhysLiveRegs(LiveUnits, PhysLiveRegs);

653 auto BestCandidate = std::make_pair(InsertPt, PhysLiveRegs);

655

656 if (I->getOpcode() == TII->getCallFrameDestroyOpcode() || I->isCall())

657 break;

659 LiveRegs CurrentPhysLiveRegs = getPhysLiveRegs(LiveUnits);

660

661

662 if (!(CurrentPhysLiveRegs & LiveRegs::NZCV))

663 BestCandidate = {I, CurrentPhysLiveRegs};

664 if (CurrentPhysLiveRegs == LiveRegs::None)

665 break;

666 }

667 return BestCandidate;

668}

669

670void MachineSMEABI::insertStateChanges(EmitContext &Context,

671 const FunctionInfo &FnInfo,

675 const BlockInfo &Block = FnInfo.Blocks[MBB.getNumber()];

676 ZAState InState = BundleStates[Bundles.getBundle(MBB.getNumber(),

677 false)];

678

679 ZAState CurrentState = Block.FixedEntryState;

680 if (CurrentState == ZAState::ANY)

681 CurrentState = InState;

682

683 for (auto &Inst : Block.Insts) {

684 if (CurrentState != Inst.NeededState) {

685 auto [InsertPt, PhysLiveRegs] =

686 findStateChangeInsertionPoint(MBB, Block, &Inst);

687 emitStateChange(Context, MBB, InsertPt, CurrentState, Inst.NeededState,

688 PhysLiveRegs);

689 CurrentState = Inst.NeededState;

690 }

691 }

692

693 if (MBB.succ_empty())

694 continue;

695

696 ZAState OutState =

697 BundleStates[Bundles.getBundle(MBB.getNumber(), true)];

698 if (CurrentState != OutState) {

699 auto [InsertPt, PhysLiveRegs] =

700 findStateChangeInsertionPoint(MBB, Block, Block.Insts.end());

701 emitStateChange(Context, MBB, InsertPt, CurrentState, OutState,

702 PhysLiveRegs);

703 }

704 }

705}

706

710 return MBBI->getDebugLoc();

712}

713

714void MachineSMEABI::emitSetupLazySave(EmitContext &Context,

718

719

720 Register TPIDR2 = MRI->createVirtualRegister(&AArch64::GPR64spRegClass);

721 Register TPIDR2Ptr = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

728

730 .addImm(AArch64SysReg::TPIDR2_EL0)

732}

733

734PhysRegSave MachineSMEABI::createPhysRegSave(LiveRegs PhysLiveRegs,

738 PhysRegSave RegSave{PhysLiveRegs};

739 if (PhysLiveRegs & LiveRegs::NZCV) {

740 RegSave.StatusFlags = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

742 .addImm(AArch64SysReg::NZCV)

744 }

745

746

747 if (PhysLiveRegs & LiveRegs::W0) {

748 RegSave.X0Save = MRI->createVirtualRegister(PhysLiveRegs & LiveRegs::W0_HI

749 ? &AArch64::GPR64RegClass

750 : &AArch64::GPR32RegClass);

752 .addReg(PhysLiveRegs & LiveRegs::W0_HI ? AArch64::X0 : AArch64::W0);

753 }

754 return RegSave;

755}

756

757void MachineSMEABI::restorePhyRegSave(const PhysRegSave &RegSave,

761 if (RegSave.StatusFlags != AArch64::NoRegister)

763 .addImm(AArch64SysReg::NZCV)

764 .addReg(RegSave.StatusFlags)

766

767 if (RegSave.X0Save != AArch64::NoRegister)

769 RegSave.PhysLiveRegs & LiveRegs::W0_HI ? AArch64::X0 : AArch64::W0)

770 .addReg(RegSave.X0Save);

771}

772

773void MachineSMEABI::emitRestoreLazySave(EmitContext &Context,

779 Register TPIDR2EL0 = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

780 Register TPIDR2 = AArch64::X0;

781

782

783 PhysRegSave RegSave = createPhysRegSave(PhysLiveRegs, MBB, MBBI, DL);

784

785

787 .addImm(AArch64SVCR::SVCRZA)

789

791 .addImm(AArch64SysReg::TPIDR2_EL0);

792

797

801 .addExternalSymbol(TLI->getLibcallName(RTLIB::SMEABI_TPIDR2_RESTORE))

802 .addRegMask(TRI->SMEABISupportRoutinesCallPreservedMaskFromX0());

803

805 .addImm(AArch64SysReg::TPIDR2_EL0)

806 .addReg(AArch64::XZR);

807

808 restorePhyRegSave(RegSave, MBB, MBBI, DL);

809}

810

813 bool ClearTPIDR2, bool On) {

815

816 if (ClearTPIDR2)

818 .addImm(AArch64SysReg::TPIDR2_EL0)

819 .addReg(AArch64::XZR);

820

821

823 .addImm(AArch64SVCR::SVCRZA)

825}

826

827void MachineSMEABI::emitAllocateLazySaveBuffer(

832 Register SP = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

833 Register SVL = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

835

836

838

839

840 if (Buffer == AArch64::NoRegister) {

841

842

843

844

845

846

848 "Lazy ZA save is not yet supported on Windows");

849 Buffer = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

850

852 .addReg(AArch64::SP);

853

860

862 }

863

864

865 {

866

867

870 "TPIDR2 block initialization is not supported on big-endian targets");

871

872

873

879 }

880}

881

883

888

892

893 Register TPIDR2EL0 = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

896 .addImm(AArch64SysReg::TPIDR2_EL0);

897

898

899 auto CommitZASave =

904 .addExternalSymbol(TLI->getLibcallName(RTLIB::SMEABI_TPIDR2_SAVE))

905 .addRegMask(TRI->SMEABISupportRoutinesCallPreservedMaskFromX0());

906 if (ZeroZA)

908 if (ZeroZT0)

910

912 .addImm(AArch64SVCR::SVCRZA)

915 if (ZeroZA)

919 if (ZeroZT0)

921 }

922}

923

924void MachineSMEABI::emitFullZASaveRestore(EmitContext &Context,

927 LiveRegs PhysLiveRegs, bool IsSave) {

930 Register BufferPtr = AArch64::X0;

931

932 PhysRegSave RegSave = createPhysRegSave(PhysLiveRegs, MBB, MBBI, DL);

933

934

936 .addReg(Context.getAgnosticZABufferPtr(*MF));

937

938

942 IsSave ? RTLIB::SMEABI_SME_SAVE : RTLIB::SMEABI_SME_RESTORE))

944 *MF,

946

947 restorePhyRegSave(RegSave, MBB, MBBI, DL);

948}

949

950void MachineSMEABI::emitZT0SaveRestore(EmitContext &Context,

953 bool IsSave) {

955 Register ZT0Save = MRI->createVirtualRegister(&AArch64::GPR64spRegClass);

956

961

962 if (IsSave) {

964 .addReg(AArch64::ZT0)

966 } else {

969 }

970}

971

972void MachineSMEABI::emitAllocateFullZASaveBuffer(

975

977 return;

978

980 Register BufferPtr = Context.getAgnosticZABufferPtr(*MF);

981 Register BufferSize = MRI->createVirtualRegister(&AArch64::GPR64RegClass);

982

983 PhysRegSave RegSave = createPhysRegSave(PhysLiveRegs, MBB, MBBI, DL);

984

985

986 {

990 .addExternalSymbol(TLI->getLibcallName(RTLIB::SMEABI_SME_STATE_SIZE))

996 .addReg(AArch64::X0);

997 }

998

999

1000 {

1003 .addReg(AArch64::SP)

1007 .addReg(AArch64::SP);

1008

1009

1011 }

1012

1013 restorePhyRegSave(RegSave, MBB, MBBI, DL);

1014}

1015

1016struct FromState {

1017 ZAState From;

1018

1019 constexpr uint8_t to(ZAState To) const {

1020 static_assert(NUM_ZA_STATE < 16, "expected ZAState to fit in 4-bits");

1022 }

1023};

1024

1025constexpr FromState transitionFrom(ZAState From) { return FromState{From}; }

1026

1027void MachineSMEABI::emitStateChange(EmitContext &Context,

1030 ZAState From, ZAState To,

1032

1033 if (From == ZAState::ANY || To == ZAState::ANY)

1034 return;

1035

1036

1037

1038 if (From == ZAState::ENTRY && To == ZAState::OFF)

1039 return;

1040

1041

1042

1043 if (From == ZAState::ENTRY) {

1045 "ENTRY state only valid in entry block");

1046 emitSMEPrologue(MBB, MBB.getFirstNonPHI());

1047 if (To == ZAState::ACTIVE)

1048 return;

1049

1050

1051

1052

1053 From = ZAState::ACTIVE;

1054 }

1055

1058 bool HasZT0State = SMEFnAttrs.hasZT0State();

1059 bool HasZAState = IsAgnosticZA || SMEFnAttrs.hasZAState();

1060

1061 switch (transitionFrom(From).to(To)) {

1062

1063 case transitionFrom(ZAState::ACTIVE).to(ZAState::ACTIVE_ZT0_SAVED):

1064 emitZT0SaveRestore(Context, MBB, InsertPt, true);

1065 break;

1066 case transitionFrom(ZAState::ACTIVE_ZT0_SAVED).to(ZAState::ACTIVE):

1067 emitZT0SaveRestore(Context, MBB, InsertPt, false);

1068 break;

1069

1070

1071 case transitionFrom(ZAState::ACTIVE).to(ZAState::LOCAL_SAVED):

1072 case transitionFrom(ZAState::ACTIVE_ZT0_SAVED).to(ZAState::LOCAL_SAVED):

1073 if (HasZT0State && From == ZAState::ACTIVE)

1074 emitZT0SaveRestore(Context, MBB, InsertPt, true);

1075 if (HasZAState)

1076 emitZASave(Context, MBB, InsertPt, PhysLiveRegs);

1077 break;

1078

1079

1080 case transitionFrom(ZAState::ACTIVE).to(ZAState::LOCAL_COMMITTED):

1081

1082

1083 assert(HasZT0State && !HasZAState && "Expect to only have ZT0 state.");

1084 emitZT0SaveRestore(Context, MBB, InsertPt, true);

1085 emitZAMode(MBB, InsertPt, false, false);

1086 break;

1087

1088

1089 case transitionFrom(ZAState::LOCAL_COMMITTED).to(ZAState::OFF):

1090 case transitionFrom(ZAState::LOCAL_COMMITTED).to(ZAState::LOCAL_SAVED):

1091

1092 break;

1093

1094

1095 case transitionFrom(ZAState::LOCAL_COMMITTED).to(ZAState::ACTIVE):

1096 case transitionFrom(ZAState::LOCAL_COMMITTED).to(ZAState::ACTIVE_ZT0_SAVED):

1097 case transitionFrom(ZAState::LOCAL_SAVED).to(ZAState::ACTIVE):

1098 if (HasZAState)

1099 emitZARestore(Context, MBB, InsertPt, PhysLiveRegs);

1100 else

1101 emitZAMode(MBB, InsertPt, false, true);

1102 if (HasZT0State && To == ZAState::ACTIVE)

1103 emitZT0SaveRestore(Context, MBB, InsertPt, false);

1104 break;

1105

1106

1107 case transitionFrom(ZAState::ACTIVE).to(ZAState::OFF):

1108 case transitionFrom(ZAState::ACTIVE_ZT0_SAVED).to(ZAState::OFF):

1109 case transitionFrom(ZAState::LOCAL_SAVED).to(ZAState::OFF):

1111 "Did not expect to turn ZA off in shared/agnostic ZA function");

1112 emitZAMode(MBB, InsertPt, From == ZAState::LOCAL_SAVED,

1113 false);

1114 break;

1115

1116 default:

1117 dbgs() << "Error: Transition from " << getZAStateString(From) << " to "

1118 << getZAStateString(To) << '\n';

1120 }

1121}

1122

1123}

1124

1125INITIALIZE_PASS(MachineSMEABI, "aarch64-machine-sme-abi", "Machine SME ABI",

1126 false, false)

1127

1130 return false;

1131

1133 SMEAttrs SMEFnAttrs = AFI->getSMEFnAttrs();

1134 if (!SMEFnAttrs.hasZAState() && !SMEFnAttrs.hasZT0State() &&

1135 !SMEFnAttrs.hasAgnosticZAInterface())

1136 return false;

1137

1138 assert(MF.getRegInfo().isSSA() && "Expected to be run on SSA form!");

1139

1140 this->MF = &MF;

1142 TII = Subtarget->getInstrInfo();

1143 TRI = Subtarget->getRegisterInfo();

1144 MRI = &MF.getRegInfo();

1145

1147 getAnalysis().getEdgeBundles();

1148

1149 FunctionInfo FnInfo = collectNeededZAStates(SMEFnAttrs);

1150

1152

1153

1154

1155

1156

1157

1158

1159

1160

1161

1162

1163

1164

1165

1166

1167

1168

1169

1170

1171

1172

1173

1174

1175

1176

1177

1178

1179

1180

1181

1182

1183 for (bool Forwards : {true, false})

1184 propagateDesiredStates(FnInfo, Forwards);

1185 }

1186

1188

1189 EmitContext Context;

1190 insertStateChanges(Context, FnInfo, Bundles, BundleStates);

1191

1192 if (Context.needsSaveBuffer()) {

1193 if (FnInfo.AfterSMEProloguePt) {

1194

1195

1197 emitAllocateZASaveBuffer(Context, *MBBI->getParent(), MBBI,

1198 FnInfo.PhysLiveRegsAfterSMEPrologue);

1199 } else {

1201 emitAllocateZASaveBuffer(

1203 FnInfo.Blocks[EntryBlock.getNumber()].PhysLiveRegsAtEntry);

1204 }

1205 }

1206

1207 return true;

1208}

1209

1211 return new MachineSMEABI(OptLevel);

1212}

unsigned const MachineRegisterInfo * MRI

static constexpr unsigned ZERO_ALL_ZA_MASK

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

This file implements the LivePhysRegs utility for tracking liveness of physical registers.

#define ENTRY(ASMNAME, ENUM)

static DebugLoc getDebugLoc(MachineBasicBlock::instr_iterator FirstMI, MachineBasicBlock::instr_iterator LastMI)

Return the first DebugLoc that has line number information, given a range of instructions.

Register const TargetRegisterInfo * TRI

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

This file defines the SmallVector class.

AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...

Register getEarlyAllocSMESaveBuffer() const

SMEAttrs getSMEFnAttrs() const

bool isTargetWindows() const

const AArch64RegisterInfo * getRegisterInfo() const override

const AArch64TargetLowering * getTargetLowering() const override

bool isLittleEndian() const

Represent the analysis usage information of a pass.

AnalysisUsage & addPreservedID(const void *ID)

AnalysisUsage & addRequired()

LLVM_ABI void setPreservesCFG()

This function should be called by the pass, iff they do not:

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

ArrayRef< unsigned > getBlocks(unsigned Bundle) const

getBlocks - Return an array of blocks that are connected to Bundle.

unsigned getBundle(unsigned N, bool Out) const

getBundle - Return the ingoing (Out = false) or outgoing (Out = true) bundle number for basic block N

unsigned getNumBundles() const

getNumBundles - Return the total number of bundles in the CFG.

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

A set of register units used to track register liveness.

bool available(MCRegister Reg) const

Returns true if no part of physical register Reg is live.

void addReg(MCRegister Reg)

Adds register units covered by physical register Reg.

LLVM_ABI void stepBackward(const MachineInstr &MI)

Updates liveness when stepping backwards over the instruction MI.

LLVM_ABI void addLiveOuts(const MachineBasicBlock &MBB)

Adds registers living out of block MBB.

int getNumber() const

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

LLVM_ABI iterator getFirstNonPHI()

Returns a pointer to the first instruction in this block that is not a PHINode instruction.

MachineInstrBundleIterator< MachineInstr > iterator

The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.

LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)

Create a new statically sized stack object, returning a nonnegative identifier to represent it.

LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment)

Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...

LLVM_ABI int CreateVariableSizedObject(Align Alignment, const AllocaInst *Alloca)

Notify the MachineFrameInfo object that a variable sized object has been created.

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.

MachineFrameInfo & getFrameInfo()

getFrameInfo - Return the frame info object for the current function.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

MachineBasicBlock * getBlockNumbered(unsigned N) const

getBlockNumbered - MachineBasicBlocks are automatically numbered when they are inserted into the mach...

unsigned getNumBlockIDs() const

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

Ty * getInfo()

getInfo - Keep track of various per-function pieces of information for backends that would like to do...

const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & addFrameIndex(int Idx) const

const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const

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

Add a new virtual register operand.

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

Add a virtual register definition operand.

Representation of each machine instruction.

MachineOperand class - Representation of each machine instruction operand.

bool isReg() const

isReg - Tests if this is a MO_Register operand.

Register getReg() const

getReg - Returns the register number.

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

LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")

createVirtualRegister - Create and return a new virtual register in the function with the specified r...

Wrapper class representing virtual and physical registers.

constexpr bool isPhysical() const

Return true if the specified register number is in the physical register namespace.

SMEAttrs is a utility class to parse the SME ACLE attributes on functions.

bool hasAgnosticZAInterface() const

bool hasPrivateZAInterface() const

bool hasSharedZAInterface() const

typename SuperClass::const_iterator const_iterator

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.

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

#define llvm_unreachable(msg)

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

static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)

getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...

CallingConv Namespace - This namespace contains an enum with a value for the well-known calling conve...

unsigned ID

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

@ AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1

Preserve X1-X15, X19-X29, SP, Z0-Z31, P0-P15.

@ Implicit

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

@ Define

Register definition.

This is an optimization pass for GlobalISel generic memory operations.

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

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

auto enumerate(FirstRange &&First, RestRanges &&...Rest)

Given two or more input ranges, returns a new range whose values are tuples (A, B,...

auto successors(const MachineBasicBlock *BB)

FunctionPass * createMachineSMEABIPass(CodeGenOptLevel)

Definition MachineSMEABIPass.cpp:1210

LLVM_ABI char & MachineDominatorsID

MachineDominators - This pass is a machine dominators analysis pass.

LLVM_ABI void reportFatalInternalError(Error Err)

Report a fatal error that indicates a bug in LLVM.

LLVM_ABI char & MachineLoopInfoID

MachineLoopInfo - This pass is a loop analysis pass.

bool any_of(R &&range, UnaryPredicate P)

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

auto reverse(ContainerTy &&C)

LLVM_ABI raw_ostream & dbgs()

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

FunctionAddr VTableAddr Count

CodeGenOptLevel

Code generation optimization level.

@ LLVM_MARK_AS_BITMASK_ENUM

uint16_t MCPhysReg

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

auto max_element(R &&Range)

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

auto predecessors(const MachineBasicBlock *BB)

This struct is a compact representation of a valid (non-zero power of two) alignment.

Incoming for lane maks phi as machine instruction, incoming register Reg and incoming block Block are...