LLVM: lib/Target/ARM/ARMFrameLowering.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

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

155#include

156#include

157#include

158#include

159#include

160#include

161#include

162

163#define DEBUG_TYPE "arm-frame-lowering"

164

165using namespace llvm;

166

169 cl::desc("Align ARM NEON spills in prolog and epilog"));

170

173 unsigned NumAlignedDPRCS2Regs);

174

182};

183

184

187 unsigned NumAlignedDPRCS2Regs,

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214 switch (Reg) {

215 default:

216 dbgs() << "Don't know where to spill " << printReg(Reg, RegInfo) << "\n";

218 break;

219

220 case ARM::FPCXTNS:

222

223 case ARM::R0:

224 case ARM::R1:

225 case ARM::R2:

226 case ARM::R3:

227 case ARM::R4:

228 case ARM::R5:

229 case ARM::R6:

230 case ARM::R7:

232

233 case ARM::R8:

234 case ARM::R9:

235 case ARM::R10:

238 else

240

241 case ARM::R11:

247

249

250 case ARM::R12:

253 else

255

256 case ARM::LR:

261

263

264 case ARM::D0:

265 case ARM::D1:

266 case ARM::D2:

267 case ARM::D3:

268 case ARM::D4:

269 case ARM::D5:

270 case ARM::D6:

271 case ARM::D7:

273

274 case ARM::D8:

275 case ARM::D9:

276 case ARM::D10:

277 case ARM::D11:

278 case ARM::D12:

279 case ARM::D13:

280 case ARM::D14:

281 case ARM::D15:

282 if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)

284 else

286

288 case ARM::D17:

289 case ARM::D18:

290 case ARM::D19:

291 case ARM::D20:

292 case ARM::D21:

293 case ARM::D22:

294 case ARM::D23:

295 case ARM::D24:

296 case ARM::D25:

297 case ARM::D26:

298 case ARM::D27:

299 case ARM::D28:

300 case ARM::D29:

301 case ARM::D30:

302 case ARM::D31:

304 }

305}

306

309 STI(sti) {}

310

312

313

314

316}

317

318

319

324

325

326

327 return true;

328}

329

330

331

332

336

337

339 return true;

340

341

343 return true;

344

345

348}

349

350

351

354}

355

356

357

358

359

360

364

365

366

367

368 if (CFSize >= ((1 << 12) - 1) / 2)

369 return false;

370

372}

373

374

375

376

377

378bool

381}

382

383

384

385

386

387

391 bool IsTailCallReturn = false;

393 unsigned RetOpcode = MBBI->getOpcode();

394 IsTailCallReturn = RetOpcode == ARM::TCRETURNdi ||

395 RetOpcode == ARM::TCRETURNri ||

396 RetOpcode == ARM::TCRETURNrinotr12;

397 }

399

400 int ArgumentPopSize = 0;

401 if (IsTailCallReturn) {

403

404

405

406

407 ArgumentPopSize = StackAdjust.getImm();

408 } else {

409

410

411

412

414 }

415

416 return ArgumentPopSize;

417}

418

422 F.needsUnwindTableEntry();

423}

424

425

426

429 unsigned Flags) {

430 unsigned Opc = MBBI->getOpcode();

437

439

440 switch (Opc) {

441 default:

443 break;

444 case ARM::t2ADDri:

445 case ARM::t2ADDri12:

446 case ARM::t2MOVTi16:

447 case ARM::tBL:

448

449

450

454 break;

455

456 case ARM::t2MOVi16: {

457 bool Wide = MBBI->getOperand(1).getImm() >= 256;

458 if (!Wide) {

461 NewInstr.add(MBBI->getOperand(0));

464 NewInstr.add(MO);

467 MBBI = NewMBBI;

468 }

470 break;

471 }

472

473 case ARM::tBLXr:

477 break;

478

479 case ARM::t2MOVi32imm:

480

481

482

483

484

485

486

494 break;

495

496 case ARM::t2STR_PRE:

497 if (MBBI->getOperand(0).getReg() == ARM::SP &&

498 MBBI->getOperand(2).getReg() == ARM::SP &&

499 MBBI->getOperand(3).getImm() == -4) {

500 unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg());

501 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_SaveRegs))

505 } else {

507 }

508 break;

509

510 case ARM::t2LDR_POST:

511 if (MBBI->getOperand(1).getReg() == ARM::SP &&

512 MBBI->getOperand(2).getReg() == ARM::SP &&

513 MBBI->getOperand(3).getImm() == 4) {

514 unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg());

515 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_SaveRegs))

519 } else {

521 }

522 break;

523

524 case ARM::t2LDMIA_RET:

525 case ARM::t2LDMIA_UPD:

526 case ARM::t2STMDB_UPD: {

527 unsigned Mask = 0;

528 bool Wide = false;

529 for (unsigned i = 4, NumOps = MBBI->getNumOperands(); i != NumOps; ++i) {

532 continue;

533 unsigned Reg = RegInfo->getSEHRegNum(MO.getReg());

534 if (Reg == 15)

535 Reg = 14;

536 if (Reg >= 8 && Reg <= 13)

537 Wide = true;

538 else if (Opc == ARM::t2LDMIA_UPD && Reg == 14)

539 Wide = true;

540 Mask |= 1 << Reg;

541 }

542 if (!Wide) {

543 unsigned NewOpc;

544 switch (Opc) {

545 case ARM::t2LDMIA_RET:

546 NewOpc = ARM::tPOP_RET;

547 break;

548 case ARM::t2LDMIA_UPD:

549 NewOpc = ARM::tPOP;

550 break;

551 case ARM::t2STMDB_UPD:

552 NewOpc = ARM::tPUSH;

553 break;

554 default:

556 }

559 for (unsigned i = 2, NumOps = MBBI->getNumOperands(); i != NumOps; ++i)

560 NewInstr.add(MBBI->getOperand(i));

563 MBBI = NewMBBI;

564 }

565 unsigned SEHOpc =

566 (Opc == ARM::t2LDMIA_RET) ? ARM::SEH_SaveRegs_Ret : ARM::SEH_SaveRegs;

569 .addImm(Wide ? 1 : 0)

571 break;

572 }

573 case ARM::VSTMDDB_UPD:

574 case ARM::VLDMDIA_UPD: {

577 unsigned Reg = RegInfo->getSEHRegNum(MO.getReg());

581 }

582 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_SaveFRegs))

586 break;

587 }

588 case ARM::tSUBspi:

589 case ARM::tADDspi:

590 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_StackAlloc))

591 .addImm(MBBI->getOperand(2).getImm() * 4)

594 break;

595 case ARM::t2SUBspImm:

596 case ARM::t2SUBspImm12:

597 case ARM::t2ADDspImm:

598 case ARM::t2ADDspImm12:

599 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_StackAlloc))

600 .addImm(MBBI->getOperand(2).getImm())

603 break;

604

605 case ARM::tMOVr:

606 if (MBBI->getOperand(1).getReg() == ARM::SP &&

608 unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg());

609 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_SaveSP))

612 } else if (MBBI->getOperand(0).getReg() == ARM::SP &&

614 unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg());

615 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_SaveSP))

618 } else {

620 }

621 break;

622

623 case ARM::tBX_RET:

624 case ARM::TCRETURNri:

625 case ARM::TCRETURNrinotr12:

626 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_Nop_Ret))

629 break;

630

631 case ARM::TCRETURNdi:

632 MIB = BuildMI(MF, DL, TII.get(ARM::SEH_Nop_Ret))

635 break;

636 }

638}

639

644 return std::prev(MBBI);

645}

646

651 if (Start.isValid())

652 Start = std::next(Start);

653 else

655

656 for (auto MI = Start; MI != End;) {

657 auto Next = std::next(MI);

658

659

661 MI = std::next(Next);

663 ++MI;

664 continue;

665 }

667 MI = Next;

668 }

669}

670

676 if (isARM)

678 Pred, PredReg, TII, MIFlags);

679 else

681 Pred, PredReg, TII, MIFlags);

682}

683

689 unsigned PredReg = 0) {

691 MIFlags, Pred, PredReg);

692}

693

696 switch (MI.getOpcode()) {

697 case ARM::VSTMDDB_UPD:

699 break;

700 case ARM::STMDB_UPD:

701 case ARM::t2STMDB_UPD:

703 break;

704 case ARM::t2STR_PRE:

705 case ARM::STR_PRE_IMM:

706 return 4;

707 default:

709 }

710

712

713

714 for (int i = MI.getNumOperands() - 1; i >= 4; --i)

717}

718

720 size_t StackSizeInBytes) {

724

725 StackProbeSize =

726 F.getFnAttributeAsParsedInteger("stack-probe-size", StackProbeSize);

727 return (StackSizeInBytes >= StackProbeSize) &&

728 F.hasFnAttribute("no-stack-arg-probe");

729}

730

731namespace {

732

733struct StackAdjustingInsts {

734 struct InstInfo {

736 unsigned SPAdjust;

737 bool BeforeFPSet;

738

739#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

740 void dump() {

741 dbgs() << " " << (BeforeFPSet ? "before-fp " : " ")

742 << "sp-adjust=" << SPAdjust;

743 I->dump();

744 }

745#endif

746 };

747

749

751 bool BeforeFPSet = false) {

752 InstInfo Info = {I, SPAdjust, BeforeFPSet};

754 }

755

759 assert(Info != Insts.end() && "invalid sp adjusting instruction");

760 Info->SPAdjust += ExtraBytes;

761 }

762

766 unsigned CFAOffset = 0;

767 for (auto &Info : Insts) {

768 if (HasFP && Info.BeforeFPSet)

769 return;

770

771 CFAOffset += Info.SPAdjust;

775 TII.get(TargetOpcode::CFI_INSTRUCTION))

778 }

779 }

780

781#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

782 void dump() {

783 dbgs() << "StackAdjustingInsts:\n";

784 for (auto &Info : Insts)

786 }

787#endif

788};

789

790}

791

792

793

794

795

796

797

798

803 const DebugLoc &DL, const unsigned Reg,

804 const Align Alignment,

805 const bool MustBeSingleInstruction) {

807 const bool CanUseBFC = AST.hasV6T2Ops() || AST.hasV7Ops();

808 const unsigned AlignMask = Alignment.value() - 1U;

809 const unsigned NrBitsToZero = Log2(Alignment);

812

813

814

815

816

817

818

819

820

821 if (CanUseBFC) {

826 } else if (AlignMask <= 255) {

832 } else {

833 assert(!MustBeSingleInstruction &&

834 "Shouldn't call emitAligningInstructions demanding a single "

835 "instruction to be emitted for large stack alignment for a target "

836 "without BFC.");

847 }

848 } else {

849

850

856 }

