1 //===- bolt/Passes/ADRRelaxationPass.cpp ----------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the ADRRelaxationPass class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Passes/ADRRelaxationPass.h"
14 #include "bolt/Core/ParallelUtilities.h"
15 #include "bolt/Utils/CommandLineOpts.h"
21 extern cl::OptionCategory BoltCategory
;
24 AdrPassOpt("adr-relaxation",
25 cl::desc("Replace ARM non-local ADR instructions with ADRP"),
26 cl::init(true), cl::cat(BoltCategory
), cl::ReallyHidden
);
32 // We don't exit directly from runOnFunction since it would call ThreadPool
33 // destructor which might result in internal assert if we're not finished
34 // creating async jobs on the moment of exit. So we're finishing all parallel
35 // jobs and checking the exit flag after it.
36 static bool PassFailed
= false;
38 void ADRRelaxationPass::runOnFunction(BinaryFunction
&BF
) {
42 BinaryContext
&BC
= BF
.getBinaryContext();
43 for (BinaryBasicBlock
&BB
: BF
) {
44 for (auto It
= BB
.begin(); It
!= BB
.end(); ++It
) {
46 if (!BC
.MIB
->isADR(Inst
))
49 const MCSymbol
*Symbol
= BC
.MIB
->getTargetSymbol(Inst
);
53 if (BF
.hasIslandsInfo()) {
54 BinaryFunction::IslandInfo
&Islands
= BF
.getIslandInfo();
55 if (Islands
.Symbols
.count(Symbol
) || Islands
.ProxySymbols
.count(Symbol
))
59 BinaryFunction
*TargetBF
= BC
.getFunctionForSymbol(Symbol
);
60 if (TargetBF
&& TargetBF
== &BF
)
64 BC
.MIB
->getADRReg(Inst
, Reg
);
65 int64_t Addend
= BC
.MIB
->getTargetAddend(Inst
);
66 InstructionListType Addr
;
69 auto L
= BC
.scopeLock();
70 Addr
= BC
.MIB
->materializeAddress(Symbol
, BC
.Ctx
.get(), Reg
, Addend
);
73 if (It
!= BB
.begin() && BC
.MIB
->isNoop(*std::prev(It
))) {
74 It
= BB
.eraseInstruction(std::prev(It
));
75 } else if (opts::StrictMode
&& !BF
.isSimple()) {
76 // If the function is not simple, it may contain a jump table undetected
77 // by us. This jump table may use an offset from the branch instruction
78 // to land in the desired place. If we add new instructions, we
79 // invalidate this offset, so we have to rely on linker-inserted NOP to
80 // replace it with ADRP, and abort if it is not present.
81 errs() << formatv("BOLT-ERROR: Cannot relax adr in non-simple function "
82 "{0}. Can't proceed in current mode.\n",
87 It
= BB
.replaceInstruction(It
, Addr
);
92 void ADRRelaxationPass::runOnFunctions(BinaryContext
&BC
) {
93 if (!opts::AdrPassOpt
|| !BC
.HasRelocations
)
96 ParallelUtilities::WorkFuncTy WorkFun
= [&](BinaryFunction
&BF
) {
100 ParallelUtilities::runOnEachFunction(
101 BC
, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL
, WorkFun
, nullptr,
102 "ADRRelaxationPass");
108 } // end namespace bolt
109 } // end namespace llvm