|
31 | 31 | #include "llvm/CodeGen/MachineBasicBlock.h"
|
32 | 32 | #include "llvm/CodeGen/MachineFunction.h"
|
33 | 33 | #include "llvm/CodeGen/MachineInstr.h"
|
| 34 | +#include "llvm/CodeGen/MachineJumpTableInfo.h" |
| 35 | +#include "llvm/CodeGen/MachineModuleInfoImpls.h" |
34 | 36 | #include "llvm/CodeGen/MachineOperand.h"
|
35 | 37 | #include "llvm/CodeGen/StackMaps.h"
|
36 | 38 | #include "llvm/CodeGen/TargetRegisterInfo.h"
|
@@ -77,6 +79,12 @@ class AArch64AsmPrinter : public AsmPrinter {
|
77 | 79 | return MCInstLowering.lowerOperand(MO, MCOp);
|
78 | 80 | }
|
79 | 81 |
|
| 82 | + void EmitJumpTableInfo() override; |
| 83 | + void emitJumpTableEntry(const MachineJumpTableInfo *MJTI, |
| 84 | + const MachineBasicBlock *MBB, unsigned JTI); |
| 85 | + |
| 86 | + void LowerJumpTableDestSmall(MCStreamer &OutStreamer, const MachineInstr &MI); |
| 87 | + |
80 | 88 | void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
|
81 | 89 | const MachineInstr &MI);
|
82 | 90 | void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
@@ -433,6 +441,104 @@ void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
|
433 | 441 | printOperand(MI, NOps - 2, OS);
|
434 | 442 | }
|
435 | 443 |
|
| 444 | +void AArch64AsmPrinter::EmitJumpTableInfo() { |
| 445 | + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); |
| 446 | + if (!MJTI) return; |
| 447 | + |
| 448 | + const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); |
| 449 | + if (JT.empty()) return; |
| 450 | + |
| 451 | + const TargetLoweringObjectFile &TLOF = getObjFileLowering(); |
| 452 | + MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM); |
| 453 | + OutStreamer->SwitchSection(ReadOnlySec); |
| 454 | + |
| 455 | + auto AFI = MF->getInfo<AArch64FunctionInfo>(); |
| 456 | + for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) { |
| 457 | + const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; |
| 458 | + |
| 459 | + // If this jump table was deleted, ignore it. |
| 460 | + if (JTBBs.empty()) continue; |
| 461 | + |
| 462 | + unsigned Size = AFI->getJumpTableEntrySize(JTI); |
| 463 | + EmitAlignment(Log2_32(Size)); |
| 464 | + OutStreamer->EmitLabel(GetJTISymbol(JTI)); |
| 465 | + |
| 466 | + for (auto *JTBB : JTBBs) |
| 467 | + emitJumpTableEntry(MJTI, JTBB, JTI); |
| 468 | + } |
| 469 | +} |
| 470 | + |
| 471 | +void AArch64AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI, |
| 472 | + const MachineBasicBlock *MBB, |
| 473 | + unsigned JTI) { |
| 474 | + const MCExpr *Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); |
| 475 | + auto AFI = MF->getInfo<AArch64FunctionInfo>(); |
| 476 | + unsigned Size = AFI->getJumpTableEntrySize(JTI); |
| 477 | + |
| 478 | + if (Size == 4) { |
| 479 | + // .word LBB - LJTI |
| 480 | + const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); |
| 481 | + const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF, JTI, OutContext); |
| 482 | + Value = MCBinaryExpr::createSub(Value, Base, OutContext); |
| 483 | + } else { |
| 484 | + // .byte (LBB - LBB) >> 2 (or .hword) |
| 485 | + const MCSymbol *BaseSym = AFI->getJumpTableEntryPCRelSymbol(JTI); |
| 486 | + const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext); |
| 487 | + Value = MCBinaryExpr::createSub(Value, Base, OutContext); |
| 488 | + Value = MCBinaryExpr::createLShr( |
| 489 | + Value, MCConstantExpr::create(2, OutContext), OutContext); |
| 490 | + } |
| 491 | + |
| 492 | + OutStreamer->EmitValue(Value, Size); |
| 493 | +} |
| 494 | + |
| 495 | +/// Small jump tables contain an unsigned byte or half, representing the offset |
| 496 | +/// from the lowest-addressed possible destination to the desired basic |
| 497 | +/// block. Since all instructions are 4-byte aligned, this is further compressed |
| 498 | +/// by counting in instructions rather than bytes (i.e. divided by 4). So, to |
| 499 | +/// materialize the correct destination we need: |
| 500 | +/// |
| 501 | +/// adr xDest, .LBB0_0 |
| 502 | +/// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh). |
| 503 | +/// add xDest, xDest, xScratch, lsl #2 |
| 504 | +void AArch64AsmPrinter::LowerJumpTableDestSmall(llvm::MCStreamer &OutStreamer, |
| 505 | + const llvm::MachineInstr &MI) { |
| 506 | + unsigned DestReg = MI.getOperand(0).getReg(); |
| 507 | + unsigned ScratchReg = MI.getOperand(1).getReg(); |
| 508 | + unsigned ScratchRegW = |
| 509 | + STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32); |
| 510 | + unsigned TableReg = MI.getOperand(2).getReg(); |
| 511 | + unsigned EntryReg = MI.getOperand(3).getReg(); |
| 512 | + int JTIdx = MI.getOperand(4).getIndex(); |
| 513 | + bool IsByteEntry = MI.getOpcode() == AArch64::JumpTableDest8; |
| 514 | + |
| 515 | + // This has to be first because the compression pass based its reachability |
| 516 | + // calculations on the start of the JumpTableDest instruction. |
| 517 | + auto Label = |
| 518 | + MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx); |
| 519 | + EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR) |
| 520 | + .addReg(DestReg) |
| 521 | + .addExpr(MCSymbolRefExpr::create( |
| 522 | + Label, MF->getContext()))); |
| 523 | + |
| 524 | + // Load the number of instruction-steps to offset from the label. |
| 525 | + unsigned LdrOpcode = IsByteEntry ? AArch64::LDRBBroX : AArch64::LDRHHroX; |
| 526 | + EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode) |
| 527 | + .addReg(ScratchRegW) |
| 528 | + .addReg(TableReg) |
| 529 | + .addReg(EntryReg) |
| 530 | + .addImm(0) |
| 531 | + .addImm(IsByteEntry ? 0 : 1)); |
| 532 | + |
| 533 | + // Multiply the steps by 4 and add to the already materialized base label |
| 534 | + // address. |
| 535 | + EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs) |
| 536 | + .addReg(DestReg) |
| 537 | + .addReg(DestReg) |
| 538 | + .addReg(ScratchReg) |
| 539 | + .addImm(2)); |
| 540 | +} |
| 541 | + |
436 | 542 | void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
|
437 | 543 | const MachineInstr &MI) {
|
438 | 544 | unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
|
@@ -662,6 +768,32 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
662 | 768 | return;
|
663 | 769 | }
|
664 | 770 |
|
| 771 | + case AArch64::JumpTableDest32: { |
| 772 | + // We want: |
| 773 | + // ldrsw xScratch, [xTable, xEntry, lsl #2] |
| 774 | + // add xDest, xTable, xScratch |
| 775 | + unsigned DestReg = MI->getOperand(0).getReg(), |
| 776 | + ScratchReg = MI->getOperand(1).getReg(), |
| 777 | + TableReg = MI->getOperand(2).getReg(), |
| 778 | + EntryReg = MI->getOperand(3).getReg(); |
| 779 | + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX) |
| 780 | + .addReg(ScratchReg) |
| 781 | + .addReg(TableReg) |
| 782 | + .addReg(EntryReg) |
| 783 | + .addImm(0) |
| 784 | + .addImm(1)); |
| 785 | + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs) |
| 786 | + .addReg(DestReg) |
| 787 | + .addReg(TableReg) |
| 788 | + .addReg(ScratchReg) |
| 789 | + .addImm(0)); |
| 790 | + return; |
| 791 | + } |
| 792 | + case AArch64::JumpTableDest16: |
| 793 | + case AArch64::JumpTableDest8: |
| 794 | + LowerJumpTableDestSmall(*OutStreamer, *MI); |
| 795 | + return; |
| 796 | + |
665 | 797 | case AArch64::FMOVH0:
|
666 | 798 | case AArch64::FMOVS0:
|
667 | 799 | case AArch64::FMOVD0:
|
|
0 commit comments