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