857}

858

859

860

861

862

863

864

869

870

873

874

875 int MaxRegBytes = 8 * 4;

877

878 MaxRegBytes = 11 * 4;

880

881 MaxRegBytes = 11 * 4 + 8 * 8;

882 }

883 int FPCXTSaveSize =

886}

887

899 "This emitPrologue does not support Thumb1!");

905 int FPCXTSaveSize = 0;

909

911

912

913

915

917

918

919

920 unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCS1Size = 0, GPRCS3Size = 0,

921 DPRCS2Size = 0;

922 int FramePtrSpillFI = 0;

923 int D8SpillFI = 0;

924

925

926

928 return;

929

930 StackAdjustingInsts DefCFAOffsetCandidates;

931 bool HasFP = hasFP(MF);

932

935 if (NumBytes != 0) {

938 DefCFAOffsetCandidates.addInst(std::prev(MBBI), NumBytes, true);

939 }

940 if (!NeedsWinCFI)

941 DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP);

947 }

948 return;

949 }

950

951

952 SpillArea FramePtrSpillArea = SpillArea::GPRCS1;

953 bool BeforeFPPush = true;

956 int FI = I.getFrameIdx();

957

960

962 FramePtrSpillFI = FI;

963 FramePtrSpillArea = Area;

964 }

965 if (Reg == ARM::D8)

966 D8SpillFI = FI;

967

968 switch (Area) {

969 case SpillArea::FPCXT:

970 FPCXTSaveSize += 4;

971 break;

972 case SpillArea::GPRCS1:

973 GPRCS1Size += 4;

974 break;

975 case SpillArea::GPRCS2:

976 GPRCS2Size += 4;

977 break;

978 case SpillArea::DPRCS1:

979 DPRCS1Size += 8;

980 break;

981 case SpillArea::GPRCS3:

982 GPRCS3Size += 4;

983 break;

984 case SpillArea::DPRCS2:

985 DPRCS2Size += 4;

986 break;

987 }

988 }

989

991 DPRCS1Push, GPRCS3Push;

992

993

995 LastPush = MBBI++;

996

997

998 if (FPCXTSaveSize > 0) {

999 LastPush = MBBI++;

1000 DefCFAOffsetCandidates.addInst(LastPush, FPCXTSaveSize, BeforeFPPush);

1001 }

1002

1003

1004 if (ArgRegsSaveSize) {

1007 LastPush = std::prev(MBBI);

1008 DefCFAOffsetCandidates.addInst(LastPush, ArgRegsSaveSize, BeforeFPPush);

1009 }

1010

1011

1012 if (GPRCS1Size > 0) {

1013 GPRCS1Push = LastPush = MBBI++;

1014 DefCFAOffsetCandidates.addInst(LastPush, GPRCS1Size, BeforeFPPush);

1015 if (FramePtrSpillArea == SpillArea::GPRCS1)

1016 BeforeFPPush = false;

1017 }

1018

1019

1020

1021

1022

1023 unsigned FPCXTOffset = NumBytes - ArgRegsSaveSize - FPCXTSaveSize;

1024 unsigned GPRCS1Offset = FPCXTOffset - GPRCS1Size;

1025 unsigned GPRCS2Offset = GPRCS1Offset - GPRCS2Size;

1026

1027 Align DPRAlign = DPRCS1Size ? std::min(Align(8), Alignment) : Align(4);

1028 unsigned DPRGapSize =

1029 (ArgRegsSaveSize + FPCXTSaveSize + GPRCS1Size + GPRCS2Size) %

1030 DPRAlign.value();

1031

1032 unsigned DPRCS1Offset = GPRCS2Offset - DPRGapSize - DPRCS1Size;

1033

1034 if (HasFP) {

1035

1036 [[maybe_unused]] int FPOffset = MFI.getObjectOffset(FramePtrSpillFI);

1037 LLVM_DEBUG(dbgs() << "FramePtrSpillFI: " << FramePtrSpillFI

1038 << ", FPOffset: " << FPOffset << "\n");

1040 "Max FP estimation is wrong");

1042 NumBytes);

1043 }

1047

1048

1049 if (GPRCS2Size > 0) {

1051 GPRCS2Push = LastPush = MBBI++;

1052 DefCFAOffsetCandidates.addInst(LastPush, GPRCS2Size, BeforeFPPush);

1053 if (FramePtrSpillArea == SpillArea::GPRCS2)

1054 BeforeFPPush = false;

1055 }

1056

1057

1058

1059 if (DPRGapSize) {

1060 assert(DPRGapSize == 4 && "unexpected alignment requirements for DPRs");

1061 if (LastPush != MBB.end() &&

1063 DefCFAOffsetCandidates.addExtraBytes(LastPush, DPRGapSize);

1064 else {

1067 DefCFAOffsetCandidates.addInst(std::prev(MBBI), DPRGapSize, BeforeFPPush);

1068 }

1069 }

1070

1071

1072 if (DPRCS1Size > 0) {

1073

1074

1075 while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::VSTMDDB_UPD) {

1077 BeforeFPPush);

1078 DPRCS1Push = LastPush = MBBI++;

1079 }

1080 }

1081

1082

1083 if (DPRCS2Size > 0) {

1085

1086

1087

1088

1090 } else

1091 NumBytes = DPRCS1Offset;

1092

1093

1094 if (GPRCS3Size > 0) {

1096 GPRCS3Push = LastPush = MBBI++;

1097 DefCFAOffsetCandidates.addInst(LastPush, GPRCS3Size, BeforeFPPush);

1098 if (FramePtrSpillArea == SpillArea::GPRCS3)

1099 BeforeFPPush = false;

1100 }

1101

1102 bool NeedsWinCFIStackAlloc = NeedsWinCFI;

1104 NeedsWinCFIStackAlloc = false;

1105

1107 uint32_t NumWords = NumBytes >> 2;

1108

1109 if (NumWords < 65536) {

1114 } else {

1115

1116

1117

1119 .addImm(NumWords & 0xffff)

1124 .addImm(NumWords >> 16)

1127 }

1128

1129 switch (TM.getCodeModel()) {

1140 break;

1145

1151 break;

1152 }

1153

1161 if (NeedsWinCFIStackAlloc) {

1162 SEH = BuildMI(MF, dl, TII.get(ARM::SEH_StackAlloc))

1167 }

1168 NumBytes = 0;

1169 }

1170

1171 if (NumBytes) {

1172

1175 DefCFAOffsetCandidates.addExtraBytes(LastPush, NumBytes);

1176 else {

1179 DefCFAOffsetCandidates.addInst(std::prev(MBBI), NumBytes);

1180 }

1181

1182 if (HasFP && isARM)

1183

1184

1185

1186

1187

1188

1189

1190

1192 }

1193

1194

1195

1196

1197

1198

1199

1201 if (HasFP) {

1203

1204

1205 int64_t FPOffsetAfterPush;

1206 switch (FramePtrSpillArea) {

1207 case SpillArea::GPRCS1:

1208 FPPushInst = GPRCS1Push;

1209 FPOffsetAfterPush = MFI.getObjectOffset(FramePtrSpillFI) +

1210 ArgRegsSaveSize + FPCXTSaveSize +

1212 LLVM_DEBUG(dbgs() << "Frame pointer in GPRCS1, offset "

1213 << FPOffsetAfterPush << " after that push\n");

1214 break;

1215 case SpillArea::GPRCS2:

1216 FPPushInst = GPRCS2Push;

1217 FPOffsetAfterPush = MFI.getObjectOffset(FramePtrSpillFI) +

1218 ArgRegsSaveSize + FPCXTSaveSize + GPRCS1Size +

1220 LLVM_DEBUG(dbgs() << "Frame pointer in GPRCS2, offset "

1221 << FPOffsetAfterPush << " after that push\n");

1222 break;

1223 case SpillArea::GPRCS3:

1224 FPPushInst = GPRCS3Push;

1225 FPOffsetAfterPush = MFI.getObjectOffset(FramePtrSpillFI) +

1226 ArgRegsSaveSize + FPCXTSaveSize + GPRCS1Size +

1227 GPRCS2Size + DPRCS1Size + DPRGapSize +

1229 LLVM_DEBUG(dbgs() << "Frame pointer in GPRCS3, offset "

1230 << FPOffsetAfterPush << " after that push\n");

1231 break;

1232 default:

1234 break;

1235 }

1236 AfterPush = std::next(FPPushInst);

1238 assert(FPOffsetAfterPush == 0);

1239

1240

1242 FramePtr, ARM::SP, FPOffsetAfterPush,

1244

1245 if (!NeedsWinCFI) {

1246

1247

1248 if (FPOffsetAfterPush != 0) {

1250 nullptr, MRI->getDwarfRegNum(FramePtr, true),

1252 BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))

1255 } else {

1256 unsigned CFIIndex =

1258 nullptr, MRI->getDwarfRegNum(FramePtr, true)));

1259 BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))

1262 }

1263 }

1264 }

1265

1266

1267

1271 End = AfterPush;

1276 }

1277

1278

1279

1280

1281 if (!NeedsWinCFI) {

1282 for (const auto &Entry : reverse(CSI)) {

1283 Register Reg = Entry.getReg();

1284 int FI = Entry.getFrameIdx();

1287 RegInfo)) {

1288 case SpillArea::GPRCS1:

1289 CFIPos = std::next(GPRCS1Push);

1290 break;

1291 case SpillArea::GPRCS2:

1292 CFIPos = std::next(GPRCS2Push);

1293 break;

1294 case SpillArea::DPRCS1:

1295 CFIPos = std::next(DPRCS1Push);

1296 break;

1297 case SpillArea::GPRCS3:

1298 CFIPos = std::next(GPRCS3Push);

1299 break;

1300 case SpillArea::FPCXT:

1301 case SpillArea::DPRCS2:

1302

1303 break;

1304 }

1305

1308 nullptr,

1309 MRI->getDwarfRegNum(Reg == ARM::R12 ? ARM::RA_AUTH_CODE : Reg,

1310 true),

1312 BuildMI(MBB, CFIPos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))

1315 }

1316 }

1317 }

1318

1319

1320

1321

1322

1323 if (!NeedsWinCFI) {

1324 LLVM_DEBUG(DefCFAOffsetCandidates.dump());

1325 DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP);

1326 }

1327

1331

1338

1339

1340

