brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · 610adad Raw
125 lines · cpp
1//===- bolt/Passes/AArch64RelaxationPass.cpp ------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the AArch64RelaxationPass class.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Passes/AArch64RelaxationPass.h"14#include "bolt/Core/ParallelUtilities.h"15#include "bolt/Utils/CommandLineOpts.h"16#include <iterator>17 18using namespace llvm;19 20namespace opts {21extern cl::OptionCategory BoltCategory;22 23static cl::opt<bool> AArch64PassOpt(24    "aarch64-relaxation",25    cl::desc("Replace ARM non-local ADR/LDR instructions with ADRP"),26    cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden);27} // namespace opts28 29namespace llvm {30namespace bolt {31 32// We don't exit directly from runOnFunction since it would call ThreadPool33// destructor which might result in internal assert if we're not finished34// creating async jobs on the moment of exit. So we're finishing all parallel35// jobs and checking the exit flag after it.36static bool PassFailed = false;37 38void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {39  if (PassFailed)40    return;41 42  BinaryContext &BC = BF.getBinaryContext();43  for (BinaryBasicBlock &BB : BF) {44    for (auto It = BB.begin(); It != BB.end(); ++It) {45      MCInst &Inst = *It;46      bool IsADR = BC.MIB->isADR(Inst);47 48      // TODO: Handle other types of LDR (literal, PC-relative) instructions.49      if (!IsADR && !BC.MIB->isLDRXl(Inst) && !BC.MIB->isLDRWl(Inst))50        continue;51 52      const MCSymbol *Symbol = BC.MIB->getTargetSymbol(Inst, IsADR ? 0 : 1);53      if (!Symbol)54        continue;55 56      if (BF.hasIslandsInfo()) {57        BinaryFunction::IslandInfo &Islands = BF.getIslandInfo();58        if (Islands.Symbols.count(Symbol) || Islands.ProxySymbols.count(Symbol))59          continue;60      }61 62      // Don't relax ADR/LDR if it points to the same function and is in the63      // main fragment and BF initial size is < 1MB.64      const unsigned OneMB = 0x100000;65      if (BF.getSize() < OneMB) {66        BinaryFunction *TargetBF = BC.getFunctionForSymbol(Symbol);67        if (TargetBF == &BF && !BB.isSplit())68          continue;69 70        // No relaxation needed if ADR/LDR references a basic block in the same71        // fragment.72        if (BinaryBasicBlock *TargetBB = BF.getBasicBlockForLabel(Symbol))73          if (BB.getFragmentNum() == TargetBB->getFragmentNum())74            continue;75      }76 77      InstructionListType AdrpMaterialization;78      {79        auto L = BC.scopeLock();80        AdrpMaterialization =81            IsADR ? BC.MIB->undoAdrpAddRelaxation(Inst, BC.Ctx.get())82                  : BC.MIB->createAdrpLdr(Inst, BC.Ctx.get());83      }84 85      if (It != BB.begin() && BC.MIB->isNoop(*std::prev(It))) {86        It = BB.eraseInstruction(std::prev(It));87      } else if (std::next(It) != BB.end() && BC.MIB->isNoop(*std::next(It))) {88        BB.eraseInstruction(std::next(It));89      } else if (!BF.isSimple()) {90        // If the function is not simple, it may contain a jump table undetected91        // by us. This jump table may use an offset from the branch instruction92        // to land in the desired place. If we add new instructions, we93        // invalidate this offset, so we have to rely on linker-inserted NOP to94        // replace it with ADRP, and abort if it is not present.95        auto L = BC.scopeLock();96        BC.errs() << "BOLT-ERROR: cannot relax " << (IsADR ? "ADR" : "LDR")97                  << " in non-simple function " << BF << '\n';98        PassFailed = true;99        return;100      }101      It = BB.replaceInstruction(It, AdrpMaterialization);102    }103  }104}105 106Error AArch64RelaxationPass::runOnFunctions(BinaryContext &BC) {107  if (!opts::AArch64PassOpt || !BC.HasRelocations)108    return Error::success();109 110  ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {111    runOnFunction(BF);112  };113 114  ParallelUtilities::runOnEachFunction(115      BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, nullptr,116      "AArch64RelaxationPass");117 118  if (PassFailed)119    return createFatalBOLTError("");120  return Error::success();121}122 123} // end namespace bolt124} // end namespace llvm125