namespace llvm {
-template <typename Derived> class ThunkInserter {
+template <typename Derived, typename InsertedThunksTy = bool>
+class ThunkInserter {
Derived &getDerived() { return *static_cast<Derived *>(this); }
protected:
- bool InsertedThunks;
+ // A variable used to track whether (and possible which) thunks have been
+ // inserted so far. InsertedThunksTy is usually a bool, but can be other types
+ // to represent more than one type of thunk. Requires an |= operator to
+ // accumulate results.
+ InsertedThunksTy InsertedThunks;
void doInitialization(Module &M) {}
void createThunkFunction(MachineModuleInfo &MMI, StringRef Name,
bool Comdat = true);
public:
void init(Module &M) {
- InsertedThunks = false;
+ InsertedThunks = InsertedThunksTy{};
getDerived().doInitialization(M);
}
// return `true` if `MMI` or `MF` was modified
bool run(MachineModuleInfo &MMI, MachineFunction &MF);
};
-template <typename Derived>
-void ThunkInserter<Derived>::createThunkFunction(MachineModuleInfo &MMI,
- StringRef Name, bool Comdat) {
+template <typename Derived, typename InsertedThunksTy>
+void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction(
+ MachineModuleInfo &MMI, StringRef Name, bool Comdat) {
assert(Name.startswith(getDerived().getThunkPrefix()) &&
"Created a thunk with an unexpected prefix!");
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
}
-template <typename Derived>
-bool ThunkInserter<Derived>::run(MachineModuleInfo &MMI, MachineFunction &MF) {
+template <typename Derived, typename InsertedThunksTy>
+bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
+ MachineFunction &MF) {
// If MF is not a thunk, check to see if we need to insert a thunk.
if (!MF.getName().startswith(getDerived().getThunkPrefix())) {
- // If we've already inserted a thunk, nothing else to do.
- if (InsertedThunks)
- return false;
-
// Only add a thunk if one of the functions has the corresponding feature
- // enabled in its subtarget, and doesn't enable external thunks.
+ // enabled in its subtarget, and doesn't enable external thunks. The target
+ // can use InsertedThunks to detect whether relevant thunks have already
+ // been inserted.
// FIXME: Conditionalize on indirect calls so we don't emit a thunk when
// nothing will end up calling it.
// FIXME: It's a little silly to look at every function just to enumerate
// the subtargets, but eventually we'll want to look at them for indirect
// calls, so maybe this is OK.
- if (!getDerived().mayUseThunk(MF))
+ if (!getDerived().mayUseThunk(MF, InsertedThunks))
return false;
- getDerived().insertThunks(MMI);
- InsertedThunks = true;
+ InsertedThunks |= getDerived().insertThunks(MMI, MF);
return true;
}
namespace {
struct SLSBLRThunkInserter : ThunkInserter<SLSBLRThunkInserter> {
const char *getThunkPrefix() { return SLSBLRNamePrefix; }
- bool mayUseThunk(const MachineFunction &MF) {
+ bool mayUseThunk(const MachineFunction &MF, bool InsertedThunks) {
+ if (InsertedThunks)
+ return false;
ComdatThunks &= !MF.getSubtarget<AArch64Subtarget>().hardenSlsNoComdat();
// FIXME: This could also check if there are any BLRs in the function
// to more accurately reflect if a thunk will be needed.
return MF.getSubtarget<AArch64Subtarget>().hardenSlsBlr();
}
- void insertThunks(MachineModuleInfo &MMI);
+ bool insertThunks(MachineModuleInfo &MMI, MachineFunction &MF);
void populateThunk(MachineFunction &MF);
private:
};
} // namespace
-void SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI) {
+bool SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI,
+ MachineFunction &MF) {
// FIXME: It probably would be possible to filter which thunks to produce
// based on which registers are actually used in BLR instructions in this
// function. But would that be a worthwhile optimization?
for (auto T : SLSBLRThunks)
createThunkFunction(MMI, T.Name, ComdatThunks);
+ return true;
}
void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {
{"__llvm_slsblr_thunk_thumb_pc", ARM::PC, true},
};
+// An enum for tracking whether Arm and Thumb thunks have been inserted into the
+// current module so far.
+enum ArmInsertedThunks { ArmThunk = 1, ThumbThunk = 2 };
+
+inline ArmInsertedThunks &operator|=(ArmInsertedThunks &X,
+ ArmInsertedThunks Y) {
+ return X = static_cast<ArmInsertedThunks>(X | Y);
+}
+
namespace {
-struct SLSBLRThunkInserter : ThunkInserter<SLSBLRThunkInserter> {
+struct SLSBLRThunkInserter
+ : ThunkInserter<SLSBLRThunkInserter, ArmInsertedThunks> {
const char *getThunkPrefix() { return SLSBLRNamePrefix; }
- bool mayUseThunk(const MachineFunction &MF) {
+ bool mayUseThunk(const MachineFunction &MF,
+ ArmInsertedThunks InsertedThunks) {
+ if ((InsertedThunks & ArmThunk &&
+ !MF.getSubtarget<ARMSubtarget>().isThumb()) ||
+ (InsertedThunks & ThumbThunk &&
+ MF.getSubtarget<ARMSubtarget>().isThumb()))
+ return false;
ComdatThunks &= !MF.getSubtarget<ARMSubtarget>().hardenSlsNoComdat();
// FIXME: This could also check if there are any indirect calls in the
// function to more accurately reflect if a thunk will be needed.
return MF.getSubtarget<ARMSubtarget>().hardenSlsBlr();
}
- void insertThunks(MachineModuleInfo &MMI);
+ ArmInsertedThunks insertThunks(MachineModuleInfo &MMI, MachineFunction &MF);
void populateThunk(MachineFunction &MF);
private:
};
} // namespace
-void SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI) {
+ArmInsertedThunks SLSBLRThunkInserter::insertThunks(MachineModuleInfo &MMI,
+ MachineFunction &MF) {
// FIXME: It probably would be possible to filter which thunks to produce
// based on which registers are actually used in indirect calls in this
// function. But would that be a worthwhile optimization?
+ const ARMSubtarget *ST = &MF.getSubtarget<ARMSubtarget>();
for (auto T : SLSBLRThunks)
- createThunkFunction(MMI, T.Name, ComdatThunks);
+ if (ST->isThumb() == T.isThumb)
+ createThunkFunction(MMI, T.Name, ComdatThunks);
+ return ST->isThumb() ? ThumbThunk : ArmThunk;
}
void SLSBLRThunkInserter::populateThunk(MachineFunction &MF) {
namespace {
struct RetpolineThunkInserter : ThunkInserter<RetpolineThunkInserter> {
const char *getThunkPrefix() { return RetpolineNamePrefix; }
- bool mayUseThunk(const MachineFunction &MF) {
+ bool mayUseThunk(const MachineFunction &MF, bool InsertedThunks) {
+ if (InsertedThunks)
+ return false;
const auto &STI = MF.getSubtarget<X86Subtarget>();
return (STI.useRetpolineIndirectCalls() ||
STI.useRetpolineIndirectBranches()) &&
!STI.useRetpolineExternalThunk();
}
- void insertThunks(MachineModuleInfo &MMI);
+ bool insertThunks(MachineModuleInfo &MMI, MachineFunction &MF);
void populateThunk(MachineFunction &MF);
};
struct LVIThunkInserter : ThunkInserter<LVIThunkInserter> {
const char *getThunkPrefix() { return LVIThunkNamePrefix; }
- bool mayUseThunk(const MachineFunction &MF) {
+ bool mayUseThunk(const MachineFunction &MF, bool InsertedThunks) {
+ if (InsertedThunks)
+ return false;
return MF.getSubtarget<X86Subtarget>().useLVIControlFlowIntegrity();
}
- void insertThunks(MachineModuleInfo &MMI) {
+ bool insertThunks(MachineModuleInfo &MMI, MachineFunction &MF) {
createThunkFunction(MMI, R11LVIThunkName);
+ return true;
}
void populateThunk(MachineFunction &MF) {
assert (MF.size() == 1);
} // end anonymous namespace
-void RetpolineThunkInserter::insertThunks(MachineModuleInfo &MMI) {
+bool RetpolineThunkInserter::insertThunks(MachineModuleInfo &MMI,
+ MachineFunction &MF) {
if (MMI.getTarget().getTargetTriple().getArch() == Triple::x86_64)
createThunkFunction(MMI, R11RetpolineName);
else
for (StringRef Name : {EAXRetpolineName, ECXRetpolineName, EDXRetpolineName,
EDIRetpolineName})
createThunkFunction(MMI, Name);
+ return true;
}
void RetpolineThunkInserter::populateThunk(MachineFunction &MF) {
--- /dev/null
+; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s
+
+; Given both Arm and Thumb functions in the same compilation unit, we should
+; get both arm and thumb thunks.
+
+define i32 @test1(i32 %a, i32 %b) {
+ ret i32 %a
+}
+
+define i32 @test2(i32 %a, i32 %b) "target-features"="+thumb-mode" {
+ ret i32 %a
+}
+
+; CHECK: test1
+; CHECK: test2
+; CHECK: __llvm_slsblr_thunk_arm_sp
+; CHECK: __llvm_slsblr_thunk_thumb_sp
\ No newline at end of file
; SB-NEXT: isb
; HARDEN-NEXT: .Lfunc_end
-
+; THUMB-NOT: __llvm_slsblr_thunk_arm
+; ARM-NOT: __llvm_slsblr_thunk_thumb