1341

1342

1348 false);

1349 } else {

1350

1351

1352

1353

1354

1355

1356

1361 false);

1365 }

1366

1368 }

1369

1370

1371

1372

1373

1374

1376 if (isARM)

1381 else

1385 }

1386

1387

1388

1389

1392}

1393

1402 "This emitEpilogue does not support Thumb1!");

1406

1408

1409

1410

1412

1413

1414

1418

1419

1420

1422 return;

1423

1424

1427

1434 }

1435

1436 if (NumBytes + IncomingArgStackToRestore != 0)

1438 NumBytes + IncomingArgStackToRestore,

1440 } else {

1441

1443 do {

1449 }

1450

1455 }

1456

1457

1458 NumBytes -=

1463

1464

1465

1468 if (NumBytes) {

1469 if (isARM)

1473 else {

1474

1475

1476

1477

1478

1479

1480

1482 "No scratch register to restore SP from FP!");

1489 }

1490 } else {

1491

1492 if (isARM)

1498 else

1503 }

1504 } else if (NumBytes &&

1508

1509

1512 (void)PushPopSplit;

1514 }

1515

1518

1519

1520 while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::VLDMDIA_UPD)

1522 }

1525 "unexpected DPR alignment gap");

1528 }

1529

1532 (void)PushPopSplit;

1534 }

1536

1537 if (ReservedArgStack || IncomingArgStackToRestore) {

1538 assert((int)ReservedArgStack + IncomingArgStackToRestore >= 0 &&

1539 "attempting to restore negative stack amount");

1541 ReservedArgStack + IncomingArgStackToRestore,

1543 }

1544

1545

1546

1547

1548

1551 }

1552

1557 }

1558}

1559

1560

1561

1562

1563

1565 int FI,

1568}

1569

1572 int SPAdj) const {

1580

1581 FrameReg = ARM::SP;

1583

1584

1585

1587

1588

1589

1590 if (RegInfo->hasStackRealignment(MF)) {

1591 assert(hasFP(MF) && "dynamic stack realignment without a FP!");

1592 if (isFixed) {

1595 } else if (hasMovingSP) {

1597 "VLAs and dynamic stack alignment, but missing base pointer!");

1600 }

1602 }

1603

1604

1606

1607

1608 if (isFixed || (hasMovingSP && !RegInfo->hasBasePointer(MF))) {

1610 return FPOffset;

1611 } else if (hasMovingSP) {

1614

1615

1616

1617 if (FPOffset >= -255 && FPOffset < 0) {

1619 return FPOffset;

1620 }

1621 }

1623

1624

1625

1626

1627

1630

1631

1632 if (AFI->isThumb2Function() && FPOffset >= -255 && FPOffset < 0) {

1634 return FPOffset;

1635 }

1636 } else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) {

1637

1639 return FPOffset;

1640 }

1641 }

1642

1643

1644

1648 }

1650}

1651

1655 unsigned StmOpc, unsigned StrOpc,

1656 bool NoGap,

1661

1663

1664 using RegAndKill = std::pair<unsigned, bool>;

1665

1667 unsigned i = CSI.size();

1668 while (i != 0) {

1669 unsigned LastReg = 0;

1670 for (; i != 0; --i) {

1671 Register Reg = CSI[i-1].getReg();

1672 if (!Func(Reg))

1673 continue;

1674

1676 bool isLiveIn = MRI.isLiveIn(Reg);

1677 if (!isLiveIn && MRI.isReserved(Reg))

1679

1680

1681

1682 if (NoGap && LastReg && LastReg != Reg-1)

1683 break;

1684 LastReg = Reg;

1685

1686

1687

1688

1689

1690 Regs.push_back(std::make_pair(Reg, !isLiveIn));

1691 }

1692

1693 if (Regs.empty())

1694 continue;

1695

1696 llvm::sort(Regs, [&](const RegAndKill &LHS, const RegAndKill &RHS) {

1697 return TRI.getEncodingValue(LHS.first) < TRI.getEncodingValue(RHS.first);

1698 });

1699

1700 if (Regs.size() > 1 || StrOpc== 0) {

1705 for (unsigned i = 0, e = Regs.size(); i < e; ++i)

1707 } else if (Regs.size() == 1) {

1714 }

1716

1717

1718

1719

1721 --MI;

1722 }

1723}

1724

1728 unsigned LdmOpc, unsigned LdrOpc,

1729 bool isVarArg, bool NoGap,

1737 bool isTailCall = false;

1738 bool isInterrupt = false;

1739 bool isTrap = false;

1740 bool isCmseEntry = false;

1744 DL = MI->getDebugLoc();

1745 unsigned RetOpcode = MI->getOpcode();

1746 isTailCall =

1747 (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNri ||

1748 RetOpcode == ARM::TCRETURNrinotr12);

1749 isInterrupt =

1750 RetOpcode == ARM::SUBS_PC_LR || RetOpcode == ARM::t2SUBS_PC_LR;

1751 isTrap =

1752 RetOpcode == ARM::TRAP || RetOpcode == ARM::TRAPNaCl ||

1753 RetOpcode == ARM::tTRAP;

1754 isCmseEntry = (RetOpcode == ARM::tBXNS || RetOpcode == ARM::tBXNS_RET);

1755 }

1756

1758 unsigned i = CSI.size();

1759 while (i != 0) {

1760 unsigned LastReg = 0;

1761 bool DeleteRet = false;

1762 for (; i != 0; --i) {

1765 if (Func(Reg))

1766 continue;

1767

1768 if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt &&

1773 Reg = ARM::PC;

1774

1775 DeleteRet = true;

1776 LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;

1777 }

1778

1779

1780

1781

1782 if (NoGap && LastReg && LastReg != Reg-1)

1783 break;

1784

1785 LastReg = Reg;

1787 }

1788

1789 if (Regs.empty())

1790 continue;

1791

1792 llvm::sort(Regs, [&](unsigned LHS, unsigned RHS) {

1793 return TRI.getEncodingValue(LHS) < TRI.getEncodingValue(RHS);

1794 });

1795

1796 if (Regs.size() > 1 || LdrOpc == 0) {

1801 for (unsigned Reg : Regs)

1803 if (DeleteRet) {

1806 MI->eraseFromParent();

1807 }

1808 }

1809 MI = MIB;

1810 } else if (Regs.size() == 1) {

1811

1812

1813 if (Regs[0] == ARM::PC)

1814 Regs[0] = ARM::LR;

1820

1821

1822 if (LdrOpc == ARM::LDR_POST_REG || LdrOpc == ARM::LDR_POST_IMM) {

1825 } else

1828 }

1829 Regs.clear();

1830

1831

1832

1834 ++MI;

1835 }

1836}

1837

1838

1839

1840

1843 unsigned NumAlignedDPRCS2Regs,

1851

1852

1853

1854

1856 unsigned DNum = I.getReg() - ARM::D8;

1857 if (DNum > NumAlignedDPRCS2Regs - 1)

1858 continue;

1859 int FI = I.getFrameIdx();

1860

1861

1863

1864

1865

1866

1867

1868

1869

1870 if (DNum == 0)

1872 }

1873

1874

1875

1876

1877

1878

1879

1880

1884

1885

1886

1887 unsigned Opc = isThumb ? ARM::t2SUBri : ARM::SUBri;

1890 .addImm(8 * NumAlignedDPRCS2Regs)

1893

1895

1896

1897

1898

1899

1901

1902

1903

1904

1905

1906 Opc = isThumb ? ARM::tMOVr : ARM::MOVr;

1912

1913

1914

1915 unsigned NextReg = ARM::D8;

1916

1917

1918

1919 if (NumAlignedDPRCS2Regs >= 6) {

1921 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QQPRRegClass);

1929 NextReg += 4;

1930 NumAlignedDPRCS2Regs -= 4;

1931 }

1932

1933

1934

1935 unsigned R4BaseReg = NextReg;

1936

1937

1938 if (NumAlignedDPRCS2Regs >= 4) {

1940 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QQPRRegClass);

1948 NextReg += 4;

1949 NumAlignedDPRCS2Regs -= 4;

1950 }

1951

1952

1953 if (NumAlignedDPRCS2Regs >= 2) {

1955 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QPRRegClass);

1962 NextReg += 2;

1963 NumAlignedDPRCS2Regs -= 2;

1964 }

1965

1966

1967 if (NumAlignedDPRCS2Regs) {

1969

1973 .addImm((NextReg - R4BaseReg) * 2)

1975 }

1976

1977

1979}

1980

1981

1982

1985 unsigned NumAlignedDPRCS2Regs) {

1986

1987

1988

1990 assert(MI->mayStore() && "Expecting spill instruction");

1991

1992

1993 switch(NumAlignedDPRCS2Regs) {

1994 case 7:

1995 ++MI;

1996 assert(MI->mayStore() && "Expecting spill instruction");

1997 [[fallthrough]];

1998 default:

1999 ++MI;

2000 assert(MI->mayStore() && "Expecting spill instruction");

2001 [[fallthrough]];

2002 case 1:

2003 case 2:

2004 case 4:

2005 assert(MI->killsRegister(ARM::R4, nullptr) && "Missed kill flag");

2006 ++MI;

2007 }

2008 return MI;

2009}

2010

2011

2012

2013

2016 unsigned NumAlignedDPRCS2Regs,

2023

2024

2025 int D8SpillFI = 0;

2027 if (I.getReg() == ARM::D8) {

2028 D8SpillFI = I.getFrameIdx();

2029 break;

2030 }

2031

2032

2033

2034

2035

2036

2039

2040 unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri;

2046

2047

2048 unsigned NextReg = ARM::D8;

2049

2050

2051 if (NumAlignedDPRCS2Regs >= 6) {

2053 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QQPRRegClass);

2060 NextReg += 4;

2061 NumAlignedDPRCS2Regs -= 4;

2062 }

2063

2064

2065

2066 unsigned R4BaseReg = NextReg;

2067

2068

2069 if (NumAlignedDPRCS2Regs >= 4) {

2071 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QQPRRegClass);

2077 NextReg += 4;

2078 NumAlignedDPRCS2Regs -= 4;

2079 }

2080

2081

2082 if (NumAlignedDPRCS2Regs >= 2) {

2084 TRI->getMatchingSuperReg(NextReg, ARM::dsub_0, &ARM::QPRRegClass);

2089 NextReg += 2;

2090 NumAlignedDPRCS2Regs -= 2;

2091 }

2092

2093

2094 if (NumAlignedDPRCS2Regs)

