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