29#define DEBUG_TYPE "arm-sls-hardening"
31#define ARM_SLS_HARDENING_NAME "ARM sls hardening pass"
65char ARMSLSHardening::ID = 0;
76 "Must not insert SpeculationBarrierEndBB as only instruction in MBB.");
78 "SpeculationBarrierEndBB must only follow unconditional control flow "
81 "SpeculationBarrierEndBB must only follow terminators.");
83 assert(ST->hasDataBarrier() || ST->hasSB());
86 ProduceSB ? (ST->isThumb() ? ARM::t2SpeculationBarrierSBEndBB
87 : ARM::SpeculationBarrierSBEndBB)
88 : (ST->isThumb() ? ARM::t2SpeculationBarrierISBDSBEndBB
89 : ARM::SpeculationBarrierISBDSBEndBB);
99 for (
auto &
MBB : MF) {
108 if (!
ST->hardenSlsRetBr())
116 NextMBBI = std::next(
MBBI);
120 insertSpeculationBarrier(ST,
MBB, std::next(
MBBI),
MI.getDebugLoc());
127static const char SLSBLRNamePrefix[] =
"__llvm_slsblr_thunk_";
134 {
"__llvm_slsblr_thunk_arm_r0", ARM::R0,
false},
135 {
"__llvm_slsblr_thunk_arm_r1", ARM::R1,
false},
136 {
"__llvm_slsblr_thunk_arm_r2", ARM::R2,
false},
137 {
"__llvm_slsblr_thunk_arm_r3", ARM::R3,
false},
138 {
"__llvm_slsblr_thunk_arm_r4", ARM::R4,
false},
139 {
"__llvm_slsblr_thunk_arm_r5", ARM::R5,
false},
140 {
"__llvm_slsblr_thunk_arm_r6", ARM::R6,
false},
141 {
"__llvm_slsblr_thunk_arm_r7", ARM::R7,
false},
142 {
"__llvm_slsblr_thunk_arm_r8", ARM::R8,
false},
143 {
"__llvm_slsblr_thunk_arm_r9", ARM::R9,
false},
144 {
"__llvm_slsblr_thunk_arm_r10", ARM::R10,
false},
145 {
"__llvm_slsblr_thunk_arm_r11", ARM::R11,
false},
146 {
"__llvm_slsblr_thunk_arm_sp", ARM::SP,
false},
147 {
"__llvm_slsblr_thunk_arm_pc", ARM::PC,
false},
148 {
"__llvm_slsblr_thunk_thumb_r0", ARM::R0,
true},
149 {
"__llvm_slsblr_thunk_thumb_r1", ARM::R1,
true},
150 {
"__llvm_slsblr_thunk_thumb_r2", ARM::R2,
true},
151 {
"__llvm_slsblr_thunk_thumb_r3", ARM::R3,
true},
152 {
"__llvm_slsblr_thunk_thumb_r4", ARM::R4,
true},
153 {
"__llvm_slsblr_thunk_thumb_r5", ARM::R5,
true},
154 {
"__llvm_slsblr_thunk_thumb_r6", ARM::R6,
true},
155 {
"__llvm_slsblr_thunk_thumb_r7", ARM::R7,
true},
156 {
"__llvm_slsblr_thunk_thumb_r8", ARM::R8,
true},
157 {
"__llvm_slsblr_thunk_thumb_r9", ARM::R9,
true},
158 {
"__llvm_slsblr_thunk_thumb_r10", ARM::R10,
true},
159 {
"__llvm_slsblr_thunk_thumb_r11", ARM::R11,
true},
160 {
"__llvm_slsblr_thunk_thumb_sp", ARM::SP,
true},
161 {
"__llvm_slsblr_thunk_thumb_pc", ARM::PC,
true},
174struct SLSBLRThunkInserter
176 const char *getThunkPrefix() {
return SLSBLRNamePrefix; }
193 bool ComdatThunks =
true;
204 if (
ST->isThumb() ==
T.isThumb)
205 createThunkFunction(MMI,
T.Name, ComdatThunks,
206 T.isThumb ?
"+thumb-mode" :
"");
218 bool isThumb = ThunkIt->isThumb;
228 Entry->addLiveIn(ThunkReg);
278 int RegOpIdxOnIndirectCall = -1;
284 RegOpIdxOnIndirectCall = 0;
287 case ARM::tBLXr_noip:
289 RegOpIdxOnIndirectCall = 2;
302 assert(Reg != ARM::R12 && Reg != ARM::LR);
303 bool RegIsKilled =
IndirectCall.getOperand(RegOpIdxOnIndirectCall).isKill();
313 const GlobalValue *GV = cast<GlobalValue>(
M->getNamedValue(ThunkIt->Name));
332 for (
unsigned OpIdx =
BL->getNumExplicitOperands();
333 OpIdx < BL->getNumOperands(); OpIdx++) {
337 if (
Op.getReg() == ARM::LR &&
Op.isDef())
339 if (
Op.getReg() == ARM::SP && !
Op.isDef())
344 int FirstOpIdxToRemove = std::max(ImpLROpIdx, ImpSPOpIdx);
345 int SecondOpIdxToRemove = std::min(ImpLROpIdx, ImpSPOpIdx);
346 BL->removeOperand(FirstOpIdxToRemove);
347 BL->removeOperand(SecondOpIdxToRemove);
361 if (!
ST->hardenSlsBlr())
368 NextMBBI = std::next(
MBBI);
373 ConvertIndirectCallToIndirectJump(
MBB,
MBBI);
383 return new ARMSLSHardening();
405 std::tuple<SLSBLRThunkInserter> TIs;
408 template <
typename... ThunkInserterT>
409 static void initTIs(
Module &M,
410 std::tuple<ThunkInserterT...> &ThunkInserters) {
411 (void)std::initializer_list<int>{
412 (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...};
414 template <
typename... ThunkInserterT>
416 std::tuple<ThunkInserterT...> &ThunkInserters) {
418 (void)std::initializer_list<int>{
419 Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...};
426char ARMIndirectThunks::ID = 0;
429 return new ARMIndirectThunks();
432bool ARMIndirectThunks::doInitialization(
Module &M) {
439 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
440 return runTIs(MMI, MF, TIs);
static bool isThumb(const MCSubtargetInfo &STI)
ArmInsertedThunks & operator|=(ArmInsertedThunks &X, ArmInsertedThunks Y)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc bool AlwaysUseISBDSB
#define ARM_SLS_HARDENING_NAME
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static const struct ThunkNameRegMode SLSBLRThunks[]
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
const HexagonInstrInfo * TII
Contains a base class for Passes that inject an MI thunk.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Module * getParent()
Get the module that this global value is contained inside of...
bool isPredicated(const MachineInstr &MI) const override
Returns true if the instruction is already predicated.
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
bool doInitialization(Module &) override
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
void moveCallSiteInfo(const MachineInstr *Old, const MachineInstr *New)
Move the call site info from Old to \New call site info.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
This class contains meta information specific to a module.
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
A Module instance is used to store all the information related to an LLVM module.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
StringRef - Represent a constant reference to a string, i.e.
bool startswith(StringRef Prefix) const
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetInstrInfo * getInstrInfo() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
static bool isIndirectCall(const MachineInstr &MI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)
Get the operands corresponding to the given Pred value.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void initializeARMSLSHardeningPass(PassRegistry &)
FunctionPass * createARMSLSHardeningPass()
static bool isIndirectControlFlowNotComingBack(const MachineInstr &MI)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
FunctionPass * createARMIndirectThunks()
static bool isSpeculationBarrierEndBBOpcode(int Opc)