2097 .addImm(2 * (NextReg - R4BaseReg))

2099

2100

2102}

2103

2107 if (CSI.empty())

2108 return false;

2109

2115

2116 unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD;

2118 ARM::t2STR_PRE : ARM::STR_PRE_IMM;

2119 unsigned FltOpc = ARM::VSTMDDB_UPD;

2121

2125 }

2126

2128 return C.getReg() == ARM::FPCXTNS;

2129 })) {

2131 ARM::SP)

2135 }

2136

2137 auto CheckRegArea = [PushPopSplit, NumAlignedDPRCS2Regs,

2138 RegInfo](unsigned Reg, SpillArea TestArea) {

2139 return getSpillArea(Reg, PushPopSplit, NumAlignedDPRCS2Regs, RegInfo) ==

2140 TestArea;

2141 };

2142 auto IsGPRCS1 = [&CheckRegArea](unsigned Reg) {

2143 return CheckRegArea(Reg, SpillArea::GPRCS1);

2144 };

2145 auto IsGPRCS2 = [&CheckRegArea](unsigned Reg) {

2146 return CheckRegArea(Reg, SpillArea::GPRCS2);

2147 };

2148 auto IsDPRCS1 = [&CheckRegArea](unsigned Reg) {

2149 return CheckRegArea(Reg, SpillArea::DPRCS1);

2150 };

2151 auto IsGPRCS3 = [&CheckRegArea](unsigned Reg) {

2152 return CheckRegArea(Reg, SpillArea::GPRCS3);

2153 };

2154

2155 emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS1);

2156 emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS2);

2157 emitPushInst(MBB, MI, CSI, FltOpc, 0, true, IsDPRCS1);

2158 emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS3);

2159

2160

2161

2162

2163 if (NumAlignedDPRCS2Regs)

2165

2166 return true;

2167}

2168

2172 if (CSI.empty())

2173 return false;

2174

2178

2183

2184

2185

2186 if (NumAlignedDPRCS2Regs)

2188

2189 unsigned PopOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD;

2190 unsigned LdrOpc =

2191 AFI->isThumbFunction() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM;

2192 unsigned FltOpc = ARM::VLDMDIA_UPD;

2193

2194 auto CheckRegArea = [PushPopSplit, NumAlignedDPRCS2Regs,

2195 RegInfo](unsigned Reg, SpillArea TestArea) {

2196 return getSpillArea(Reg, PushPopSplit, NumAlignedDPRCS2Regs, RegInfo) ==

2197 TestArea;

2198 };

2199 auto IsGPRCS1 = [&CheckRegArea](unsigned Reg) {

2200 return CheckRegArea(Reg, SpillArea::GPRCS1);

2201 };

2202 auto IsGPRCS2 = [&CheckRegArea](unsigned Reg) {

2203 return CheckRegArea(Reg, SpillArea::GPRCS2);

2204 };

2205 auto IsDPRCS1 = [&CheckRegArea](unsigned Reg) {

2206 return CheckRegArea(Reg, SpillArea::DPRCS1);

2207 };

2208 auto IsGPRCS3 = [&CheckRegArea](unsigned Reg) {

2209 return CheckRegArea(Reg, SpillArea::GPRCS3);

2210 };

2211

2212 emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS3);

2213 emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, IsDPRCS1);

2214 emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS2);

2215 emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS1);

2216

2217 return true;

2218}

2219

2220

2223 unsigned FnSize = 0;

2224 for (auto &MBB : MF) {

2225 for (auto &MI : MBB)

2226 FnSize += TII.getInstSizeInBytes(MI);

2227 }

2230 FnSize += Table.MBBs.size() * 4;

2232 return FnSize;

2233}

2234

2235

2236

2237

2238

2241 bool &HasNonSPFrameIndex) {

2246 unsigned Limit = (1 << 12) - 1;

2247 for (auto &MBB : MF) {

2248 for (auto &MI : MBB) {

2249 if (MI.isDebugInstr())

2250 continue;

2251 for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {

2252 if (MI.getOperand(i).isFI())

2253 continue;

2254

2255

2256

2257 if (MI.getOpcode() == ARM::ADDri) {

2258 Limit = std::min(Limit, (1U << 8) - 1);

2259 break;

2260 }

2261

2262

2263 if (MI.getOpcode() == ARM::t2ADDri || MI.getOpcode() == ARM::t2ADDri12)

2264 break;

2265

2268 if (RegClass && !RegClass->contains(ARM::SP))

2269 HasNonSPFrameIndex = true;

2270

2271

2275

2276 break;

2279 Limit = std::min(Limit, (1U << 8) - 1);

2280 break;

2282 Limit = std::min(Limit, ((1U << 8) - 1) * 2);

2283 break;

2287 Limit = std::min(Limit, ((1U << 8) - 1) * 4);

2288 break;

2290

2291

2293 Limit = std::min(Limit, (1U << 8) - 1);

2294 break;

2297

2298

2299 return 0;

2301 Limit = std::min(Limit, ((1U << 7) - 1) * 1);

2302 break;

2304 Limit = std::min(Limit, ((1U << 7) - 1) * 2);

2305 break;

2307 Limit = std::min(Limit, ((1U << 7) - 1) * 4);

2308 break;

2309 default:

2310 llvm_unreachable("Unhandled addressing mode in stack size limit calculation");

2311 }

2312 break;

2313 }

2314 }

2315 }

2316

2317 return Limit;

2318}

2319

2320

2321

2322

2323static void

2327 return;

2328

2329

2331 return;

2332

2333

2335 return;

2336

2337

2339 return;

2340

2341

2344 return;

2345

2346

2347

2348

2349

2350

2351 unsigned NumSpills = 0;

2352 for (; NumSpills < 8; ++NumSpills)

2353 if (!SavedRegs.test(ARM::D8 + NumSpills))

2354 break;

2355

2356

2357 if (NumSpills < 2)

2358 return;

2359

2360

2362

2363

2364 SavedRegs.set(ARM::R4);

2365}

2366

2368

2369

2370 if (STI.hasV8_1MMainlineOps() &&

2372 return false;

2373

2374

2375

2376

2378 true ))

2379 return false;

2380

2381 return true;

2382}

2383

2387 return Subtarget.createAAPCSFrameChain() && hasFP(MF);

2388}

2389

2390

2391

2392

2397 return false;

2398

2400 for (const auto &MBB : MF)

2401 for (const auto &MI : MBB)

2402 if (MI.getOpcode() == ARM::tSTRspi || MI.getOpcode() == ARM::tSTRi ||

2403 STI.genExecuteOnly())

2404 for (const auto &Op : MI.operands())

2405 if (Op.isFI()) {

2408 if (ARM::hGPRRegClass.contains(Reg) && Reg != ARM::SP)

2409 return true;

2410 }

2411 return false;

2412}

2413

2418

2419

2420

2421

2424 bool CS1Spilled = false;

2425 bool LRSpilled = false;

2426 unsigned NumGPRSpills = 0;

2427 unsigned NumFPRSpills = 0;

2438 (void)TRI;

2442

2443

2444

2445

2446

2447

2449 (MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF)))

2450 SavedRegs.set(ARM::R4);

2451

2452

2453

2454

2455

2456

2459 SavedRegs.set(ARM::R4);

2460 SavedRegs.set(ARM::LR);

2461 }

2462

2464

2466 SavedRegs.set(ARM::LR);

2467

2468

2469

2470

2471

2472

2473

2474 if (MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF) ||

2475 MFI.estimateStackSize(MF) > 508)

2476 SavedRegs.set(ARM::R4);

2477 }

2478

2479

2481

2482

2485

2486

2488 CanEliminateFrame = false;

2489

2490

2492 CanEliminateFrame = false;

2493

2494

2495

2497 for (unsigned i = 0; CSRegs[i]; ++i) {

2498 unsigned Reg = CSRegs[i];

2499 bool Spilled = false;

2500 if (SavedRegs.test(Reg)) {

2501 Spilled = true;

2502 CanEliminateFrame = false;

2503 }

2504

2505 if (!ARM::GPRRegClass.contains(Reg)) {

2506 if (Spilled) {

2507 if (ARM::SPRRegClass.contains(Reg))

2508 NumFPRSpills++;

2509 else if (ARM::DPRRegClass.contains(Reg))

2510 NumFPRSpills += 2;

2511 else if (ARM::QPRRegClass.contains(Reg))

2512 NumFPRSpills += 4;

2513 }

2514 continue;

2515 }

2516

2517 if (Spilled) {

2518 NumGPRSpills++;

2519

2521 if (Reg == ARM::LR)

2522 LRSpilled = true;

2523 CS1Spilled = true;

2524 continue;

2525 }

2526

2527

2528 switch (Reg) {

2529 case ARM::LR:

2530 LRSpilled = true;

2531 [[fallthrough]];

2532 case ARM::R0: case ARM::R1:

2533 case ARM::R2: case ARM::R3:

2534 case ARM::R4: case ARM::R5:

2535 case ARM::R6: case ARM::R7:

2536 CS1Spilled = true;

2537 break;

2538 default:

2539 break;

2540 }

2541 } else {

2543 UnspilledCS1GPRs.push_back(Reg);

2544 continue;

2545 }

2546

2547 switch (Reg) {

2548 case ARM::R0: case ARM::R1:

2549 case ARM::R2: case ARM::R3:

2550 case ARM::R4: case ARM::R5:

2551 case ARM::R6: case ARM::R7:

2552 case ARM::LR:

2553 UnspilledCS1GPRs.push_back(Reg);

2554 break;

2555 default:

2556 UnspilledCS2GPRs.push_back(Reg);

2557 break;

2558 }

2559 }

2560 }

2561

2562 bool ForceLRSpill = false;

2565

2566

2567 if (FnSize >= (1 << 11)) {

2568 CanEliminateFrame = false;

2569 ForceLRSpill = true;

2570 }

2571 }

2572

2573

2574

2575

2576

2577

2578

2579

2580

2581

2582

2583

2584

2585

2586

2587 unsigned EstimatedStackSize =

2588 MFI.estimateStackSize(MF) + 4 * (NumGPRSpills + NumFPRSpills);

2589

2590

2591 int MaxFixedOffset = 0;

2592 for (int I = MFI.getObjectIndexBegin(); I < 0; ++I) {

2593 int MaxObjectOffset = MFI.getObjectOffset(I) + MFI.getObjectSize(I);

2594 MaxFixedOffset = std::max(MaxFixedOffset, MaxObjectOffset);

2595 }

2596

2597 bool HasFP = hasFP(MF);

