| //===- bolt/Passes/ADRRelaxationPass.cpp ----------------------------------===// |
| // |
| // 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 implements the ADRRelaxationPass class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "bolt/Passes/ADRRelaxationPass.h" |
| #include "bolt/Core/ParallelUtilities.h" |
| #include "bolt/Utils/CommandLineOpts.h" |
| #include <iterator> |
| |
| using namespace llvm; |
| |
| namespace opts { |
| extern cl::OptionCategory BoltCategory; |
| |
| static cl::opt<bool> |
| AdrPassOpt("adr-relaxation", |
| cl::desc("Replace ARM non-local ADR instructions with ADRP"), |
| cl::init(true), cl::cat(BoltCategory), cl::ReallyHidden); |
| } // namespace opts |
| |
| namespace llvm { |
| namespace bolt { |
| |
| void ADRRelaxationPass::runOnFunction(BinaryFunction &BF) { |
| BinaryContext &BC = BF.getBinaryContext(); |
| for (BinaryBasicBlock &BB : BF) { |
| for (auto It = BB.begin(); It != BB.end(); ++It) { |
| MCInst &Inst = *It; |
| if (!BC.MIB->isADR(Inst)) |
| continue; |
| |
| const MCSymbol *Symbol = BC.MIB->getTargetSymbol(Inst); |
| if (!Symbol) |
| continue; |
| |
| if (BF.hasIslandsInfo()) { |
| BinaryFunction::IslandInfo &Islands = BF.getIslandInfo(); |
| if (Islands.Symbols.count(Symbol) || Islands.ProxySymbols.count(Symbol)) |
| continue; |
| } |
| |
| BinaryFunction *TargetBF = BC.getFunctionForSymbol(Symbol); |
| if (TargetBF && TargetBF == &BF) |
| continue; |
| |
| MCPhysReg Reg; |
| BC.MIB->getADRReg(Inst, Reg); |
| int64_t Addend = BC.MIB->getTargetAddend(Inst); |
| InstructionListType Addr = |
| BC.MIB->materializeAddress(Symbol, BC.Ctx.get(), Reg, Addend); |
| |
| if (It != BB.begin() && BC.MIB->isNoop(*std::prev(It))) { |
| It = BB.eraseInstruction(std::prev(It)); |
| } else if (opts::StrictMode && !BF.isSimple()) { |
| // If the function is not simple, it may contain a jump table undetected |
| // by us. This jump table may use an offset from the branch instruction |
| // to land in the desired place. If we add new instructions, we |
| // invalidate this offset, so we have to rely on linker-inserted NOP to |
| // replace it with ADRP, and abort if it is not present. |
| errs() << formatv("BOLT-ERROR: Cannot relax adr in non-simple function " |
| "{0}. Can't proceed in current mode.\n", |
| BF.getOneName()); |
| exit(1); |
| } |
| It = BB.replaceInstruction(It, Addr); |
| } |
| } |
| } |
| |
| void ADRRelaxationPass::runOnFunctions(BinaryContext &BC) { |
| if (!opts::AdrPassOpt || !BC.HasRelocations) |
| return; |
| |
| ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { |
| runOnFunction(BF); |
| }; |
| |
| ParallelUtilities::runOnEachFunction( |
| BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, nullptr, |
| "ADRRelaxationPass", /* ForceSequential */ true); |
| } |
| |
| } // end namespace bolt |
| } // end namespace llvm |