aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64CollectLOH.cpp')
-rw-r--r--llvm/lib/Target/AArch64/AArch64CollectLOH.cpp26
1 files changed, 25 insertions, 1 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp b/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
index efdb1131abc9..ac243347b24d 100644
--- a/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
+++ b/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
@@ -419,13 +419,37 @@ static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI,
++NumADRPToLDR;
}
break;
- case MCLOH_AdrpAddLdr:
+ case MCLOH_AdrpAddLdr: {
+ // There is a possibility that the linker may try to rewrite:
+ // adrp x0, @sym@PAGE
+ // add x1, x0, @sym@PAGEOFF
+ // [x0 = some other def]
+ // ldr x2, [x1]
+ // ...into...
+ // adrp x0, @sym
+ // nop
+ // [x0 = some other def]
+ // ldr x2, [x0]
+ // ...if the offset to the symbol won't fit within a literal load.
+ // This causes the load to use the result of the adrp, which in this
+ // case has already been clobbered.
+ // FIXME: Implement proper liveness tracking for all registers. For now,
+ // don't emit the LOH if there are any instructions between the add and
+ // the ldr.
+ MachineInstr *AddMI = const_cast<MachineInstr *>(Info.MI1);
+ const MachineInstr *LdrMI = Info.MI0;
+ auto AddIt = MachineBasicBlock::iterator(AddMI);
+ auto EndIt = AddMI->getParent()->end();
+ if (AddMI->getIterator() == EndIt || LdrMI != &*next_nodbg(AddIt, EndIt))
+ break;
+
LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddLdr:\n"
<< '\t' << MI << '\t' << *Info.MI1 << '\t'
<< *Info.MI0);
AFI.addLOHDirective(MCLOH_AdrpAddLdr, {&MI, Info.MI1, Info.MI0});
++NumADDToLDR;
break;
+ }
case MCLOH_AdrpAddStr:
if (Info.MI1 != nullptr) {
LLVM_DEBUG(dbgs() << "Adding MCLOH_AdrpAddStr:\n"