2598 if (HasFP) {

2600 EstimatedStackSize += 4;

2601 } else {

2602

2603

2604 EstimatedStackSize += MaxFixedOffset;

2605 }

2606 EstimatedStackSize += 16;

2607

2608 unsigned EstimatedRSStackSizeLimit, EstimatedRSFixedSizeLimit;

2609 bool HasNonSPFrameIndex = false;

2611

2612

2613

2614

2615

2616

2617

2618

2619

2620

2621

2622

2623

2624

2625

2626

2627

2628

2630 EstimatedRSStackSizeLimit = (1U << 5) * 4;

2631 else

2632 EstimatedRSStackSizeLimit = (1U << 8) * 4;

2633 EstimatedRSFixedSizeLimit = (1U << 5) * 4;

2634 } else {

2635 EstimatedRSStackSizeLimit =

2637 EstimatedRSFixedSizeLimit = EstimatedRSStackSizeLimit;

2638 }

2639

2640

2641 bool HasLargeStack = EstimatedStackSize > EstimatedRSStackSizeLimit;

2642

2643

2644

2645

2646

2647 bool HasMovingSP = MFI.hasVarSizedObjects() ||

2649 bool HasBPOrFixedSP = RegInfo->hasBasePointer(MF) || !HasMovingSP;

2650

2651

2652

2653

2654

2655

2656

2658 bool HasLargeArgumentList =

2659 HasFP && (MaxFixedOffset - MaxFPOffset) > (int)EstimatedRSFixedSizeLimit;

2660

2661 bool BigFrameOffsets = HasLargeStack || !HasBPOrFixedSP ||

2662 HasLargeArgumentList || HasNonSPFrameIndex;

2663 LLVM_DEBUG(dbgs() << "EstimatedLimit: " << EstimatedRSStackSizeLimit

2664 << "; EstimatedStack: " << EstimatedStackSize

2665 << "; EstimatedFPStack: " << MaxFixedOffset - MaxFPOffset

2666 << "; BigFrameOffsets: " << BigFrameOffsets << "\n");

2667 if (BigFrameOffsets ||

2670

2671 if (HasFP) {

2673

2674

2677 !LRSpilled) {

2678 SavedRegs.set(ARM::LR);

2679 LRSpilled = true;

2680 NumGPRSpills++;

2681 auto LRPos = llvm::find(UnspilledCS1GPRs, ARM::LR);

2682 if (LRPos != UnspilledCS1GPRs.end())

2683 UnspilledCS1GPRs.erase(LRPos);

2684 }

2686 if (FPPos != UnspilledCS1GPRs.end())

2687 UnspilledCS1GPRs.erase(FPPos);

2688 NumGPRSpills++;

2690 CS1Spilled = true;

2691 }

2692

2693

2694

2695

2696

2697

2698

2699

2700

2701

2702

2703

2704

2705 unsigned NumExtraCSSpill = 0;

2706

2708

2709

2710

2711

2712

2713

2714

2715

2716

2717

2719

2720

2721

2722 int EntryRegDeficit = 0;

2723 for (unsigned Reg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3}) {

2725 --EntryRegDeficit;

2728 << " is unused argument register, EntryRegDeficit = "

2729 << EntryRegDeficit << "\n");

2730 }

2731 }

2732

2733

2736 << " return regs used, ExitRegDeficit = "

2737 << ExitRegDeficit << "\n");

2738

2739 int RegDeficit = std::max(EntryRegDeficit, ExitRegDeficit);

2740 LLVM_DEBUG(dbgs() << "RegDeficit = " << RegDeficit << "\n");

2741

2742

2743

2744 for (unsigned Reg : {ARM::R4, ARM::R5, ARM::R6}) {

2745 if (SavedRegs.test(Reg)) {

2746 --RegDeficit;

2748 << " is saved low register, RegDeficit = "

2749 << RegDeficit << "\n");

2750 } else {

2755 << " is non-saved low register, adding to AvailableRegs\n");

2756 }

2757 }

2758

2759

2760 if (!HasFP || FramePtr != ARM::R7) {

2761 if (SavedRegs.test(ARM::R7)) {

2762 --RegDeficit;

2763 LLVM_DEBUG(dbgs() << "%r7 is saved low register, RegDeficit = "

2764 << RegDeficit << "\n");

2765 } else {

2766 AvailableRegs.push_back(ARM::R7);

2769 << "%r7 is non-saved low register, adding to AvailableRegs\n");

2770 }

2771 }

2772

2773

2774 for (unsigned Reg : {ARM::R8, ARM::R9, ARM::R10, ARM::R11}) {

2775 if (SavedRegs.test(Reg)) {

2776 ++RegDeficit;

2778 << " is saved high register, RegDeficit = "

2779 << RegDeficit << "\n");

2780 }

2781 }

2782

2783

2784

2785

2786 if ((EntryRegDeficit > ExitRegDeficit) &&

2789 if (SavedRegs.test(ARM::LR)) {

2790 --RegDeficit;

2791 LLVM_DEBUG(dbgs() << "%lr is saved register, RegDeficit = "

2792 << RegDeficit << "\n");

2793 } else {

2794 AvailableRegs.push_back(ARM::LR);

2795 LLVM_DEBUG(dbgs() << "%lr is not saved, adding to AvailableRegs\n");

2796 }

2797 }

2798

2799

2800

2801

2802

2803

2804 LLVM_DEBUG(dbgs() << "Final RegDeficit = " << RegDeficit << "\n");

2805 for (; RegDeficit > 0 && !AvailableRegs.empty(); --RegDeficit) {

2806 unsigned Reg = AvailableRegs.pop_back_val();

2808 << " to make up reg deficit\n");

2809 SavedRegs.set(Reg);

2810 NumGPRSpills++;

2811 CS1Spilled = true;

2812 assert(MRI.isReserved(Reg) && "Should not be reserved");

2813 if (Reg != ARM::LR && MRI.isPhysRegUsed(Reg))

2814 NumExtraCSSpill++;

2815 UnspilledCS1GPRs.erase(llvm::find(UnspilledCS1GPRs, Reg));

2816 if (Reg == ARM::LR)

2817 LRSpilled = true;

2818 }

2819 LLVM_DEBUG(dbgs() << "After adding spills, RegDeficit = " << RegDeficit

2820 << "\n");

2821 }

2822

2823

2824

2826

2827

2828

2829 if (!LRSpilled && CS1Spilled && !ExpensiveLRRestore) {

2830 SavedRegs.set(ARM::LR);

2831 NumGPRSpills++;

2833 LRPos = llvm::find(UnspilledCS1GPRs, (unsigned)ARM::LR);

2834 if (LRPos != UnspilledCS1GPRs.end())

2835 UnspilledCS1GPRs.erase(LRPos);

2836

2837 ForceLRSpill = false;

2838 if (MRI.isReserved(ARM::LR) && MRI.isPhysRegUsed(ARM::LR) &&

2840 NumExtraCSSpill++;

2841 }

2842

2843

2844

2845

2846 LLVM_DEBUG(dbgs() << "NumGPRSpills = " << NumGPRSpills << "\n");

2848 if (TargetAlign >= Align(8) && (NumGPRSpills & 1)) {

2849 if (CS1Spilled && !UnspilledCS1GPRs.empty()) {

2850 for (unsigned Reg : UnspilledCS1GPRs) {

2851

2852

2856 (Reg == ARM::LR && !ExpensiveLRRestore)) {

2857 SavedRegs.set(Reg);

2859 << " to make up alignment\n");

2860 if (MRI.isReserved(Reg) && MRI.isPhysRegUsed(Reg) &&

2862 NumExtraCSSpill++;

2863 break;

2864 }

2865 }

2867 unsigned Reg = UnspilledCS2GPRs.front();

2868 SavedRegs.set(Reg);

2870 << " to make up alignment\n");

2871 if (MRI.isReserved(Reg) && MRI.isPhysRegUsed(Reg))

2872 NumExtraCSSpill++;

2873 }

2874 }

2875

2876

2877

2878

2879

2880

2881

2882 unsigned RegsNeeded = 0;

2884 RegsNeeded++;

2885

2886

2888 RegsNeeded++;

2889 }

2890

2891 if (RegsNeeded > NumExtraCSSpill) {

2892

2893

2894 unsigned NumExtras = TargetAlign.value() / 4;

2896 while (NumExtras && !UnspilledCS1GPRs.empty()) {

2897 unsigned Reg = UnspilledCS1GPRs.pop_back_val();

2898 if (MRI.isReserved(Reg) &&

2901 NumExtras--;

2902 }

2903 }

2904

2906 while (NumExtras && !UnspilledCS2GPRs.empty()) {

2907 unsigned Reg = UnspilledCS2GPRs.pop_back_val();

2908 if (MRI.isReserved(Reg)) {

2910 NumExtras--;

2911 }

2912 }

2913 }

2914 if (NumExtras == 0) {

2915 for (unsigned Reg : Extras) {

2916 SavedRegs.set(Reg);

2917 if (MRI.isPhysRegUsed(Reg))

2918 NumExtraCSSpill++;

2919 }

2920 }

2921 while ((RegsNeeded > NumExtraCSSpill) && RS) {

2922

2923 LLVM_DEBUG(dbgs() << "Reserving emergency spill slot\n");

2925 unsigned Size = TRI->getSpillSize(RC);

2926 Align Alignment = TRI->getSpillAlign(RC);

2928 MFI.CreateSpillStackObject(Size, Alignment));

2929 --RegsNeeded;

2930 }

2931 }

2932 }

2933

2934 if (ForceLRSpill)

2935 SavedRegs.set(ARM::LR);

2937}

2938

2942 return;

2943

2944

2945

2946

2948 if (Info.getReg() != ARM::LR)

2949 continue;

2952 return !Term.isReturn() || Term.getOpcode() == ARM::LDMIA_RET ||

2953 Term.getOpcode() == ARM::t2LDMIA_RET ||

2954 Term.getOpcode() == ARM::tPOP_RET;

2955 });

2956 })) {

2957 Info.setRestored(false);

2958 break;

2959 }

2960 }

2961}

2962

2967}

2968

2972

2973

2974

2975

2978 SavedRegs.set(ARM::R0);

2979}

2980

2983 std::vector &CSI) const {

2984

2985

2986 if (STI.hasV8_1MMainlineOps() &&

2988 CSI.emplace_back(ARM::FPCXTNS);

2989 CSI.back().setRestored(false);

2990 }

2991

2992

2993

2994

2997

2998

2999

3000

3003

3005 [=](const auto &CS) {

3007 return Reg == ARM::R10 || Reg == ARM::R11 ||

3008 Reg == ARM::R8 || Reg == ARM::R9 ||

3009 ARM::DPRRegClass.contains(Reg);

3010 }),

