xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- AArch64SelectionDAGInfo.cpp - AArch64 SelectionDAG Info -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the AArch64SelectionDAGInfo class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "AArch64TargetMachine.h"
140b57cec5SDimitry Andric using namespace llvm;
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #define DEBUG_TYPE "aarch64-selectiondag-info"
170b57cec5SDimitry Andric 
18*0fca6ea1SDimitry Andric static cl::opt<bool>
19*0fca6ea1SDimitry Andric     LowerToSMERoutines("aarch64-lower-to-sme-routines", cl::Hidden,
20*0fca6ea1SDimitry Andric                        cl::desc("Enable AArch64 SME memory operations "
21*0fca6ea1SDimitry Andric                                 "to lower to librt functions"),
22*0fca6ea1SDimitry Andric                        cl::init(true));
23*0fca6ea1SDimitry Andric 
EmitMOPS(AArch64ISD::NodeType SDOpcode,SelectionDAG & DAG,const SDLoc & DL,SDValue Chain,SDValue Dst,SDValue SrcOrValue,SDValue Size,Align Alignment,bool isVolatile,MachinePointerInfo DstPtrInfo,MachinePointerInfo SrcPtrInfo) const241fd87a68SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitMOPS(AArch64ISD::NodeType SDOpcode,
251fd87a68SDimitry Andric                                           SelectionDAG &DAG, const SDLoc &DL,
261fd87a68SDimitry Andric                                           SDValue Chain, SDValue Dst,
271fd87a68SDimitry Andric                                           SDValue SrcOrValue, SDValue Size,
281fd87a68SDimitry Andric                                           Align Alignment, bool isVolatile,
291fd87a68SDimitry Andric                                           MachinePointerInfo DstPtrInfo,
301fd87a68SDimitry Andric                                           MachinePointerInfo SrcPtrInfo) const {
311fd87a68SDimitry Andric 
321fd87a68SDimitry Andric   // Get the constant size of the copy/set.
331fd87a68SDimitry Andric   uint64_t ConstSize = 0;
341fd87a68SDimitry Andric   if (auto *C = dyn_cast<ConstantSDNode>(Size))
351fd87a68SDimitry Andric     ConstSize = C->getZExtValue();
361fd87a68SDimitry Andric 
371fd87a68SDimitry Andric   const bool IsSet = SDOpcode == AArch64ISD::MOPS_MEMSET ||
381fd87a68SDimitry Andric                      SDOpcode == AArch64ISD::MOPS_MEMSET_TAGGING;
391fd87a68SDimitry Andric 
401fd87a68SDimitry Andric   const auto MachineOpcode = [&]() {
411fd87a68SDimitry Andric     switch (SDOpcode) {
421fd87a68SDimitry Andric     case AArch64ISD::MOPS_MEMSET:
431fd87a68SDimitry Andric       return AArch64::MOPSMemorySetPseudo;
441fd87a68SDimitry Andric     case AArch64ISD::MOPS_MEMSET_TAGGING:
451fd87a68SDimitry Andric       return AArch64::MOPSMemorySetTaggingPseudo;
461fd87a68SDimitry Andric     case AArch64ISD::MOPS_MEMCOPY:
471fd87a68SDimitry Andric       return AArch64::MOPSMemoryCopyPseudo;
481fd87a68SDimitry Andric     case AArch64ISD::MOPS_MEMMOVE:
491fd87a68SDimitry Andric       return AArch64::MOPSMemoryMovePseudo;
501fd87a68SDimitry Andric     default:
511fd87a68SDimitry Andric       llvm_unreachable("Unhandled MOPS ISD Opcode");
521fd87a68SDimitry Andric     }
531fd87a68SDimitry Andric   }();
541fd87a68SDimitry Andric 
551fd87a68SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
561fd87a68SDimitry Andric 
575f757f3fSDimitry Andric   auto Vol =
585f757f3fSDimitry Andric       isVolatile ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone;
595f757f3fSDimitry Andric   auto DstFlags = MachineMemOperand::MOStore | Vol;
601fd87a68SDimitry Andric   auto *DstOp =
615f757f3fSDimitry Andric       MF.getMachineMemOperand(DstPtrInfo, DstFlags, ConstSize, Alignment);
621fd87a68SDimitry Andric 
631fd87a68SDimitry Andric   if (IsSet) {
645f757f3fSDimitry Andric     // Extend value to i64, if required.
651fd87a68SDimitry Andric     if (SrcOrValue.getValueType() != MVT::i64)
661fd87a68SDimitry Andric       SrcOrValue = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, SrcOrValue);
671fd87a68SDimitry Andric     SDValue Ops[] = {Dst, Size, SrcOrValue, Chain};
681fd87a68SDimitry Andric     const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::Other};
691fd87a68SDimitry Andric     MachineSDNode *Node = DAG.getMachineNode(MachineOpcode, DL, ResultTys, Ops);
701fd87a68SDimitry Andric     DAG.setNodeMemRefs(Node, {DstOp});
711fd87a68SDimitry Andric     return SDValue(Node, 2);
721fd87a68SDimitry Andric   } else {
731fd87a68SDimitry Andric     SDValue Ops[] = {Dst, SrcOrValue, Size, Chain};
741fd87a68SDimitry Andric     const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::i64, MVT::Other};
751fd87a68SDimitry Andric     MachineSDNode *Node = DAG.getMachineNode(MachineOpcode, DL, ResultTys, Ops);
765f757f3fSDimitry Andric 
775f757f3fSDimitry Andric     auto SrcFlags = MachineMemOperand::MOLoad | Vol;
785f757f3fSDimitry Andric     auto *SrcOp =
795f757f3fSDimitry Andric         MF.getMachineMemOperand(SrcPtrInfo, SrcFlags, ConstSize, Alignment);
801fd87a68SDimitry Andric     DAG.setNodeMemRefs(Node, {DstOp, SrcOp});
811fd87a68SDimitry Andric     return SDValue(Node, 3);
821fd87a68SDimitry Andric   }
831fd87a68SDimitry Andric }
841fd87a68SDimitry Andric 
EmitStreamingCompatibleMemLibCall(SelectionDAG & DAG,const SDLoc & DL,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,RTLIB::Libcall LC) const85*0fca6ea1SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitStreamingCompatibleMemLibCall(
86*0fca6ea1SDimitry Andric     SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
87*0fca6ea1SDimitry Andric     SDValue Size, RTLIB::Libcall LC) const {
88*0fca6ea1SDimitry Andric   const AArch64Subtarget &STI =
89*0fca6ea1SDimitry Andric       DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
90*0fca6ea1SDimitry Andric   const AArch64TargetLowering *TLI = STI.getTargetLowering();
91*0fca6ea1SDimitry Andric   SDValue Symbol;
92*0fca6ea1SDimitry Andric   TargetLowering::ArgListEntry DstEntry;
93*0fca6ea1SDimitry Andric   DstEntry.Ty = PointerType::getUnqual(*DAG.getContext());
94*0fca6ea1SDimitry Andric   DstEntry.Node = Dst;
95*0fca6ea1SDimitry Andric   TargetLowering::ArgListTy Args;
96*0fca6ea1SDimitry Andric   Args.push_back(DstEntry);
97*0fca6ea1SDimitry Andric   EVT PointerVT = TLI->getPointerTy(DAG.getDataLayout());
98*0fca6ea1SDimitry Andric 
99*0fca6ea1SDimitry Andric   switch (LC) {
100*0fca6ea1SDimitry Andric   case RTLIB::MEMCPY: {
101*0fca6ea1SDimitry Andric     TargetLowering::ArgListEntry Entry;
102*0fca6ea1SDimitry Andric     Entry.Ty = PointerType::getUnqual(*DAG.getContext());
103*0fca6ea1SDimitry Andric     Symbol = DAG.getExternalSymbol("__arm_sc_memcpy", PointerVT);
104*0fca6ea1SDimitry Andric     Entry.Node = Src;
105*0fca6ea1SDimitry Andric     Args.push_back(Entry);
106*0fca6ea1SDimitry Andric     break;
107*0fca6ea1SDimitry Andric   }
108*0fca6ea1SDimitry Andric   case RTLIB::MEMMOVE: {
109*0fca6ea1SDimitry Andric     TargetLowering::ArgListEntry Entry;
110*0fca6ea1SDimitry Andric     Entry.Ty = PointerType::getUnqual(*DAG.getContext());
111*0fca6ea1SDimitry Andric     Symbol = DAG.getExternalSymbol("__arm_sc_memmove", PointerVT);
112*0fca6ea1SDimitry Andric     Entry.Node = Src;
113*0fca6ea1SDimitry Andric     Args.push_back(Entry);
114*0fca6ea1SDimitry Andric     break;
115*0fca6ea1SDimitry Andric   }
116*0fca6ea1SDimitry Andric   case RTLIB::MEMSET: {
117*0fca6ea1SDimitry Andric     TargetLowering::ArgListEntry Entry;
118*0fca6ea1SDimitry Andric     Entry.Ty = Type::getInt32Ty(*DAG.getContext());
119*0fca6ea1SDimitry Andric     Symbol = DAG.getExternalSymbol("__arm_sc_memset", PointerVT);
120*0fca6ea1SDimitry Andric     Src = DAG.getZExtOrTrunc(Src, DL, MVT::i32);
121*0fca6ea1SDimitry Andric     Entry.Node = Src;
122*0fca6ea1SDimitry Andric     Args.push_back(Entry);
123*0fca6ea1SDimitry Andric     break;
124*0fca6ea1SDimitry Andric   }
125*0fca6ea1SDimitry Andric   default:
126*0fca6ea1SDimitry Andric     return SDValue();
127*0fca6ea1SDimitry Andric   }
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric   TargetLowering::ArgListEntry SizeEntry;
130*0fca6ea1SDimitry Andric   SizeEntry.Node = Size;
131*0fca6ea1SDimitry Andric   SizeEntry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
132*0fca6ea1SDimitry Andric   Args.push_back(SizeEntry);
133*0fca6ea1SDimitry Andric   assert(Symbol->getOpcode() == ISD::ExternalSymbol &&
134*0fca6ea1SDimitry Andric          "Function name is not set");
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric   TargetLowering::CallLoweringInfo CLI(DAG);
137*0fca6ea1SDimitry Andric   PointerType *RetTy = PointerType::getUnqual(*DAG.getContext());
138*0fca6ea1SDimitry Andric   CLI.setDebugLoc(DL).setChain(Chain).setLibCallee(
139*0fca6ea1SDimitry Andric       TLI->getLibcallCallingConv(LC), RetTy, Symbol, std::move(Args));
140*0fca6ea1SDimitry Andric   return TLI->LowerCallTo(CLI).second;
141*0fca6ea1SDimitry Andric }
142*0fca6ea1SDimitry Andric 
EmitTargetCodeForMemcpy(SelectionDAG & DAG,const SDLoc & DL,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,Align Alignment,bool isVolatile,bool AlwaysInline,MachinePointerInfo DstPtrInfo,MachinePointerInfo SrcPtrInfo) const1431fd87a68SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemcpy(
1441fd87a68SDimitry Andric     SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
1451fd87a68SDimitry Andric     SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
1461fd87a68SDimitry Andric     MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
1471fd87a68SDimitry Andric   const AArch64Subtarget &STI =
1481fd87a68SDimitry Andric       DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
149*0fca6ea1SDimitry Andric 
1501fd87a68SDimitry Andric   if (STI.hasMOPS())
1511fd87a68SDimitry Andric     return EmitMOPS(AArch64ISD::MOPS_MEMCOPY, DAG, DL, Chain, Dst, Src, Size,
1521fd87a68SDimitry Andric                     Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
153*0fca6ea1SDimitry Andric 
154*0fca6ea1SDimitry Andric   SMEAttrs Attrs(DAG.getMachineFunction().getFunction());
155*0fca6ea1SDimitry Andric   if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
156*0fca6ea1SDimitry Andric     return EmitStreamingCompatibleMemLibCall(DAG, DL, Chain, Dst, Src, Size,
157*0fca6ea1SDimitry Andric                                              RTLIB::MEMCPY);
1581fd87a68SDimitry Andric   return SDValue();
1591fd87a68SDimitry Andric }
1601fd87a68SDimitry Andric 
EmitTargetCodeForMemset(SelectionDAG & DAG,const SDLoc & dl,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,Align Alignment,bool isVolatile,bool AlwaysInline,MachinePointerInfo DstPtrInfo) const1610b57cec5SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemset(
1620b57cec5SDimitry Andric     SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
16381ad6265SDimitry Andric     SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
1640b57cec5SDimitry Andric     MachinePointerInfo DstPtrInfo) const {
1651fd87a68SDimitry Andric   const AArch64Subtarget &STI =
1661fd87a68SDimitry Andric       DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
1671fd87a68SDimitry Andric 
168*0fca6ea1SDimitry Andric   if (STI.hasMOPS())
1691fd87a68SDimitry Andric     return EmitMOPS(AArch64ISD::MOPS_MEMSET, DAG, dl, Chain, Dst, Src, Size,
1701fd87a68SDimitry Andric                     Alignment, isVolatile, DstPtrInfo, MachinePointerInfo{});
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric   SMEAttrs Attrs(DAG.getMachineFunction().getFunction());
173*0fca6ea1SDimitry Andric   if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
174*0fca6ea1SDimitry Andric     return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
175*0fca6ea1SDimitry Andric                                              RTLIB::MEMSET);
1760b57cec5SDimitry Andric   return SDValue();
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
EmitTargetCodeForMemmove(SelectionDAG & DAG,const SDLoc & dl,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,Align Alignment,bool isVolatile,MachinePointerInfo DstPtrInfo,MachinePointerInfo SrcPtrInfo) const1791fd87a68SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemmove(
1801fd87a68SDimitry Andric     SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
1811fd87a68SDimitry Andric     SDValue Size, Align Alignment, bool isVolatile,
1821fd87a68SDimitry Andric     MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
1831fd87a68SDimitry Andric   const AArch64Subtarget &STI =
1841fd87a68SDimitry Andric       DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
185*0fca6ea1SDimitry Andric 
186*0fca6ea1SDimitry Andric   if (STI.hasMOPS())
1871fd87a68SDimitry Andric     return EmitMOPS(AArch64ISD::MOPS_MEMMOVE, DAG, dl, Chain, Dst, Src, Size,
1881fd87a68SDimitry Andric                     Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
189*0fca6ea1SDimitry Andric 
190*0fca6ea1SDimitry Andric   SMEAttrs Attrs(DAG.getMachineFunction().getFunction());
191*0fca6ea1SDimitry Andric   if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
192*0fca6ea1SDimitry Andric     return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
193*0fca6ea1SDimitry Andric                                              RTLIB::MEMMOVE);
1941fd87a68SDimitry Andric   return SDValue();
1951fd87a68SDimitry Andric }
1961fd87a68SDimitry Andric 
1970b57cec5SDimitry Andric static const int kSetTagLoopThreshold = 176;
1980b57cec5SDimitry Andric 
EmitUnrolledSetTag(SelectionDAG & DAG,const SDLoc & dl,SDValue Chain,SDValue Ptr,uint64_t ObjSize,const MachineMemOperand * BaseMemOperand,bool ZeroData)1990b57cec5SDimitry Andric static SDValue EmitUnrolledSetTag(SelectionDAG &DAG, const SDLoc &dl,
2000b57cec5SDimitry Andric                                   SDValue Chain, SDValue Ptr, uint64_t ObjSize,
2010b57cec5SDimitry Andric                                   const MachineMemOperand *BaseMemOperand,
2020b57cec5SDimitry Andric                                   bool ZeroData) {
2030b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2040b57cec5SDimitry Andric   unsigned ObjSizeScaled = ObjSize / 16;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   SDValue TagSrc = Ptr;
2070b57cec5SDimitry Andric   if (Ptr.getOpcode() == ISD::FrameIndex) {
2080b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
2090b57cec5SDimitry Andric     Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
2100b57cec5SDimitry Andric     // A frame index operand may end up as [SP + offset] => it is fine to use SP
2110b57cec5SDimitry Andric     // register as the tag source.
2120b57cec5SDimitry Andric     TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
2160b57cec5SDimitry Andric   const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   SmallVector<SDValue, 8> OutChains;
2190b57cec5SDimitry Andric   unsigned OffsetScaled = 0;
2200b57cec5SDimitry Andric   while (OffsetScaled < ObjSizeScaled) {
2210b57cec5SDimitry Andric     if (ObjSizeScaled - OffsetScaled >= 2) {
2225f757f3fSDimitry Andric       SDValue AddrNode = DAG.getMemBasePlusOffset(
2235f757f3fSDimitry Andric           Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
2240b57cec5SDimitry Andric       SDValue St = DAG.getMemIntrinsicNode(
2250b57cec5SDimitry Andric           OpCode2, dl, DAG.getVTList(MVT::Other),
2260b57cec5SDimitry Andric           {Chain, TagSrc, AddrNode},
2270b57cec5SDimitry Andric           MVT::v4i64,
2280b57cec5SDimitry Andric           MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
2290b57cec5SDimitry Andric       OffsetScaled += 2;
2300b57cec5SDimitry Andric       OutChains.push_back(St);
2310b57cec5SDimitry Andric       continue;
2320b57cec5SDimitry Andric     }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric     if (ObjSizeScaled - OffsetScaled > 0) {
2355f757f3fSDimitry Andric       SDValue AddrNode = DAG.getMemBasePlusOffset(
2365f757f3fSDimitry Andric           Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
2370b57cec5SDimitry Andric       SDValue St = DAG.getMemIntrinsicNode(
2380b57cec5SDimitry Andric           OpCode1, dl, DAG.getVTList(MVT::Other),
2390b57cec5SDimitry Andric           {Chain, TagSrc, AddrNode},
2400b57cec5SDimitry Andric           MVT::v2i64,
2410b57cec5SDimitry Andric           MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
2420b57cec5SDimitry Andric       OffsetScaled += 1;
2430b57cec5SDimitry Andric       OutChains.push_back(St);
2440b57cec5SDimitry Andric     }
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
2480b57cec5SDimitry Andric   return Res;
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
EmitTargetCodeForSetTag(SelectionDAG & DAG,const SDLoc & dl,SDValue Chain,SDValue Addr,SDValue Size,MachinePointerInfo DstPtrInfo,bool ZeroData) const2510b57cec5SDimitry Andric SDValue AArch64SelectionDAGInfo::EmitTargetCodeForSetTag(
2520b57cec5SDimitry Andric     SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
2530b57cec5SDimitry Andric     SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
2541db9f3b2SDimitry Andric   uint64_t ObjSize = Size->getAsZExtVal();
2550b57cec5SDimitry Andric   assert(ObjSize % 16 == 0);
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2580b57cec5SDimitry Andric   MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
2595ffd83dbSDimitry Andric       DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   bool UseSetTagRangeLoop =
2620b57cec5SDimitry Andric       kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
2630b57cec5SDimitry Andric   if (!UseSetTagRangeLoop)
2640b57cec5SDimitry Andric     return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
2650b57cec5SDimitry Andric                               ZeroData);
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
2685ffd83dbSDimitry Andric 
2695ffd83dbSDimitry Andric   unsigned Opcode;
2705ffd83dbSDimitry Andric   if (Addr.getOpcode() == ISD::FrameIndex) {
2715ffd83dbSDimitry Andric     int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
2725ffd83dbSDimitry Andric     Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
2735ffd83dbSDimitry Andric     Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
2745ffd83dbSDimitry Andric   } else {
2755ffd83dbSDimitry Andric     Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
2765ffd83dbSDimitry Andric   }
2775ffd83dbSDimitry Andric   SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
2785ffd83dbSDimitry Andric   SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric   DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
2810b57cec5SDimitry Andric   return SDValue(St, 2);
2820b57cec5SDimitry Andric }
283