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 // Don't relax adr if it points to the same function and it is not split
60 // and BF initial size is < 1MB.
61 const unsigned OneMB
= 0x100000;
62 if (!BF
.isSplit() && BF
.getSize() < OneMB
) {
63 BinaryFunction
*TargetBF
= BC
.getFunctionForSymbol(Symbol
);
64 if (TargetBF
&& TargetBF
== &BF
)
69 BC
.MIB
->getADRReg(Inst
, Reg
);
70 int64_t Addend
= BC
.MIB
->getTargetAddend(Inst
);
71 InstructionListType Addr
;
74 auto L
= BC
.scopeLock();
75 Addr
= BC
.MIB
->materializeAddress(Symbol
, BC
.Ctx
.get(), Reg
, Addend
);
78 if (It
!= BB
.begin() && BC
.MIB
->isNoop(*std::prev(It
))) {
79 It
= BB
.eraseInstruction(std::prev(It
));
80 } else if (std::next(It
) != BB
.end() && BC
.MIB
->isNoop(*std::next(It
))) {
81 BB
.eraseInstruction(std::next(It
));
82 } else if (!opts::StrictMode
&& !BF
.isSimple()) {
83 // If the function is not simple, it may contain a jump table undetected
84 // by us. This jump table may use an offset from the branch instruction
85 // to land in the desired place. If we add new instructions, we
86 // invalidate this offset, so we have to rely on linker-inserted NOP to
87 // replace it with ADRP, and abort if it is not present.
88 auto L
= BC
.scopeLock();
90 "BOLT-ERROR: Cannot relax adr in non-simple function "
91 "{0}. Use --strict option to override\n",
96 It
= BB
.replaceInstruction(It
, Addr
);
101 Error
ADRRelaxationPass::runOnFunctions(BinaryContext
&BC
) {
102 if (!opts::AdrPassOpt
|| !BC
.HasRelocations
)
103 return Error::success();
105 ParallelUtilities::WorkFuncTy WorkFun
= [&](BinaryFunction
&BF
) {
109 ParallelUtilities::runOnEachFunction(
110 BC
, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL
, WorkFun
, nullptr,
111 "ADRRelaxationPass");
114 return createFatalBOLTError("");
115 return Error::success();
118 } // end namespace bolt
119 } // end namespace llvm