3012 break;

3014

3015

3017 break;

3020 "ABI-required frame pointers need a CSR split when signing return "

3021 "address.");

3023 [=](const auto &CS) {

3025 return Reg != ARM::LR;

3026 }),

3028 break;

3029 default:

3030 llvm_unreachable("Unexpected CSR split with return address signing");

3031 }

3032 }

3033

3034 return false;

3035}

3036

3039 static const SpillSlot FixedSpillOffsets[] = {{ARM::FPCXTNS, -4}};

3040 NumEntries = std::size(FixedSpillOffsets);

3041 return FixedSpillOffsets;

3042}

3043

3052 unsigned Opc = I->getOpcode();

3053 bool IsDestroy = Opc == TII.getCallFrameDestroyOpcode();

3054 unsigned CalleePopAmount = IsDestroy ? I->getOperand(1).getImm() : 0;

3055

3057 "This eliminateCallFramePseudoInstr does not support Thumb1!");

3058

3059 int PIdx = I->findFirstPredOperandIdx();

3063 unsigned PredReg = TII.getFramePred(*I);

3064

3066

3067 if (IsDestroy && CalleePopAmount != -1U)

3069

3070

3071

3072

3073 unsigned Amount = TII.getFrameSize(*I);

3074 if (Amount != 0) {

3075

3076

3077

3079

3080 if (Opc == ARM::ADJCALLSTACKDOWN || Opc == ARM::tADJCALLSTACKDOWN) {

3082 Pred, PredReg);

3083 } else {

3084 assert(Opc == ARM::ADJCALLSTACKUP || Opc == ARM::tADJCALLSTACKUP);

3086 Pred, PredReg);

3087 }

3088 }

3089 } else if (CalleePopAmount != -1U) {

3090

3091

3094 }

3096}

3097

3098

3099

3100

3101

3103 unsigned Shifted = 0;

3104

3106 return 0;

3107

3108 while (!(Value & 0xC0000000)) {

3110 Shifted += 2;

3111 }

3112

3113 bool Carry = (Value & 0x00FFFFFF);

3114 Value = ((Value & 0xFF000000) >> 24) + Carry;

3115

3116 if (Value & 0x0000100)

3118

3119 if (Shifted > 24)

3121 else

3123

3125}

3126

3127

3128

3130

3131

3132

3133

3134

3135

3136

3137

3138

3139

3140

3141

3142

3143

3144

3145

3146

3147

3148

3149

3150

3151

3152

3153

3154

3157 unsigned Opcode;

3158 unsigned CFIIndex;

3160 bool Thumb = ST->isThumb();

3161 bool Thumb2 = ST->isThumb2();

3162

3163

3164

3166 report_fatal_error("Segmented stacks do not support vararg functions.");

3167 if (!ST->isTargetAndroid() && !ST->isTargetLinux())

3168 report_fatal_error("Segmented stacks not supported on this platform.");

3169

3177

3179 return;

3180

3182

3183

3184

3185 unsigned ScratchReg0 = ARM::R4;

3186 unsigned ScratchReg1 = ARM::R5;

3187 unsigned MovOp = ST->useMovt() ? ARM::t2MOVi32imm : ARM::tMOVi32imm;

3189

3195

3196

3199 WalkList.push_back(&PrologueMBB);

3200

3201 do {

3204 if (BeforePrologueRegion.insert(PredBB).second)

3206 }

3207 } while (!WalkList.empty());

3208

3209

3210

3211

3212

3213 MachineBasicBlock *AddedBlocks[] = {PrevStackMBB, McrMBB, GetMBB, AllocMBB,

3214 PostStackMBB};

3215

3217 BeforePrologueRegion.insert(B);

3218

3219 for (const auto &LI : PrologueMBB.liveins()) {

3221 PredBB->addLiveIn(LI);

3222 }

3223

3224

3225

3227 BeforePrologueRegion.erase(B);

3229 }

3230

3232

3234

3235

3238 }

3239

3240

3242

3243

3244

3246

3247

3248

3249

3250

3251

3252

3253

3254 if (Thumb) {

3255 BuildMI(PrevStackMBB, DL, TII.get(ARM::tPUSH))

3257 .addReg(ScratchReg0)

3258 .addReg(ScratchReg1);

3259 } else {

3260 BuildMI(PrevStackMBB, DL, TII.get(ARM::STMDB_UPD))

3264 .addReg(ScratchReg0)

3265 .addReg(ScratchReg1);

3266 }

3267

3268

3269

3272 BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3275 nullptr, MRI->getDwarfRegNum(ScratchReg1, true), -4));

3276 BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3279 nullptr, MRI->getDwarfRegNum(ScratchReg0, true), -8));

3280 BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3282 }

3283

3284

3285 if (Thumb) {

3286 BuildMI(McrMBB, DL, TII.get(ARM::tMOVr), ScratchReg1)

3289 } else if (CompareStackPointer) {

3290 BuildMI(McrMBB, DL, TII.get(ARM::MOVr), ScratchReg1)

3294 }

3295

3296

3297 if (!CompareStackPointer && Thumb) {

3298 if (AlignedStackSize < 256) {

3299 BuildMI(McrMBB, DL, TII.get(ARM::tSUBi8), ScratchReg1)

3301 .addReg(ScratchReg1)

3302 .addImm(AlignedStackSize)

3304 } else {

3305 if (Thumb2 || ST->genExecuteOnly()) {

3306 BuildMI(McrMBB, DL, TII.get(MovOp), ScratchReg0)

3307 .addImm(AlignedStackSize);

3308 } else {

3309 auto MBBI = McrMBB->end();

3312 AlignedStackSize);

3313 }

3314 BuildMI(McrMBB, DL, TII.get(ARM::tSUBrr), ScratchReg1)

3316 .addReg(ScratchReg1)

3317 .addReg(ScratchReg0)

3319 }

3320 } else if (!CompareStackPointer) {

3321 if (AlignedStackSize < 256) {

3322 BuildMI(McrMBB, DL, TII.get(ARM::SUBri), ScratchReg1)

3324 .addImm(AlignedStackSize)

3327 } else {

3328 auto MBBI = McrMBB->end();

3331 AlignedStackSize);

3332 BuildMI(McrMBB, DL, TII.get(ARM::SUBrr), ScratchReg1)

3334 .addReg(ScratchReg0)

3337 }

3338 }

3339

3340 if (Thumb && ST->isThumb1Only()) {

3341 if (ST->genExecuteOnly()) {

3342 BuildMI(GetMBB, DL, TII.get(MovOp), ScratchReg0)

3344 } else {

3350

3351

3352 BuildMI(GetMBB, DL, TII.get(ARM::tLDRpci), ScratchReg0)

3355 }

3356

3357

3358 BuildMI(GetMBB, DL, TII.get(ARM::tLDRi), ScratchReg0)

3359 .addReg(ScratchReg0)

3362 } else {

3363

3364

3365 BuildMI(McrMBB, DL, TII.get(Thumb ? ARM::t2MRC : ARM::MRC),

3366 ScratchReg0)

3373

3374

3375 assert(ST->isTargetAndroid() || ST->isTargetLinux());

3376 unsigned TlsOffset = ST->isTargetAndroid() ? 63 : 1;

3377

3378

3379

3380 BuildMI(GetMBB, DL, TII.get(Thumb ? ARM::t2LDRi12 : ARM::LDRi12),

3381 ScratchReg0)

3382 .addReg(ScratchReg0)

3383 .addImm(4 * TlsOffset)

3385 }

3386

3387

3388

3389 Opcode = Thumb ? ARM::tCMPr : ARM::CMPrr;

3391 .addReg(ScratchReg0)

3392 .addReg(ScratchReg1)

3394

3395

3396 Opcode = Thumb ? ARM::tBcc : ARM::Bcc;

3398 .addMBB(PostStackMBB)

3401

3402

3403

3404

3405

3406

3407

3408 if (Thumb) {

3409 if (AlignedStackSize < 256) {

3410 BuildMI(AllocMBB, DL, TII.get(ARM::tMOVi8), ScratchReg0)

3412 .addImm(AlignedStackSize)

3414 } else {

3415 if (Thumb2 || ST->genExecuteOnly()) {

3416 BuildMI(AllocMBB, DL, TII.get(MovOp), ScratchReg0)

3417 .addImm(AlignedStackSize);

3418 } else {

3419 auto MBBI = AllocMBB->end();

3422 AlignedStackSize);

3423 }

3424 }

3425 } else {

3426 if (AlignedStackSize < 256) {

3427 BuildMI(AllocMBB, DL, TII.get(ARM::MOVi), ScratchReg0)

3428 .addImm(AlignedStackSize)

3431 } else {

3432 auto MBBI = AllocMBB->end();

3435 AlignedStackSize);

3436 }

3437 }

3438

3439

3440

3441 if (Thumb) {

3443 BuildMI(AllocMBB, DL, TII.get(ARM::tMOVi8), ScratchReg1)

3447 } else {

3448 if (Thumb2 || ST->genExecuteOnly()) {

3449 BuildMI(AllocMBB, DL, TII.get(MovOp), ScratchReg1)

3451 } else {

3452 auto MBBI = AllocMBB->end();

3455 *AllocMBB, MBBI, DL, ScratchReg1, 0,

3457 }

3458 }

3459 } else {

3461 BuildMI(AllocMBB, DL, TII.get(ARM::MOVi), ScratchReg1)

3465 } else {

3466 auto MBBI = AllocMBB->end();

3469 *AllocMBB, MBBI, DL, ScratchReg1, 0,

3471 }

3472 }

3473

3474

3475 if (Thumb) {

3479 } else {

3480 BuildMI(AllocMBB, DL, TII.get(ARM::STMDB_UPD))

3485 }

3486

3487

3488

3491 BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3494 nullptr, MRI->getDwarfRegNum(ARM::LR, true), -12));

3495 BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3497 }

3498

3499

3500 if (Thumb) {

3504 } else {

3507 }

3508

3509

3510 if (Thumb) {

3511 if (ST->isThumb1Only()) {

3514 .addReg(ScratchReg0);

3515 BuildMI(AllocMBB, DL, TII.get(ARM::tMOVr), ARM::LR)

3516 .addReg(ScratchReg0)

3518 } else {

3519 BuildMI(AllocMBB, DL, TII.get(ARM::t2LDR_POST))

3525 }

3526 } else {

3527 BuildMI(AllocMBB, DL, TII.get(ARM::LDMIA_UPD))

3532 }

