//===- 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 using namespace llvm; namespace opts { extern cl::OptionCategory BoltCategory; static cl::opt 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