//===---------- AArch64CollectLOH.cpp - AArch64 collect LOH pass --*- C++ -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a pass that collect the Linker Optimization Hint (LOH). // This pass should be run at the very end of the compilation flow, just before // assembly printer. // To be useful for the linker, the LOH must be printed into the assembly file. // // A LOH describes a sequence of instructions that may be optimized by the // linker. // This same sequence cannot be optimized by the compiler because some of // the information will be known at link time. // For instance, consider the following sequence: // L1: adrp xA, sym@PAGE // L2: add xB, xA, sym@PAGEOFF // L3: ldr xC, [xB, #imm] // This sequence can be turned into: // A literal load if sym@PAGE + sym@PAGEOFF + #imm - address(L3) is < 1MB: // L3: ldr xC, sym+#imm // It may also be turned into either the following more efficient // code sequences: // - If sym@PAGEOFF + #imm fits the encoding space of L3. // L1: adrp xA, sym@PAGE // L3: ldr xC, [xB, sym@PAGEOFF + #imm] // - If sym@PAGE + sym@PAGEOFF - address(L1) < 1MB: // L1: adr xA, sym // L3: ldr xC, [xB, #imm] // // To be valid a LOH must meet all the requirements needed by all the related // possible linker transformations. // For instance, using the running example, the constraints to emit // ".loh AdrpAddLdr" are: // - L1, L2, and L3 instructions are of the expected type, i.e., // respectively ADRP, ADD (immediate), and LD. // - The result of L1 is used only by L2. // - The register argument (xA) used in the ADD instruction is defined // only by L1. // - The result of L2 is used only by L3. // - The base address (xB) in L3 is defined only L2. // - The ADRP in L1 and the ADD in L2 must reference the same symbol using // @PAGE/@PAGEOFF with no additional constants // // Currently supported LOHs are: // * So called non-ADRP-related: // - .loh AdrpAddLdr L1, L2, L3: // L1: adrp xA, sym@PAGE // L2: add xB, xA, sym@PAGEOFF // L3: ldr xC, [xB, #imm] // - .loh AdrpLdrGotLdr L1, L2, L3: // L1: adrp xA, sym@GOTPAGE // L2: ldr xB, [xA, sym@GOTPAGEOFF] // L3: ldr xC, [xB, #imm] // - .loh AdrpLdr L1, L3: // L1: adrp xA, sym@PAGE // L3: ldr xC, [xA, sym@PAGEOFF] // - .loh AdrpAddStr L1, L2, L3: // L1: adrp xA, sym@PAGE // L2: add xB, xA, sym@PAGEOFF // L3: str xC, [xB, #imm] // - .loh AdrpLdrGotStr L1, L2, L3: // L1: adrp xA, sym@GOTPAGE // L2: ldr xB, [xA, sym@GOTPAGEOFF] // L3: str xC, [xB, #imm] // - .loh AdrpAdd L1, L2: // L1: adrp xA, sym@PAGE // L2: add xB, xA, sym@PAGEOFF // For all these LOHs, L1, L2, L3 form a simple chain: // L1 result is used only by L2 and L2 result by L3. // L3 LOH-related argument is defined only by L2 and L2 LOH-related argument // by L1. // All these LOHs aim at using more efficient load/store patterns by folding // some instructions used to compute the address directly into the load/store. // // * So called ADRP-related: // - .loh AdrpAdrp L2, L1: // L2: ADRP xA, sym1@PAGE // L1: ADRP xA, sym2@PAGE // L2 dominates L1 and xA is not redifined between L2 and L1 // This LOH aims at getting rid of redundant ADRP instructions. // // The overall design for emitting the LOHs is: // 1. AArch64CollectLOH (this pass) records the LOHs in the AArch64FunctionInfo. // 2. AArch64AsmPrinter reads the LOHs from AArch64FunctionInfo and it: // 1. Associates them a label. // 2. Emits them in a MCStreamer (EmitLOHDirective). // - The MCMachOStreamer records them into the MCAssembler. // - The MCAsmStreamer prints them. // - Other MCStreamers ignore them. // 3. Closes the MCStreamer: // - The MachObjectWriter gets them from the MCAssembler and writes // them in the object file. // - Other ObjectWriters ignore them. //===----------------------------------------------------------------------===// #include "AArch64.h" #include "AArch64InstrInfo.h" #include "AArch64MachineFunctionInfo.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumADRPSimpleCandidate, "Number of simplifiable ADRP dominate by another"); STATISTIC(NumADDToSTR, "Number of simplifiable STR reachable by ADD"); STATISTIC(NumLDRToSTR, "Number of simplifiable STR reachable by LDR"); STATISTIC(NumADDToLDR, "Number of simplifiable LDR reachable by ADD"); STATISTIC(NumLDRToLDR, "Number of simplifiable LDR reachable by LDR"); STATISTIC(NumADRPToLDR, "Number of simplifiable LDR reachable by ADRP"); STATISTIC(NumADRSimpleCandidate, "Number of simplifiable ADRP + ADD"); #define AARCH64_COLLECT_LOH_NAME … namespace { struct AArch64CollectLOH : public MachineFunctionPass { … }; char AArch64CollectLOH::ID = …; } // end anonymous namespace. INITIALIZE_PASS(…) static bool canAddBePartOfLOH(const MachineInstr &MI) { … } /// Answer the following question: Can Def be one of the definition /// involved in a part of a LOH? static bool canDefBePartOfLOH(const MachineInstr &MI) { … } /// Check whether the given instruction can the end of a LOH chain involving a /// store. static bool isCandidateStore(const MachineInstr &MI, const MachineOperand &MO) { … } /// Check whether the given instruction can be the end of a LOH chain /// involving a load. static bool isCandidateLoad(const MachineInstr &MI) { … } /// Check whether the given instruction can load a litteral. static bool supportLoadFromLiteral(const MachineInstr &MI) { … } /// Number of GPR registers traked by mapRegToGPRIndex() static const unsigned N_GPR_REGS = …; /// Map register number to index from 0-30. static int mapRegToGPRIndex(MCPhysReg Reg) { … } /// State tracked per register. /// The main algorithm walks backwards over a basic block maintaining this /// datastructure for each tracked general purpose register. struct LOHInfo { … }; /// Update state \p Info given \p MI uses the tracked register. static void handleUse(const MachineInstr &MI, const MachineOperand &MO, LOHInfo &Info) { … } /// Update state \p Info given the tracked register is clobbered. static void handleClobber(LOHInfo &Info) { … } /// Update state \p Info given that \p MI is possibly the middle instruction /// of an LOH involving 3 instructions. static bool handleMiddleInst(const MachineInstr &MI, LOHInfo &DefInfo, LOHInfo &OpInfo) { … } /// Update state when seeing and ADRP instruction. static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI, LOHInfo &Info, LOHInfo *LOHInfos) { … } static void handleRegMaskClobber(const uint32_t *RegMask, MCPhysReg Reg, LOHInfo *LOHInfos) { … } static void handleNormalInst(const MachineInstr &MI, LOHInfo *LOHInfos) { … } bool AArch64CollectLOH::runOnMachineFunction(MachineFunction &MF) { … } FunctionPass *llvm::createAArch64CollectLOHPass() { … }