3533

3534

3535

3536

3537

3538 if (Thumb) {

3541 .addReg(ScratchReg0)

3542 .addReg(ScratchReg1);

3543 } else {

3544 BuildMI(AllocMBB, DL, TII.get(ARM::LDMIA_UPD))

3548 .addReg(ScratchReg0)

3549 .addReg(ScratchReg1);

3550 }

3551

3552

3555 BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3557 }

3558

3559

3561

3562

3563

3564 if (Thumb) {

3565 BuildMI(PostStackMBB, DL, TII.get(ARM::tPOP))

3567 .addReg(ScratchReg0)

3568 .addReg(ScratchReg1);

3569 } else {

3570 BuildMI(PostStackMBB, DL, TII.get(ARM::LDMIA_UPD))

3574 .addReg(ScratchReg0)

3575 .addReg(ScratchReg1);

3576 }

3577

3578

3581 BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3583

3584

3585

3587 nullptr, MRI->getDwarfRegNum(ScratchReg0, true)));

3588 BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3591 nullptr, MRI->getDwarfRegNum(ScratchReg1, true)));

3592 BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))

3594 }

3595

3596

3598

3600

3603

3605

3607

3608#ifdef EXPENSIVE_CHECKS

3610#endif

3611}

unsigned const MachineRegisterInfo * MRI

static int64_t getArgumentStackToRestore(MachineFunction &MF, MachineBasicBlock &MBB)

Returns how much of the incoming argument stack area (in bytes) we should clean up in an epilogue.

static bool needsWinCFI(const MachineFunction &MF)

static unsigned estimateRSStackSizeLimit(MachineFunction &MF)

Look at each instruction that references stack frames and return the stack size limit beyond which so...

static bool isThumb(const MCSubtargetInfo &STI)

static MachineBasicBlock::iterator skipAlignedDPRCS2Spills(MachineBasicBlock::iterator MI, unsigned NumAlignedDPRCS2Regs)

Skip past the code inserted by emitAlignedDPRCS2Spills, and return an iterator to the following instr...

static void emitAligningInstructions(MachineFunction &MF, ARMFunctionInfo *AFI, const TargetInstrInfo &TII, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, const unsigned Reg, const Align Alignment, const bool MustBeSingleInstruction)

Emit an instruction sequence that will align the address in register Reg by zero-ing out the lower bi...

static uint32_t alignToARMConstant(uint32_t Value)

Get the minimum constant for ARM that is greater than or equal to the argument.

static void checkNumAlignedDPRCS2Regs(MachineFunction &MF, BitVector &SavedRegs)

static void insertSEHRange(MachineBasicBlock &MBB, MachineBasicBlock::iterator Start, const MachineBasicBlock::iterator &End, const ARMBaseInstrInfo &TII, unsigned MIFlags)

static void emitAlignedDPRCS2Restores(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, unsigned NumAlignedDPRCS2Regs, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI)

Emit aligned reload instructions for NumAlignedDPRCS2Regs D-registers starting from d8.

static void emitAlignedDPRCS2Spills(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, unsigned NumAlignedDPRCS2Regs, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI)

Emit aligned spill instructions for NumAlignedDPRCS2Regs D-registers starting from d8.

static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, const ARMBaseInstrInfo &TII, int NumBytes, unsigned MIFlags=MachineInstr::NoFlags, ARMCC::CondCodes Pred=ARMCC::AL, unsigned PredReg=0)

static unsigned EstimateFunctionSizeInBytes(const MachineFunction &MF, const ARMBaseInstrInfo &TII)

static MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI, const TargetInstrInfo &TII, unsigned Flags)

SpillArea getSpillArea(Register Reg, ARMSubtarget::PushPopSplitVariation Variation, unsigned NumAlignedDPRCS2Regs, const ARMBaseRegisterInfo *RegInfo)

Get the spill area that Reg should be saved into in the prologue.

static bool canSpillOnFrameIndexAccess(const MachineFunction &MF, const TargetFrameLowering &TFI)

static bool WindowsRequiresStackProbe(const MachineFunction &MF, size_t StackSizeInBytes)

static int getMaxFPOffset(const ARMSubtarget &STI, const ARMFunctionInfo &AFI, const MachineFunction &MF)

We need the offset of the frame pointer relative to other MachineFrameInfo offsets which are encoded ...

static MachineBasicBlock::iterator initMBBRange(MachineBasicBlock &MBB, const MachineBasicBlock::iterator &MBBI)

static int sizeOfSPAdjustment(const MachineInstr &MI)

static const uint64_t kSplitStackAvailable

static cl::opt< bool > SpillAlignedNEONRegs("align-neon-spills", cl::Hidden, cl::init(true), cl::desc("Align ARM NEON spills in prolog and epilog"))

static void emitRegPlusImmediate(bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, const ARMBaseInstrInfo &TII, unsigned DestReg, unsigned SrcReg, int NumBytes, unsigned MIFlags=MachineInstr::NoFlags, ARMCC::CondCodes Pred=ARMCC::AL, unsigned PredReg=0)

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

MachineBasicBlock MachineBasicBlock::iterator MBBI

This file contains the simple types necessary to represent the attributes associated with functions a...

This file implements the BitVector class.

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Analysis containing CSE Info

const HexagonInstrInfo * TII

This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...

unsigned const TargetRegisterInfo * TRI

This file declares the machine register scavenger class.

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

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

This file defines the SmallPtrSet class.

This file defines the SmallVector class.

static const unsigned FramePtr

bool hasBasePointer(const MachineFunction &MF) const

virtual void emitLoadConstPool(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, Register DestReg, unsigned SubIdx, int Val, ARMCC::CondCodes Pred=ARMCC::AL, Register PredReg=Register(), unsigned MIFlags=MachineInstr::NoFlags) const

emitLoadConstPool - Emits a load from constpool to materialize the specified immediate.

const MCPhysReg * getCalleeSavedRegs(const MachineFunction *MF) const override

Code Generation virtual methods...

bool cannotEliminateFrame(const MachineFunction &MF) const

Register getFrameRegister(const MachineFunction &MF) const override

bool canRealignStack(const MachineFunction &MF) const override

Register getBaseRegister() const

static ARMConstantPoolSymbol * Create(LLVMContext &C, StringRef s, unsigned ID, unsigned char PCAdj)

ARMConstantPoolValue - ARM specific constantpool value.

bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override

restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...

StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const override

getFrameIndexReference - Provide a base+offset reference to an FI slot for debug info.

bool keepFramePointer(const MachineFunction &MF) const

static void updateLRRestored(MachineFunction &MF)

Update the IsRestored flag on LR if it is spilled, based on the return instructions.

void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override

emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.

ARMFrameLowering(const ARMSubtarget &sti)

bool enableShrinkWrapping(const MachineFunction &MF) const override

Returns true if the target will correctly handle shrink wrapping.

void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override

bool requiresAAPCSFrameRecord(const MachineFunction &MF) const

bool isFPReserved(const MachineFunction &MF) const

isFPReserved - Return true if the frame pointer register should be considered a reserved register on ...

bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override

canSimplifyCallFramePseudos - If there is a reserved call frame, the call frame pseudos can be simpli...

void adjustForSegmentedStacks(MachineFunction &MF, MachineBasicBlock &MBB) const override

Adjust the prologue to have the function use segmented stacks.

bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override

spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...

bool hasReservedCallFrame(const MachineFunction &MF) const override

hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...

const SpillSlot * getCalleeSavedSpillSlots(unsigned &NumEntries) const override

getCalleeSavedSpillSlots - This method returns a pointer to an array of pairs, that contains an entry...

void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS=nullptr) const override

processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...

bool hasFPImpl(const MachineFunction &MF) const override

hasFPImpl - Return true if the specified function should have a dedicated frame pointer register.

int ResolveFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg, int SPAdj) const

void getCalleeSaves(const MachineFunction &MF, BitVector &SavedRegs) const override

Returns the callee-saved registers as computed by determineCalleeSaves in the BitVector SavedRegs.

void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override

This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...

bool enableCalleeSaveSkip(const MachineFunction &MF) const override

Returns true if the target can safely skip saving callee-saved registers for noreturn nounwind functi...

bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector< CalleeSavedInfo > &CSI) const override

ARMFunctionInfo - This class is derived from MachineFunctionInfo and contains private ARM-specific in...

bool hasStackFrame() const

bool isThumb2Function() const

unsigned getFPCXTSaveAreaSize() const

unsigned getGPRCalleeSavedArea1Size() const

unsigned getDPRCalleeSavedGapSize() const

unsigned getDPRCalleeSavedArea1Size() const

unsigned createPICLabelUId()

void setLRIsSpilled(bool s)

void setDPRCalleeSavedArea1Offset(unsigned o)

void setGPRCalleeSavedArea2Size(unsigned s)

bool isThumb1OnlyFunction() const

void setHasStackFrame(bool s)

bool isThumbFunction() const

void setFramePtrSpillOffset(unsigned o)

unsigned getGPRCalleeSavedArea2Size() const

unsigned getNumAlignedDPRCS2Regs() const

bool shouldSignReturnAddress() const

void setGPRCalleeSavedArea1Size(unsigned s)

unsigned getArgumentStackToRestore() const

void setFPCXTSaveAreaSize(unsigned s)

bool isCmseNSEntryFunction() const

unsigned getGPRCalleeSavedArea3Size() const

unsigned getFramePtrSpillOffset() const

bool shouldRestoreSPFromFP() const

unsigned getArgRegsSaveSize() const

void setGPRCalleeSavedArea2Offset(unsigned o)

void setGPRCalleeSavedArea1Offset(unsigned o)

void setDPRCalleeSavedArea1Size(unsigned s)

void setDPRCalleeSavedGapSize(unsigned s)

unsigned getArgumentStackSize() const

void setShouldRestoreSPFromFP(bool s)

unsigned getReturnRegsCount() const

void setGPRCalleeSavedArea3Size(unsigned s)

bool getPreservesR0() const

const ARMBaseInstrInfo * getInstrInfo() const override

bool isTargetWindows() const

const ARMBaseRegisterInfo * getRegisterInfo() const override

enum PushPopSplitVariation getPushPopSplitVariation(const MachineFunction &MF) const

PushPopSplitVariation

How the push and pop instructions of callee saved general-purpose registers should be split.

