30#define DEBUG_TYPE "aarch64-stack-tagging-pre-ra"
37 "Unconditionally apply unchecked-ld-st optimization (even for large "
38 "stack frames, or in the presence of variable sized allocas)."),
43 "apply unchecked-ld-st when the target is definitely within range"),
48 cl::desc(
"Apply first slot optimization for stack tagging "
49 "(eliminate ADDG Rt, Rn, 0, 0)."));
53class AArch64StackTaggingPreRAImpl {
67 bool mayUseUncheckedLoadStore();
68 void uncheckUsesOf(
unsigned TaggedReg,
int FI);
69 void uncheckLoadsAndStores();
70 std::optional<int> findFirstSlotCandidate();
76 AArch64StackTaggingPreRALegacy() : MachineFunctionPass(ID) {}
78 bool runOnMachineFunction(MachineFunction &MF)
override {
81 return AArch64StackTaggingPreRAImpl().run(MF);
84 StringRef getPassName()
const override {
85 return "AArch64 Stack Tagging PreRA";
88 void getAnalysisUsage(AnalysisUsage &AU)
const override {
95char AArch64StackTaggingPreRALegacy::ID = 0;
98 "aarch64-stack-tagging-pre-ra",
99 "AArch64 Stack Tagging PreRA Pass",
false,
false)
101 "aarch64-stack-tagging-pre-ra",
105 return new AArch64StackTaggingPreRALegacy();
111 if (AArch64StackTaggingPreRAImpl().
run(MF)) {
121 case AArch64::LDRBBui:
122 case AArch64::LDRHHui:
123 case AArch64::LDRWui:
124 case AArch64::LDRXui:
126 case AArch64::LDRBui:
127 case AArch64::LDRHui:
128 case AArch64::LDRSui:
129 case AArch64::LDRDui:
130 case AArch64::LDRQui:
132 case AArch64::LDRSHWui:
133 case AArch64::LDRSHXui:
135 case AArch64::LDRSBWui:
136 case AArch64::LDRSBXui:
138 case AArch64::LDRSWui:
140 case AArch64::STRBBui:
141 case AArch64::STRHHui:
142 case AArch64::STRWui:
143 case AArch64::STRXui:
145 case AArch64::STRBui:
146 case AArch64::STRHui:
147 case AArch64::STRSui:
148 case AArch64::STRDui:
149 case AArch64::STRQui:
157 case AArch64::LDPSWi:
170bool AArch64StackTaggingPreRAImpl::mayUseUncheckedLoadStore() {
187 unsigned FrameSize = 0;
188 for (
unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i)
189 FrameSize += MFI->getObjectSize(i);
190 bool EntireFrameReachableFromSP = FrameSize < 0xf00;
191 return !MFI->hasVarSizedObjects() && EntireFrameReachableFromSP;
194void AArch64StackTaggingPreRAImpl::uncheckUsesOf(
unsigned TaggedReg,
int FI) {
199 unsigned OpIdx =
TII->getLoadStoreImmIdx(UseI.getOpcode()) - 1;
200 if (UseI.getOperand(
OpIdx).isReg() &&
201 UseI.getOperand(
OpIdx).getReg() == TaggedReg) {
202 UseI.getOperand(
OpIdx).ChangeToFrameIndex(FI);
205 }
else if (UseI.isCopy() && UseI.getOperand(0).getReg().isVirtual()) {
206 uncheckUsesOf(UseI.getOperand(0).getReg(), FI);
211void AArch64StackTaggingPreRAImpl::uncheckLoadsAndStores() {
212 for (
auto *
I : ReTags) {
213 Register TaggedReg =
I->getOperand(0).getReg();
214 int FI =
I->getOperand(1).getIndex();
215 uncheckUsesOf(TaggedReg, FI);
223 SlotWithTag(
int FI,
int Tag) : FI(FI),
Tag(
Tag) {}
224 explicit SlotWithTag(
const MachineInstr &
MI)
225 : FI(
MI.getOperand(1).getIndex()),
Tag(
MI.getOperand(4).
getImm()) {}
240 static bool isEqual(
const SlotWithTag &
A,
const SlotWithTag &
B) {
257std::optional<int> AArch64StackTaggingPreRAImpl::findFirstSlotCandidate() {
273 dbgs() <<
"AArch64StackTaggingPreRAImpl::findFirstSlotCandidate\n");
278 SlotWithTag MaxScoreST{-1, -1};
280 for (
auto *
I : ReTags) {
285 Register RetagReg =
I->getOperand(0).getReg();
293 while (!WorkList.
empty()) {
295 for (
auto &UseI : MRI->use_instructions(
UseReg)) {
296 unsigned Opcode = UseI.getOpcode();
297 if (Opcode == AArch64::STGi || Opcode == AArch64::ST2Gi ||
298 Opcode == AArch64::STZGi || Opcode == AArch64::STZ2Gi ||
299 Opcode == AArch64::STGPi || Opcode == AArch64::STGloop ||
300 Opcode == AArch64::STZGloop || Opcode == AArch64::STGloop_wback ||
301 Opcode == AArch64::STZGloop_wback)
304 Register DstReg = UseI.getOperand(0).getReg();
315 int TotalScore = RetagScore[
ST] += Score;
316 if (TotalScore > MaxScore ||
317 (TotalScore == MaxScore &&
ST.FI > MaxScoreST.FI)) {
318 MaxScore = TotalScore;
323 if (MaxScoreST.FI < 0)
327 if (MaxScoreST.Tag == 0)
328 return MaxScoreST.FI;
331 SlotWithTag SwapST{-1, -1};
332 for (
auto *
I : ReTags) {
343 for (
auto *&
I : ReTags) {
346 if (ST == MaxScoreST) {
348 }
else if (ST == SwapST) {
349 TagOp.
setImm(MaxScoreST.Tag);
352 return MaxScoreST.FI;
367 LLVM_DEBUG(
dbgs() <<
"********** AArch64 Stack Tagging PreRA **********\n"
368 <<
"********** Function: " << MF->
getName() <<
'\n');
371 for (
auto &BB : *MF) {
373 if (
I.getOpcode() == AArch64::TAGPstack) {
374 ReTags.push_back(&
I);
375 int FI =
I.getOperand(1).getIndex();
378 assert(
I.getOperand(2).getImm() == 0);
385 for (
int FI : TaggedSlots)
391 if (mayUseUncheckedLoadStore())
392 uncheckLoadsAndStores();
397 std::optional<int> BaseSlot = findFirstSlotCandidate();
399 AFI->setTaggedBasePointerIndex(*BaseSlot);
401 for (
auto *
I : ReTags) {
402 int FI =
I->getOperand(1).getIndex();
403 int Tag =
I->getOperand(4).getImm();
405 if (
Tag == 0 && FI == BaseSlot) {
406 BuildMI(*
I->getParent(),
I, {},
TII->get(AArch64::COPY),
407 I->getOperand(0).getReg())
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isSlotPreAllocated(MachineFrameInfo *MFI, int FI)
static cl::opt< UncheckedLdStMode > ClUncheckedLdSt("stack-tagging-unchecked-ld-st", cl::Hidden, cl::init(UncheckedSafe), cl::desc("Unconditionally apply unchecked-ld-st optimization (even for large " "stack frames, or in the presence of variable sized allocas)."), cl::values(clEnumValN(UncheckedNever, "never", "never apply unchecked-ld-st"), clEnumValN(UncheckedSafe, "safe", "apply unchecked-ld-st when the target is definitely within range"), clEnumValN(UncheckedAlways, "always", "always apply unchecked-ld-st")))
static cl::opt< bool > ClFirstSlot("stack-tagging-first-slot-opt", cl::Hidden, cl::init(true), cl::desc("Apply first slot optimization for stack tagging " "(eliminate ADDG Rt, Rn, 0, 0)."))
static bool isUncheckedLoadOrStoreOpcode(unsigned Opcode)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file implements a set that has insertion order iteration characteristics.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
bool isObjectPreAllocated(int ObjectIdx) const
Return true if the object was pre-allocated into the local block.
@ SSPLK_None
Did not trigger a stack protector.
bool getUseLocalStackAllocationBlock() const
Get whether the local allocation blob should be allocated together or let PEI allocate the locals in ...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
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.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
@ MO_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64StackTaggingPreRALegacyPass()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
static bool isEqual(const SlotWithTag &A, const SlotWithTag &B)
static SlotWithTag getTombstoneKey()
static SlotWithTag getEmptyKey()
static unsigned getHashValue(const SlotWithTag &V)
An information struct used to provide DenseMap with the various necessary components for a given valu...