109467b48Spatrick //===-- AArch64StackTaggingPreRA.cpp --- Stack Tagging for AArch64 -----===//
209467b48Spatrick //
3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information.
5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick 
1009467b48Spatrick #include "AArch64.h"
1109467b48Spatrick #include "AArch64MachineFunctionInfo.h"
1209467b48Spatrick #include "AArch64InstrInfo.h"
1309467b48Spatrick #include "llvm/ADT/DepthFirstIterator.h"
1409467b48Spatrick #include "llvm/ADT/SetVector.h"
1509467b48Spatrick #include "llvm/ADT/Statistic.h"
1609467b48Spatrick #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
1709467b48Spatrick #include "llvm/CodeGen/MachineFrameInfo.h"
1809467b48Spatrick #include "llvm/CodeGen/MachineFunction.h"
1909467b48Spatrick #include "llvm/CodeGen/MachineFunctionPass.h"
2009467b48Spatrick #include "llvm/CodeGen/MachineInstrBuilder.h"
2109467b48Spatrick #include "llvm/CodeGen/MachineLoopInfo.h"
2209467b48Spatrick #include "llvm/CodeGen/MachineRegisterInfo.h"
2309467b48Spatrick #include "llvm/CodeGen/MachineTraceMetrics.h"
2409467b48Spatrick #include "llvm/CodeGen/Passes.h"
2509467b48Spatrick #include "llvm/CodeGen/TargetInstrInfo.h"
2609467b48Spatrick #include "llvm/CodeGen/TargetRegisterInfo.h"
2709467b48Spatrick #include "llvm/CodeGen/TargetSubtargetInfo.h"
2809467b48Spatrick #include "llvm/Support/CommandLine.h"
2909467b48Spatrick #include "llvm/Support/Debug.h"
3009467b48Spatrick #include "llvm/Support/raw_ostream.h"
3109467b48Spatrick 
3209467b48Spatrick using namespace llvm;
3309467b48Spatrick 
3409467b48Spatrick #define DEBUG_TYPE "aarch64-stack-tagging-pre-ra"
3509467b48Spatrick 
3609467b48Spatrick enum UncheckedLdStMode { UncheckedNever, UncheckedSafe, UncheckedAlways };
3709467b48Spatrick 
3809467b48Spatrick cl::opt<UncheckedLdStMode> ClUncheckedLdSt(
3909467b48Spatrick     "stack-tagging-unchecked-ld-st", cl::Hidden,
4009467b48Spatrick     cl::init(UncheckedSafe),
4109467b48Spatrick     cl::desc(
4209467b48Spatrick         "Unconditionally apply unchecked-ld-st optimization (even for large "
4309467b48Spatrick         "stack frames, or in the presence of variable sized allocas)."),
4409467b48Spatrick     cl::values(
4509467b48Spatrick         clEnumValN(UncheckedNever, "never", "never apply unchecked-ld-st"),
4609467b48Spatrick         clEnumValN(
4709467b48Spatrick             UncheckedSafe, "safe",
4809467b48Spatrick             "apply unchecked-ld-st when the target is definitely within range"),
4909467b48Spatrick         clEnumValN(UncheckedAlways, "always", "always apply unchecked-ld-st")));
5009467b48Spatrick 
5173471bf0Spatrick static cl::opt<bool>
5273471bf0Spatrick     ClFirstSlot("stack-tagging-first-slot-opt", cl::Hidden, cl::init(true),
5373471bf0Spatrick                 cl::desc("Apply first slot optimization for stack tagging "
5473471bf0Spatrick                          "(eliminate ADDG Rt, Rn, 0, 0)."));
5573471bf0Spatrick 
5609467b48Spatrick namespace {
5709467b48Spatrick 
5809467b48Spatrick class AArch64StackTaggingPreRA : public MachineFunctionPass {
5909467b48Spatrick   MachineFunction *MF;
6009467b48Spatrick   AArch64FunctionInfo *AFI;
6109467b48Spatrick   MachineFrameInfo *MFI;
6209467b48Spatrick   MachineRegisterInfo *MRI;
6309467b48Spatrick   const AArch64RegisterInfo *TRI;
6409467b48Spatrick   const AArch64InstrInfo *TII;
6509467b48Spatrick 
6609467b48Spatrick   SmallVector<MachineInstr*, 16> ReTags;
6709467b48Spatrick 
6809467b48Spatrick public:
6909467b48Spatrick   static char ID;
AArch64StackTaggingPreRA()7009467b48Spatrick   AArch64StackTaggingPreRA() : MachineFunctionPass(ID) {
7109467b48Spatrick     initializeAArch64StackTaggingPreRAPass(*PassRegistry::getPassRegistry());
7209467b48Spatrick   }
7309467b48Spatrick 
7409467b48Spatrick   bool mayUseUncheckedLoadStore();
7509467b48Spatrick   void uncheckUsesOf(unsigned TaggedReg, int FI);
7609467b48Spatrick   void uncheckLoadsAndStores();
77*d415bd75Srobert   std::optional<int> findFirstSlotCandidate();
7809467b48Spatrick 
7909467b48Spatrick   bool runOnMachineFunction(MachineFunction &Func) override;
getPassName() const8009467b48Spatrick   StringRef getPassName() const override {
8109467b48Spatrick     return "AArch64 Stack Tagging PreRA";
8209467b48Spatrick   }
8309467b48Spatrick 
getAnalysisUsage(AnalysisUsage & AU) const8409467b48Spatrick   void getAnalysisUsage(AnalysisUsage &AU) const override {
8509467b48Spatrick     AU.setPreservesCFG();
8609467b48Spatrick     MachineFunctionPass::getAnalysisUsage(AU);
8709467b48Spatrick   }
8809467b48Spatrick };
8909467b48Spatrick } // end anonymous namespace
9009467b48Spatrick 
9109467b48Spatrick char AArch64StackTaggingPreRA::ID = 0;
9209467b48Spatrick 
9309467b48Spatrick INITIALIZE_PASS_BEGIN(AArch64StackTaggingPreRA, "aarch64-stack-tagging-pre-ra",
9409467b48Spatrick                       "AArch64 Stack Tagging PreRA Pass", false, false)
9509467b48Spatrick INITIALIZE_PASS_END(AArch64StackTaggingPreRA, "aarch64-stack-tagging-pre-ra",
9609467b48Spatrick                     "AArch64 Stack Tagging PreRA Pass", false, false)
9709467b48Spatrick 
createAArch64StackTaggingPreRAPass()9809467b48Spatrick FunctionPass *llvm::createAArch64StackTaggingPreRAPass() {
9909467b48Spatrick   return new AArch64StackTaggingPreRA();
10009467b48Spatrick }
10109467b48Spatrick 
isUncheckedLoadOrStoreOpcode(unsigned Opcode)10209467b48Spatrick static bool isUncheckedLoadOrStoreOpcode(unsigned Opcode) {
10309467b48Spatrick   switch (Opcode) {
10409467b48Spatrick   case AArch64::LDRBBui:
10509467b48Spatrick   case AArch64::LDRHHui:
10609467b48Spatrick   case AArch64::LDRWui:
10709467b48Spatrick   case AArch64::LDRXui:
10809467b48Spatrick 
10909467b48Spatrick   case AArch64::LDRBui:
11009467b48Spatrick   case AArch64::LDRHui:
11109467b48Spatrick   case AArch64::LDRSui:
11209467b48Spatrick   case AArch64::LDRDui:
11309467b48Spatrick   case AArch64::LDRQui:
11409467b48Spatrick 
11509467b48Spatrick   case AArch64::LDRSHWui:
11609467b48Spatrick   case AArch64::LDRSHXui:
11709467b48Spatrick 
11809467b48Spatrick   case AArch64::LDRSBWui:
11909467b48Spatrick   case AArch64::LDRSBXui:
12009467b48Spatrick 
12109467b48Spatrick   case AArch64::LDRSWui:
12209467b48Spatrick 
12309467b48Spatrick   case AArch64::STRBBui:
12409467b48Spatrick   case AArch64::STRHHui:
12509467b48Spatrick   case AArch64::STRWui:
12609467b48Spatrick   case AArch64::STRXui:
12709467b48Spatrick 
12809467b48Spatrick   case AArch64::STRBui:
12909467b48Spatrick   case AArch64::STRHui:
13009467b48Spatrick   case AArch64::STRSui:
13109467b48Spatrick   case AArch64::STRDui:
13209467b48Spatrick   case AArch64::STRQui:
13309467b48Spatrick 
13409467b48Spatrick   case AArch64::LDPWi:
13509467b48Spatrick   case AArch64::LDPXi:
13609467b48Spatrick   case AArch64::LDPSi:
13709467b48Spatrick   case AArch64::LDPDi:
13809467b48Spatrick   case AArch64::LDPQi:
13909467b48Spatrick 
14009467b48Spatrick   case AArch64::LDPSWi:
14109467b48Spatrick 
14209467b48Spatrick   case AArch64::STPWi:
14309467b48Spatrick   case AArch64::STPXi:
14409467b48Spatrick   case AArch64::STPSi:
14509467b48Spatrick   case AArch64::STPDi:
14609467b48Spatrick   case AArch64::STPQi:
14709467b48Spatrick     return true;
14809467b48Spatrick   default:
14909467b48Spatrick     return false;
15009467b48Spatrick   }
15109467b48Spatrick }
15209467b48Spatrick 
mayUseUncheckedLoadStore()15309467b48Spatrick bool AArch64StackTaggingPreRA::mayUseUncheckedLoadStore() {
15409467b48Spatrick   if (ClUncheckedLdSt == UncheckedNever)
15509467b48Spatrick     return false;
15609467b48Spatrick   else if (ClUncheckedLdSt == UncheckedAlways)
15709467b48Spatrick     return true;
15809467b48Spatrick 
15909467b48Spatrick   // This estimate can be improved if we had harder guarantees about stack frame
16009467b48Spatrick   // layout. With LocalStackAllocation we can estimate SP offset to any
16109467b48Spatrick   // preallocated slot. AArch64FrameLowering::orderFrameObjects could put tagged
16209467b48Spatrick   // objects ahead of non-tagged ones, but that's not always desirable.
16309467b48Spatrick   //
16409467b48Spatrick   // Underestimating SP offset here may require the use of LDG to materialize
16509467b48Spatrick   // the tagged address of the stack slot, along with a scratch register
16609467b48Spatrick   // allocation (post-regalloc!).
16709467b48Spatrick   //
16809467b48Spatrick   // For now we do the safe thing here and require that the entire stack frame
16909467b48Spatrick   // is within range of the shortest of the unchecked instructions.
17009467b48Spatrick   unsigned FrameSize = 0;
17109467b48Spatrick   for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i)
17209467b48Spatrick     FrameSize += MFI->getObjectSize(i);
17309467b48Spatrick   bool EntireFrameReachableFromSP = FrameSize < 0xf00;
17409467b48Spatrick   return !MFI->hasVarSizedObjects() && EntireFrameReachableFromSP;
17509467b48Spatrick }
17609467b48Spatrick 
uncheckUsesOf(unsigned TaggedReg,int FI)17709467b48Spatrick void AArch64StackTaggingPreRA::uncheckUsesOf(unsigned TaggedReg, int FI) {
178*d415bd75Srobert   for (MachineInstr &UseI :
179*d415bd75Srobert        llvm::make_early_inc_range(MRI->use_instructions(TaggedReg))) {
180*d415bd75Srobert     if (isUncheckedLoadOrStoreOpcode(UseI.getOpcode())) {
18109467b48Spatrick       // FI operand is always the one before the immediate offset.
182*d415bd75Srobert       unsigned OpIdx = TII->getLoadStoreImmIdx(UseI.getOpcode()) - 1;
183*d415bd75Srobert       if (UseI.getOperand(OpIdx).isReg() &&
184*d415bd75Srobert           UseI.getOperand(OpIdx).getReg() == TaggedReg) {
185*d415bd75Srobert         UseI.getOperand(OpIdx).ChangeToFrameIndex(FI);
186*d415bd75Srobert         UseI.getOperand(OpIdx).setTargetFlags(AArch64II::MO_TAGGED);
18709467b48Spatrick       }
188*d415bd75Srobert     } else if (UseI.isCopy() && UseI.getOperand(0).getReg().isVirtual()) {
189*d415bd75Srobert       uncheckUsesOf(UseI.getOperand(0).getReg(), FI);
19009467b48Spatrick     }
19109467b48Spatrick   }
19209467b48Spatrick }
19309467b48Spatrick 
uncheckLoadsAndStores()19409467b48Spatrick void AArch64StackTaggingPreRA::uncheckLoadsAndStores() {
19509467b48Spatrick   for (auto *I : ReTags) {
196*d415bd75Srobert     Register TaggedReg = I->getOperand(0).getReg();
19709467b48Spatrick     int FI = I->getOperand(1).getIndex();
19809467b48Spatrick     uncheckUsesOf(TaggedReg, FI);
19909467b48Spatrick   }
20009467b48Spatrick }
20109467b48Spatrick 
20273471bf0Spatrick namespace {
20373471bf0Spatrick struct SlotWithTag {
20473471bf0Spatrick   int FI;
20573471bf0Spatrick   int Tag;
SlotWithTag__anon3b846e050211::SlotWithTag20673471bf0Spatrick   SlotWithTag(int FI, int Tag) : FI(FI), Tag(Tag) {}
SlotWithTag__anon3b846e050211::SlotWithTag20773471bf0Spatrick   explicit SlotWithTag(const MachineInstr &MI)
20873471bf0Spatrick       : FI(MI.getOperand(1).getIndex()), Tag(MI.getOperand(4).getImm()) {}
operator ==__anon3b846e050211::SlotWithTag20973471bf0Spatrick   bool operator==(const SlotWithTag &Other) const {
21073471bf0Spatrick     return FI == Other.FI && Tag == Other.Tag;
21173471bf0Spatrick   }
21273471bf0Spatrick };
21373471bf0Spatrick } // namespace
21473471bf0Spatrick 
21573471bf0Spatrick namespace llvm {
21673471bf0Spatrick template <> struct DenseMapInfo<SlotWithTag> {
getEmptyKeyllvm::DenseMapInfo21773471bf0Spatrick   static inline SlotWithTag getEmptyKey() { return {-2, -2}; }
getTombstoneKeyllvm::DenseMapInfo21873471bf0Spatrick   static inline SlotWithTag getTombstoneKey() { return {-3, -3}; }
getHashValuellvm::DenseMapInfo21973471bf0Spatrick   static unsigned getHashValue(const SlotWithTag &V) {
22073471bf0Spatrick     return hash_combine(DenseMapInfo<int>::getHashValue(V.FI),
22173471bf0Spatrick                         DenseMapInfo<int>::getHashValue(V.Tag));
22273471bf0Spatrick   }
isEqualllvm::DenseMapInfo22373471bf0Spatrick   static bool isEqual(const SlotWithTag &A, const SlotWithTag &B) {
22473471bf0Spatrick     return A == B;
22573471bf0Spatrick   }
22673471bf0Spatrick };
22773471bf0Spatrick } // namespace llvm
22873471bf0Spatrick 
isSlotPreAllocated(MachineFrameInfo * MFI,int FI)22973471bf0Spatrick static bool isSlotPreAllocated(MachineFrameInfo *MFI, int FI) {
23073471bf0Spatrick   return MFI->getUseLocalStackAllocationBlock() &&
23173471bf0Spatrick          MFI->isObjectPreAllocated(FI);
23273471bf0Spatrick }
23373471bf0Spatrick 
23473471bf0Spatrick // Pin one of the tagged slots to offset 0 from the tagged base pointer.
23573471bf0Spatrick // This would make its address available in a virtual register (IRG's def), as
23673471bf0Spatrick // opposed to requiring an ADDG instruction to materialize. This effectively
23773471bf0Spatrick // eliminates a vreg (by replacing it with direct uses of IRG, which is usually
23873471bf0Spatrick // live almost everywhere anyway), and therefore needs to happen before
23973471bf0Spatrick // regalloc.
findFirstSlotCandidate()240*d415bd75Srobert std::optional<int> AArch64StackTaggingPreRA::findFirstSlotCandidate() {
24173471bf0Spatrick   // Find the best (FI, Tag) pair to pin to offset 0.
24273471bf0Spatrick   // Looking at the possible uses of a tagged address, the advantage of pinning
24373471bf0Spatrick   // is:
24473471bf0Spatrick   // - COPY to physical register.
24573471bf0Spatrick   //   Does not matter, this would trade a MOV instruction for an ADDG.
24673471bf0Spatrick   // - ST*G matter, but those mostly appear near the function prologue where all
24773471bf0Spatrick   //   the tagged addresses need to be materialized anyway; also, counting ST*G
24873471bf0Spatrick   //   uses would overweight large allocas that require more than one ST*G
24973471bf0Spatrick   //   instruction.
25073471bf0Spatrick   // - Load/Store instructions in the address operand do not require a tagged
25173471bf0Spatrick   //   pointer, so they also do not benefit. These operands have already been
25273471bf0Spatrick   //   eliminated (see uncheckLoadsAndStores) so all remaining load/store
25373471bf0Spatrick   //   instructions count.
25473471bf0Spatrick   // - Any other instruction may benefit from being pinned to offset 0.
25573471bf0Spatrick   LLVM_DEBUG(dbgs() << "AArch64StackTaggingPreRA::findFirstSlotCandidate\n");
25673471bf0Spatrick   if (!ClFirstSlot)
257*d415bd75Srobert     return std::nullopt;
25873471bf0Spatrick 
25973471bf0Spatrick   DenseMap<SlotWithTag, int> RetagScore;
26073471bf0Spatrick   SlotWithTag MaxScoreST{-1, -1};
26173471bf0Spatrick   int MaxScore = -1;
26273471bf0Spatrick   for (auto *I : ReTags) {
26373471bf0Spatrick     SlotWithTag ST{*I};
26473471bf0Spatrick     if (isSlotPreAllocated(MFI, ST.FI))
26573471bf0Spatrick       continue;
26673471bf0Spatrick 
26773471bf0Spatrick     Register RetagReg = I->getOperand(0).getReg();
268*d415bd75Srobert     if (!RetagReg.isVirtual())
26973471bf0Spatrick       continue;
27073471bf0Spatrick 
27173471bf0Spatrick     int Score = 0;
27273471bf0Spatrick     SmallVector<Register, 8> WorkList;
27373471bf0Spatrick     WorkList.push_back(RetagReg);
27473471bf0Spatrick 
27573471bf0Spatrick     while (!WorkList.empty()) {
276*d415bd75Srobert       Register UseReg = WorkList.pop_back_val();
27773471bf0Spatrick       for (auto &UseI : MRI->use_instructions(UseReg)) {
27873471bf0Spatrick         unsigned Opcode = UseI.getOpcode();
27973471bf0Spatrick         if (Opcode == AArch64::STGOffset || Opcode == AArch64::ST2GOffset ||
28073471bf0Spatrick             Opcode == AArch64::STZGOffset || Opcode == AArch64::STZ2GOffset ||
28173471bf0Spatrick             Opcode == AArch64::STGPi || Opcode == AArch64::STGloop ||
28273471bf0Spatrick             Opcode == AArch64::STZGloop || Opcode == AArch64::STGloop_wback ||
28373471bf0Spatrick             Opcode == AArch64::STZGloop_wback)
28473471bf0Spatrick           continue;
28573471bf0Spatrick         if (UseI.isCopy()) {
28673471bf0Spatrick           Register DstReg = UseI.getOperand(0).getReg();
287*d415bd75Srobert           if (DstReg.isVirtual())
28873471bf0Spatrick             WorkList.push_back(DstReg);
28973471bf0Spatrick           continue;
29073471bf0Spatrick         }
29173471bf0Spatrick         LLVM_DEBUG(dbgs() << "[" << ST.FI << ":" << ST.Tag << "] use of %"
29273471bf0Spatrick                           << Register::virtReg2Index(UseReg) << " in " << UseI
29373471bf0Spatrick                           << "\n");
29473471bf0Spatrick         Score++;
29573471bf0Spatrick       }
29673471bf0Spatrick     }
29773471bf0Spatrick 
29873471bf0Spatrick     int TotalScore = RetagScore[ST] += Score;
29973471bf0Spatrick     if (TotalScore > MaxScore ||
30073471bf0Spatrick         (TotalScore == MaxScore && ST.FI > MaxScoreST.FI)) {
30173471bf0Spatrick       MaxScore = TotalScore;
30273471bf0Spatrick       MaxScoreST = ST;
30373471bf0Spatrick     }
30473471bf0Spatrick   }
30573471bf0Spatrick 
30673471bf0Spatrick   if (MaxScoreST.FI < 0)
307*d415bd75Srobert     return std::nullopt;
30873471bf0Spatrick 
30973471bf0Spatrick   // If FI's tag is already 0, we are done.
31073471bf0Spatrick   if (MaxScoreST.Tag == 0)
31173471bf0Spatrick     return MaxScoreST.FI;
31273471bf0Spatrick 
31373471bf0Spatrick   // Otherwise, find a random victim pair (FI, Tag) where Tag == 0.
31473471bf0Spatrick   SlotWithTag SwapST{-1, -1};
31573471bf0Spatrick   for (auto *I : ReTags) {
31673471bf0Spatrick     SlotWithTag ST{*I};
31773471bf0Spatrick     if (ST.Tag == 0) {
31873471bf0Spatrick       SwapST = ST;
31973471bf0Spatrick       break;
32073471bf0Spatrick     }
32173471bf0Spatrick   }
32273471bf0Spatrick 
32373471bf0Spatrick   // Swap tags between the victim and the highest scoring pair.
32473471bf0Spatrick   // If SwapWith is still (-1, -1), that's fine, too - we'll simply take tag for
32573471bf0Spatrick   // the highest score slot without changing anything else.
32673471bf0Spatrick   for (auto *&I : ReTags) {
32773471bf0Spatrick     SlotWithTag ST{*I};
32873471bf0Spatrick     MachineOperand &TagOp = I->getOperand(4);
32973471bf0Spatrick     if (ST == MaxScoreST) {
33073471bf0Spatrick       TagOp.setImm(0);
33173471bf0Spatrick     } else if (ST == SwapST) {
33273471bf0Spatrick       TagOp.setImm(MaxScoreST.Tag);
33373471bf0Spatrick     }
33473471bf0Spatrick   }
33573471bf0Spatrick   return MaxScoreST.FI;
33673471bf0Spatrick }
33773471bf0Spatrick 
runOnMachineFunction(MachineFunction & Func)33809467b48Spatrick bool AArch64StackTaggingPreRA::runOnMachineFunction(MachineFunction &Func) {
33909467b48Spatrick   MF = &Func;
34009467b48Spatrick   MRI = &MF->getRegInfo();
34109467b48Spatrick   AFI = MF->getInfo<AArch64FunctionInfo>();
34209467b48Spatrick   TII = static_cast<const AArch64InstrInfo *>(MF->getSubtarget().getInstrInfo());
34309467b48Spatrick   TRI = static_cast<const AArch64RegisterInfo *>(
34409467b48Spatrick       MF->getSubtarget().getRegisterInfo());
34509467b48Spatrick   MFI = &MF->getFrameInfo();
34609467b48Spatrick   ReTags.clear();
34709467b48Spatrick 
34809467b48Spatrick   assert(MRI->isSSA());
34909467b48Spatrick 
35009467b48Spatrick   LLVM_DEBUG(dbgs() << "********** AArch64 Stack Tagging PreRA **********\n"
35109467b48Spatrick                     << "********** Function: " << MF->getName() << '\n');
35209467b48Spatrick 
35309467b48Spatrick   SmallSetVector<int, 8> TaggedSlots;
35409467b48Spatrick   for (auto &BB : *MF) {
35509467b48Spatrick     for (auto &I : BB) {
35609467b48Spatrick       if (I.getOpcode() == AArch64::TAGPstack) {
35709467b48Spatrick         ReTags.push_back(&I);
35809467b48Spatrick         int FI = I.getOperand(1).getIndex();
35909467b48Spatrick         TaggedSlots.insert(FI);
36009467b48Spatrick         // There should be no offsets in TAGP yet.
36109467b48Spatrick         assert(I.getOperand(2).getImm() == 0);
36209467b48Spatrick       }
36309467b48Spatrick     }
36409467b48Spatrick   }
36509467b48Spatrick 
36673471bf0Spatrick   // Take over from SSP. It does nothing for tagged slots, and should not really
36773471bf0Spatrick   // have been enabled in the first place.
36873471bf0Spatrick   for (int FI : TaggedSlots)
36973471bf0Spatrick     MFI->setObjectSSPLayout(FI, MachineFrameInfo::SSPLK_None);
37073471bf0Spatrick 
37109467b48Spatrick   if (ReTags.empty())
37209467b48Spatrick     return false;
37309467b48Spatrick 
37409467b48Spatrick   if (mayUseUncheckedLoadStore())
37509467b48Spatrick     uncheckLoadsAndStores();
37609467b48Spatrick 
37773471bf0Spatrick   // Find a slot that is used with zero tag offset, like ADDG #fi, 0.
37873471bf0Spatrick   // If the base tagged pointer is set up to the address of this slot,
37973471bf0Spatrick   // the ADDG instruction can be eliminated.
380*d415bd75Srobert   std::optional<int> BaseSlot = findFirstSlotCandidate();
38173471bf0Spatrick   if (BaseSlot)
38273471bf0Spatrick     AFI->setTaggedBasePointerIndex(*BaseSlot);
38373471bf0Spatrick 
38473471bf0Spatrick   for (auto *I : ReTags) {
38573471bf0Spatrick     int FI = I->getOperand(1).getIndex();
38673471bf0Spatrick     int Tag = I->getOperand(4).getImm();
38773471bf0Spatrick     Register Base = I->getOperand(3).getReg();
38873471bf0Spatrick     if (Tag == 0 && FI == BaseSlot) {
38973471bf0Spatrick       BuildMI(*I->getParent(), I, {}, TII->get(AArch64::COPY),
39073471bf0Spatrick               I->getOperand(0).getReg())
39173471bf0Spatrick           .addReg(Base);
39273471bf0Spatrick       I->eraseFromParent();
39373471bf0Spatrick     }
39473471bf0Spatrick   }
39573471bf0Spatrick 
39609467b48Spatrick   return true;
39709467b48Spatrick }
398