@ SplitR11WindowsSEH

When the stack frame size is not known (because of variable-sized objects or realignment),...

@ SplitR7

R7 and LR must be adjacent, because R7 is the frame pointer, and must point to a frame record consist...

@ SplitR11AAPCSSignRA

When generating AAPCS-compilant frame chains, R11 is the frame pointer, and must be pushed adjacent t...

@ NoSplit

All GPRs can be pushed in a single instruction.

const ARMFrameLowering * getFrameLowering() const override

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

size_t size() const

size - Get the array size.

bool empty() const

empty - Check if the array is empty.

bool test(unsigned Idx) const

The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...

This class represents an Operation in the Expression.

CallingConv::ID getCallingConv() const

getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...

LLVMContext & getContext() const

getContext - Return a reference to the LLVMContext associated with this function.

bool isVarArg() const

isVarArg - Return true if this function takes a variable number of arguments.

bool hasFnAttribute(Attribute::AttrKind Kind) const

Return true if the function has the attribute.

bool usesWindowsCFI() const

static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc={})

.cfi_def_cfa_register modifies a rule for computing CFA.

static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})

.cfi_def_cfa defines a rule for computing CFA as: take address from Register and add Offset to it.

static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})

.cfi_offset Previous value of Register is saved at offset Offset from CFA.

static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc={})

.cfi_def_cfa_offset modifies a rule for computing CFA.

static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, SMLoc Loc={})

.cfi_same_value Current value of Register is the same as in the previous frame.

Context object for machine code objects.

const MCRegisterInfo * getRegisterInfo() const

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

MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...

Wrapper class representing physical registers. Should be passed by value.

iterator_range< livein_iterator > liveins() const

iterator getFirstTerminator()

Returns an iterator to the first terminator instruction of this basic block.

void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())

Add Succ as a successor of this MachineBasicBlock.

void sortUniqueLiveIns()

Sorts and uniques the LiveIns vector.

iterator getLastNonDebugInstr(bool SkipPseudoOp=true)

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

void ReplaceUsesOfBlockWith(MachineBasicBlock *Old, MachineBasicBlock *New)

Given a machine basic block that branched to 'Old', change the code and CFG so that it branches to 'N...

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.

instr_iterator erase(instr_iterator I)

Remove an instruction from the instruction list and delete it.

iterator_range< iterator > terminators()

iterator insertAfter(iterator I, MachineInstr *MI)

Insert MI into the instruction list after I.

bool isSuccessor(const MachineBasicBlock *MBB) const

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

iterator_range< pred_iterator > predecessors()

MachineInstrBundleIterator< MachineInstr > iterator

The MachineConstantPool class keeps track of constants referenced by a function which must be spilled...

const std::vector< MachineConstantPoolEntry > & getConstants() const

unsigned getConstantPoolIndex(const Constant *C, Align Alignment)

getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.

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

bool needsSplitStackProlog() const

Return true if this function requires a split stack prolog, even if it uses no stack space.

bool hasVarSizedObjects() const

This method may be called any time after instruction selection is complete to determine if the stack ...

uint64_t getStackSize() const

Return the number of bytes that must be allocated to hold all of the fixed size frame objects.

bool isReturnAddressTaken() const

This method may be called any time after instruction selection is complete to determine if there is a...

bool isFrameAddressTaken() const

This method may be called any time after instruction selection is complete to determine if there is a...

Align getMaxAlign() const

Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...

uint64_t getMaxCallFrameSize() const

Return the maximum size of a call frame that must be allocated for an outgoing function call.

int getStackProtectorIndex() const

Return the index for the stack protector object.

int64_t getOffsetAdjustment() const

Return the correction for frame offsets.

bool isCalleeSavedInfoValid() const

Has the callee saved info been calculated yet?

BitVector getPristineRegs(const MachineFunction &MF) const

Return a set of physical registers that are pristine.

const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const

Returns a reference to call saved info vector for the current function.

int64_t getObjectOffset(int ObjectIdx) const

Return the assigned stack offset of the specified object from the incoming stack pointer.

bool isFixedObjectIndex(int ObjectIdx) const

Returns true if the specified index corresponds to a fixed stack object.

void setObjectAlignment(int ObjectIdx, Align Alignment)

setObjectAlignment - Change the alignment of the specified stack object.

void setOffsetAdjustment(int64_t Adj)

Set the correction for frame offsets.

unsigned addFrameInst(const MCCFIInstruction &Inst)

void setHasWinCFI(bool v)

const TargetSubtargetInfo & getSubtarget() const

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

StringRef getName() const

getName - Return the name of the corresponding LLVM function.

MachineFrameInfo & getFrameInfo()

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

MCContext & getContext() const

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

bool verify(Pass *p=nullptr, const char *Banner=nullptr, raw_ostream *OS=nullptr, bool AbortOnError=true) const

Run the current MachineFunction through the machine code verifier, useful for debugger use.

Function & getFunction()

Return the LLVM function that this machine code represents.

Ty * getInfo()

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

MachineConstantPool * getConstantPool()

getConstantPool - Return the constant pool object for the current function.

const MachineJumpTableInfo * getJumpTableInfo() const

getJumpTableInfo - Return the jump table info object for the current function.

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

CreateMachineBasicBlock - Allocate a new MachineBasicBlock.

void insert(iterator MBBI, MachineBasicBlock *MBB)

const TargetMachine & getTarget() const

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

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

const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const

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

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & add(const MachineOperand &MO) const

const MachineInstrBuilder & addFrameIndex(int Idx) const

const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int 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 & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const

const MachineInstrBuilder & setMIFlags(unsigned Flags) const

const MachineInstrBuilder & copyImplicitOps(const MachineInstr &OtherMI) const

Copy all the implicit operands from OtherMI onto this one.

bool isValid() const

Check for null.

Representation of each machine instruction.

bool addRegisterKilled(Register IncomingReg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound=false)

We have determined MI kills a register.

const std::vector< MachineJumpTableEntry > & getJumpTables() const

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

bool isLiveIn(Register Reg) const

MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...

void addScavengingFrameIndex(int FI)

Add a scavenging frame index.

Wrapper class representing virtual and physical registers.

bool erase(PtrType Ptr)

Remove pointer from the set.

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

iterator erase(const_iterator CI)

typename SuperClass::iterator 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.

StackOffset holds a fixed and a scalable offset in bytes.

int64_t getFixed() const

Returns the fixed component of the stack.

Information about stack frame layout on the target.

bool hasFP(const MachineFunction &MF) const

hasFP - Return true if the specified function should have a dedicated frame pointer register.

virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS=nullptr) const

This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...

virtual void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS=nullptr) const

processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...

virtual void getCalleeSaves(const MachineFunction &MF, BitVector &SavedRegs) const

Returns the callee-saved registers as computed by determineCalleeSaves in the BitVector SavedRegs.

Align getStackAlign() const

getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...

int alignSPAdjust(int SPAdj) const

alignSPAdjust - This method aligns the stack adjustment to the correct alignment.

virtual StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const

getFrameIndexReference - This method should return the base register and offset used to reference a f...

TargetInstrInfo - Interface to description of machine instruction set.

Primary interface to the complete machine description for the target machine.

const MCAsmInfo * getMCAsmInfo() const

Return target specific asm information.

bool FramePointerIsReserved(const MachineFunction &MF) const

FramePointerIsReserved - This returns true if the frame pointer must always either point to a new fra...

bool DisableFramePointerElim(const MachineFunction &MF) const

DisableFramePointerElim - This returns true if frame pointer elimination optimization should be disab...

bool contains(Register Reg) const

Return true if the specified register is included in this register class.

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

bool hasStackRealignment(const MachineFunction &MF) const

True if stack realignment is required and still possible.

virtual const TargetRegisterInfo * getRegisterInfo() const

getRegisterInfo - If register information is available, return it.

virtual const TargetFrameLowering * getFrameLowering() const

virtual const TargetInstrInfo * getInstrInfo() const

LLVM Value Representation.

An efficient, type-erasing, non-owning reference to a callable.

self_iterator getIterator()

#define llvm_unreachable(msg)

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

unsigned getAM2Opc(AddrOpc Opc, unsigned Imm12, ShiftOpc SO, unsigned IdxMode=0)

unsigned getSORegOpc(ShiftOpc ShOp, unsigned Imm)

@ D16

Only 16 D registers.

@ GHC

Used by the Glasgow Haskell Compiler (GHC).

@ C

The default llvm calling convention, compatible with C.

@ Implicit

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

@ Define

Register definition.

@ Kill

The last use of a register.

Reg

All possible values of the reg field in the ModR/M byte.

initializer< Ty > init(const Ty &Val)

NodeAddr< FuncNode * > Func

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.

void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)

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

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

bool all_of(R &&range, UnaryPredicate P)

Provide wrappers to std::all_of 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.

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.

static bool isSEHInstruction(const MachineInstr &MI)

bool any_of(R &&range, UnaryPredicate P)

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

bool tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget, MachineFunction &MF, MachineInstr *MI, unsigned NumBytes)

Tries to add registers to the reglist of a given base-updating push/pop instruction to adjust the sta...

auto reverse(ContainerTy &&C)

void sort(IteratorTy Start, IteratorTy End)

raw_ostream & dbgs()

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

void report_fatal_error(Error Err, bool gen_crash_diag=true)

Report a serious error, calling any installed error handler.

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

unsigned getDefRegState(bool B)

unsigned getKillRegState(bool B)

auto count(R &&Range, const E &Element)

Wrapper function around std::count to count the number of times an element Element occurs in the give...

static MachineOperand t1CondCodeOp(bool isDead=false)

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

auto find_if(R &&Range, UnaryPredicate P)

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

static MachineOperand condCodeOp(unsigned CCReg=0)

Get the operand corresponding to the conditional code result.

unsigned Log2(Align A)

Returns the log2 of the alignment.

void emitARMRegPlusImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, Register DestReg, Register BaseReg, int NumBytes, ARMCC::CondCodes Pred, Register PredReg, const ARMBaseInstrInfo &TII, unsigned MIFlags=0)

emitARMRegPlusImmediate / emitT2RegPlusImmediate - Emits a series of instructions to materializea des...

Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)

Prints virtual and physical registers with or without a TRI instance.

void emitT2RegPlusImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, Register DestReg, Register BaseReg, int NumBytes, ARMCC::CondCodes Pred, Register PredReg, const ARMBaseInstrInfo &TII, unsigned MIFlags=0)

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

uint64_t value() const

This is a hole in the type system and should not be abused.