@@ -213,6 +213,37 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
213213 Inst.getOpcode () == AArch64::ADDXrx64);
214214 }
215215
216+ bool isSUB (const MCInst &Inst) const override {
217+ const unsigned opcode = Inst.getOpcode ();
218+ bool isSubInstr = false ;
219+ switch (opcode) {
220+ case AArch64::SUBSWri:
221+ case AArch64::SUBSWrr:
222+ case AArch64::SUBSWrs:
223+ case AArch64::SUBSWrx:
224+ case AArch64::SUBSXri:
225+ case AArch64::SUBSXrr:
226+ case AArch64::SUBSXrs:
227+ case AArch64::SUBSXrx:
228+ case AArch64::SUBSXrx64:
229+ case AArch64::SUBWri:
230+ case AArch64::SUBWrr:
231+ case AArch64::SUBWrs:
232+ case AArch64::SUBWrx:
233+ case AArch64::SUBXri:
234+ case AArch64::SUBXrr:
235+ case AArch64::SUBXrs:
236+ case AArch64::SUBXrx:
237+ case AArch64::SUBXrx64:
238+ isSubInstr = true ;
239+ break ;
240+ default :
241+ isSubInstr = false ;
242+ break ;
243+ }
244+ return isSubInstr;
245+ }
246+
216247 bool isLDRB (const MCInst &Inst) const {
217248 return (Inst.getOpcode () == AArch64::LDRBBpost ||
218249 Inst.getOpcode () == AArch64::LDRBBpre ||
@@ -652,6 +683,34 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
652683 // / # of this BB)
653684 // / br x0 # Indirect jump instruction
654685 // /
686+ // / adrp + ldr pair instructions of JT
687+ // / adrp x3, :got:jump_table
688+ // / ldr x1, [x1, #value]
689+ // / ldrh w1, [x1, w3, uxtw #1]
690+ // / adr x3, 573ae4
691+ // / add x1, x3, w1, sxth #2
692+ // / br x1
693+ // /
694+ // / lld/test/ELF/aarch64-adrp-ldr-got.s
695+ // / if .rodata and .text are sufficiently (<1M)
696+ // / close to each other so that the adrp + ldr pair can be relaxed to
697+ // / nop + adr.
698+ // / nop #
699+ // / adr x0, #6d8f8 # Get JT table address
700+ // / ldrh w0, [x0, w4, uxtw #1] # Loads JT entry
701+ // / adr x2, 1479b0 # Get PC first instruction for next BB
702+ // / add x0, x2, w0, sxth #2 # Finish building branch target
703+ // / # (entries in JT are relative to the end
704+ // / # of this BB)
705+ // / br x0 # Indirect jump instruction
706+ // /
707+ // / sub + ldr pair instructions of JT, JT address on the stack and other BB
708+ // / sub x1, x29, #0x4, lsl #12
709+ // / ldr x1, [x1, #14352]
710+ // / ldrh w1, [x1, w3, uxtw #1]
711+ // / adr x3, 573ae4
712+ // / add x1, x3, w1, sxth #2
713+ // / br x1
655714 bool analyzeIndirectBranchFragment (
656715 const MCInst &Inst,
657716 DenseMap<const MCInst *, SmallVector<MCInst *, 4 >> &UDChain,
@@ -753,45 +812,77 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
753812
754813 // Match ADD that calculates the JumpTable Base Address (not the offset)
755814 SmallVector<MCInst *, 4 > &UsesLoad = UDChain[DefLoad];
756- const MCInst *DefJTBaseAdd = UsesLoad[1 ];
815+ const MCInst *DefJTPageBias = UsesLoad[1 ];
757816 MCPhysReg From, To;
758- if (DefJTBaseAdd == nullptr || isLoadFromStack (*DefJTBaseAdd) ||
759- isRegToRegMove (*DefJTBaseAdd, From, To)) {
817+ JumpTable = nullptr ;
818+ if (DefJTPageBias == nullptr || isLoadFromStack (*DefJTPageBias) ||
819+ isRegToRegMove (*DefJTPageBias, From, To)) {
760820 // Sometimes base address may have been defined in another basic block
761821 // (hoisted). Return with no jump table info.
762- JumpTable = nullptr ;
763822 return true ;
764823 }
765824
766- if (DefJTBaseAdd->getOpcode () == AArch64::ADR) {
825+ if (isAddXri (*DefJTPageBias)) {
826+ if (DefJTPageBias->getOperand (2 ).isImm ())
827+ Offset = DefJTPageBias->getOperand (2 ).getImm ();
828+ SmallVector<MCInst *, 4 > &UsesJTBaseAdd = UDChain[DefJTPageBias];
829+ const MCInst *DefJTBasePage = UsesJTBaseAdd[1 ];
830+ if (DefJTBasePage == nullptr || isLoadFromStack (*DefJTBasePage)) {
831+ return true ;
832+ }
833+ assert (DefJTBasePage->getOpcode () == AArch64::ADRP &&
834+ " Failed to match jump table base page pattern! (2)" );
835+ if (DefJTBasePage->getOperand (1 ).isExpr ())
836+ JumpTable = DefJTBasePage->getOperand (1 ).getExpr ();
837+ return true ;
838+ } else if (isADR (*DefJTPageBias)) {
767839 // TODO: Handle the pattern where there is no adrp/add pair.
768840 // It also occurs when the binary is static.
769- // adr x13, 0x215a18 <_nl_value_type_LC_COLLATE+0x50>
841+ // nop
842+ // *adr x13, 0x215a18 <_nl_value_type_LC_COLLATE+0x50>
770843 // ldrh w13, [x13, w12, uxtw #1]
771844 // adr x12, 0x247b30 <__gettextparse+0x5b0>
772845 // add x13, x12, w13, sxth #2
773846 // br x13
774- errs () << " BOLT-WARNING: Failed to match indirect branch: "
775- " nop/adr instead of adrp/add \n " ;
776- return false ;
777- }
778-
779- assert (DefJTBaseAdd->getOpcode () == AArch64::ADDXri &&
780- " Failed to match jump table base address pattern! (1)" );
847+ SmallVector<MCInst *, 4 > &UsesJTNop = UDChain[DefJTPageBias];
848+ assert ((UsesJTNop.size () == 1 && UsesJTNop[0 ] == nullptr ) &&
849+ " Failed to match jump table pattern! (2)" );
850+ if (DefJTPageBias->getOperand (1 ).isExpr ()) {
851+ JumpTable = DefJTPageBias->getOperand (1 ).getExpr ();
852+ return true ;
853+ }
854+ } else if (mayLoad (*DefJTPageBias)) {
855+ if (isLoadFromStack (*DefJTPageBias))
856+ return true ;
781857
782- if (DefJTBaseAdd->getOperand (2 ).isImm ())
783- Offset = DefJTBaseAdd->getOperand (2 ).getImm ();
784- SmallVector<MCInst *, 4 > &UsesJTBaseAdd = UDChain[DefJTBaseAdd];
785- const MCInst *DefJTBasePage = UsesJTBaseAdd[1 ];
786- if (DefJTBasePage == nullptr || isLoadFromStack (*DefJTBasePage)) {
787- JumpTable = nullptr ;
788- return true ;
858+ SmallVector<MCInst *, 4 > &UsesJTBase = UDChain[DefJTPageBias];
859+ const MCInst *DefJTBasePage = UsesJTBase[1 ];
860+ if (DefJTBasePage == nullptr )
861+ return true ;
862+ if (DefJTBasePage->getOpcode () == AArch64::ADRP) {
863+ // test jmp-table-pattern-matching.s (3)
864+ if (DefJTBasePage->getOperand (1 ).isExpr ())
865+ JumpTable = DefJTBasePage->getOperand (1 ).getExpr ();
866+ return true ;
867+ } else {
868+ // Base address may have been defined in another basic block
869+ // and sub instruction can be used to get base page address
870+ // jmp-table-pattern-matching.s (2)
871+ if (isSUB (*DefJTBasePage)) {
872+ for (const MCOperand &Operand : useOperands (*DefJTBasePage)) {
873+ if (!Operand.isReg ())
874+ continue ;
875+ const unsigned Reg = Operand.getReg ();
876+ if (Reg == AArch64::SP || Reg == AArch64::WSP ||
877+ Reg == AArch64::FP || Reg == AArch64::W29)
878+ return true ;
879+ }
880+ }
881+ }
789882 }
790- assert (DefJTBasePage->getOpcode () == AArch64::ADRP &&
791- " Failed to match jump table base page pattern! (2)" );
792- if (DefJTBasePage->getOperand (1 ).isExpr ())
793- JumpTable = DefJTBasePage->getOperand (1 ).getExpr ();
794- return true ;
883+
884+ assert (" Failed to match jump table pattern! (4)" );
885+ return false ;
795886 }
796887
797888 DenseMap<const MCInst *, SmallVector<MCInst *, 4 >>
0 commit comments