LLVM 20.0.0git
AArch64SelectionDAGInfo.cpp
Go to the documentation of this file.
1//===-- AArch64SelectionDAGInfo.cpp - AArch64 SelectionDAG Info -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the AArch64SelectionDAGInfo class.
10//
11//===----------------------------------------------------------------------===//
12
15
16using namespace llvm;
17
18#define DEBUG_TYPE "aarch64-selectiondag-info"
19
20static cl::opt<bool>
21 LowerToSMERoutines("aarch64-lower-to-sme-routines", cl::Hidden,
22 cl::desc("Enable AArch64 SME memory operations "
23 "to lower to librt functions"),
24 cl::init(true));
25
27 return Opcode >= AArch64ISD::FIRST_MEMORY_OPCODE &&
29}
30
32 return Opcode >= AArch64ISD::FIRST_STRICTFP_OPCODE &&
34}
35
37 const SDLoc &DL, SDValue Chain,
38 SDValue Dst, SDValue SrcOrValue,
39 SDValue Size, Align Alignment,
40 bool isVolatile,
41 MachinePointerInfo DstPtrInfo,
42 MachinePointerInfo SrcPtrInfo) const {
43
44 // Get the constant size of the copy/set.
45 uint64_t ConstSize = 0;
46 if (auto *C = dyn_cast<ConstantSDNode>(Size))
47 ConstSize = C->getZExtValue();
48
49 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
50 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
51
53
54 auto Vol =
56 auto DstFlags = MachineMemOperand::MOStore | Vol;
57 auto *DstOp =
58 MF.getMachineMemOperand(DstPtrInfo, DstFlags, ConstSize, Alignment);
59
60 if (IsSet) {
61 // Extend value to i64, if required.
62 if (SrcOrValue.getValueType() != MVT::i64)
63 SrcOrValue = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, SrcOrValue);
64 SDValue Ops[] = {Dst, Size, SrcOrValue, Chain};
65 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::Other};
66 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
67 DAG.setNodeMemRefs(Node, {DstOp});
68 return SDValue(Node, 2);
69 } else {
70 SDValue Ops[] = {Dst, SrcOrValue, Size, Chain};
71 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::i64, MVT::Other};
72 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
73
74 auto SrcFlags = MachineMemOperand::MOLoad | Vol;
75 auto *SrcOp =
76 MF.getMachineMemOperand(SrcPtrInfo, SrcFlags, ConstSize, Alignment);
77 DAG.setNodeMemRefs(Node, {DstOp, SrcOp});
78 return SDValue(Node, 3);
79 }
80}
81
83 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
84 SDValue Size, RTLIB::Libcall LC) const {
85 const AArch64Subtarget &STI =
88 SDValue Symbol;
90 DstEntry.Ty = PointerType::getUnqual(*DAG.getContext());
91 DstEntry.Node = Dst;
93 Args.push_back(DstEntry);
94 EVT PointerVT = TLI->getPointerTy(DAG.getDataLayout());
95
96 switch (LC) {
97 case RTLIB::MEMCPY: {
99 Entry.Ty = PointerType::getUnqual(*DAG.getContext());
100 Symbol = DAG.getExternalSymbol("__arm_sc_memcpy", PointerVT);
101 Entry.Node = Src;
102 Args.push_back(Entry);
103 break;
104 }
105 case RTLIB::MEMMOVE: {
107 Entry.Ty = PointerType::getUnqual(*DAG.getContext());
108 Symbol = DAG.getExternalSymbol("__arm_sc_memmove", PointerVT);
109 Entry.Node = Src;
110 Args.push_back(Entry);
111 break;
112 }
113 case RTLIB::MEMSET: {
115 Entry.Ty = Type::getInt32Ty(*DAG.getContext());
116 Symbol = DAG.getExternalSymbol("__arm_sc_memset", PointerVT);
117 Src = DAG.getZExtOrTrunc(Src, DL, MVT::i32);
118 Entry.Node = Src;
119 Args.push_back(Entry);
120 break;
121 }
122 default:
123 return SDValue();
124 }
125
127 SizeEntry.Node = Size;
128 SizeEntry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
129 Args.push_back(SizeEntry);
130 assert(Symbol->getOpcode() == ISD::ExternalSymbol &&
131 "Function name is not set");
132
136 TLI->getLibcallCallingConv(LC), RetTy, Symbol, std::move(Args));
137 return TLI->LowerCallTo(CLI).second;
138}
139
141 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
142 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
143 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
144 const AArch64Subtarget &STI =
146
147 if (STI.hasMOPS())
148 return EmitMOPS(AArch64::MOPSMemoryCopyPseudo, DAG, DL, Chain, Dst, Src,
149 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
150
152 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
153 return EmitStreamingCompatibleMemLibCall(DAG, DL, Chain, Dst, Src, Size,
154 RTLIB::MEMCPY);
155 return SDValue();
156}
157
159 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
160 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
161 MachinePointerInfo DstPtrInfo) const {
162 const AArch64Subtarget &STI =
164
165 if (STI.hasMOPS())
166 return EmitMOPS(AArch64::MOPSMemorySetPseudo, DAG, dl, Chain, Dst, Src,
167 Size, Alignment, isVolatile, DstPtrInfo,
169
171 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
172 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
173 RTLIB::MEMSET);
174 return SDValue();
175}
176
178 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
179 SDValue Size, Align Alignment, bool isVolatile,
180 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
181 const AArch64Subtarget &STI =
183
184 if (STI.hasMOPS())
185 return EmitMOPS(AArch64::MOPSMemoryMovePseudo, DAG, dl, Chain, Dst, Src,
186 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
187
189 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
190 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
191 RTLIB::MEMMOVE);
192 return SDValue();
193}
194
195static const int kSetTagLoopThreshold = 176;
196
198 SDValue Chain, SDValue Ptr, uint64_t ObjSize,
199 const MachineMemOperand *BaseMemOperand,
200 bool ZeroData) {
202 unsigned ObjSizeScaled = ObjSize / 16;
203
204 SDValue TagSrc = Ptr;
205 if (Ptr.getOpcode() == ISD::FrameIndex) {
206 int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
207 Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
208 // A frame index operand may end up as [SP + offset] => it is fine to use SP
209 // register as the tag source.
210 TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
211 }
212
213 const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
214 const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
215
216 SmallVector<SDValue, 8> OutChains;
217 unsigned OffsetScaled = 0;
218 while (OffsetScaled < ObjSizeScaled) {
219 if (ObjSizeScaled - OffsetScaled >= 2) {
220 SDValue AddrNode = DAG.getMemBasePlusOffset(
221 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
223 OpCode2, dl, DAG.getVTList(MVT::Other),
224 {Chain, TagSrc, AddrNode},
225 MVT::v4i64,
226 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
227 OffsetScaled += 2;
228 OutChains.push_back(St);
229 continue;
230 }
231
232 if (ObjSizeScaled - OffsetScaled > 0) {
233 SDValue AddrNode = DAG.getMemBasePlusOffset(
234 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
236 OpCode1, dl, DAG.getVTList(MVT::Other),
237 {Chain, TagSrc, AddrNode},
238 MVT::v2i64,
239 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
240 OffsetScaled += 1;
241 OutChains.push_back(St);
242 }
243 }
244
245 SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
246 return Res;
247}
248
250 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
251 SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
252 uint64_t ObjSize = Size->getAsZExtVal();
253 assert(ObjSize % 16 == 0);
254
256 MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
257 DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
258
259 bool UseSetTagRangeLoop =
260 kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
261 if (!UseSetTagRangeLoop)
262 return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
263 ZeroData);
264
265 const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
266
267 unsigned Opcode;
268 if (Addr.getOpcode() == ISD::FrameIndex) {
269 int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
270 Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
271 Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
272 } else {
273 Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
274 }
275 SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
276 SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
277
278 DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
279 return SDValue(St, 2);
280}
static SDValue EmitUnrolledSetTag(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Ptr, uint64_t ObjSize, const MachineMemOperand *BaseMemOperand, bool ZeroData)
static cl::opt< bool > LowerToSMERoutines("aarch64-lower-to-sme-routines", cl::Hidden, cl::desc("Enable AArch64 SME memory operations " "to lower to librt functions"), cl::init(true))
static const int kSetTagLoopThreshold
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
return RetTy
uint64_t Addr
uint64_t Size
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SDValue EmitMOPS(unsigned Opcode, SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue SrcOrValue, SDValue Size, Align Alignment, bool isVolatile, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const
SDValue EmitTargetCodeForMemmove(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVolatile, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const override
Emit target-specific code that performs a memmove.
SDValue EmitStreamingCompatibleMemLibCall(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src, SDValue Size, RTLIB::Libcall LC) const
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const override
Emit target-specific code that performs a memcpy.
bool isTargetStrictFPOpcode(unsigned Opcode) const override
Returns true if a node with the given target-specific opcode has strict floating-point semantics.
bool isTargetMemoryOpcode(unsigned Opcode) const override
Returns true if a node with the given target-specific opcode has a memory operand.
SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline, MachinePointerInfo DstPtrInfo) const override
Emit target-specific code that performs a memset.
SDValue EmitTargetCodeForSetTag(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, SDValue Op2, MachinePointerInfo DstPtrInfo, bool ZeroData) const override
const AArch64TargetLowering * getTargetLowering() const override
IntegerType * getIntPtrType(LLVMContext &C, unsigned AddressSpace=0) const
Returns an integer type with size at least as big as that of a pointer in the given address space.
Definition: DataLayout.cpp:851
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Function & getFunction()
Return the LLVM function that this machine code represents.
A description of a memory reference used in the backend.
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
An SDNode that represents everything that will be needed to construct a MachineInstr.
Class to represent pointers.
Definition: DerivedTypes.h:670
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
Definition: DerivedTypes.h:686
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
EVT getValueType() const
Return the ValueType of the referenced return value.
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
Definition: SelectionDAG.h:228
SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getRegister(Register Reg, EVT VT)
void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
const DataLayout & getDataLayout() const
Definition: SelectionDAG.h:495
SDValue getTargetFrameIndex(int FI, EVT VT)
Definition: SelectionDAG.h:753
SDValue getMemBasePlusOffset(SDValue Base, TypeSize Offset, const SDLoc &DL, const SDNodeFlags Flags=SDNodeFlags())
Returns sum of the base pointer and offset.
SDValue getExternalSymbol(const char *Sym, EVT VT)
SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
Definition: SelectionDAG.h:698
MachineFunction & getMachineFunction() const
Definition: SelectionDAG.h:490
SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVMContext * getContext() const
Definition: SelectionDAG.h:508
SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=0, const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
std::vector< ArgListEntry > ArgListTy
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition: TypeSize.h:345
static IntegerType * getInt32Ty(LLVMContext &C)
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition: ISDOpcodes.h:814
@ FrameIndex
Definition: ISDOpcodes.h:80
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition: ISDOpcodes.h:52
@ ExternalSymbol
Definition: ISDOpcodes.h:83
Libcall
RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Extended Value Type.
Definition: ValueTypes.h:35
This class contains a discriminated union of information about pointers in memory operands,...
This structure contains all information that is necessary for lowering calls.
CallLoweringInfo & setLibCallee(CallingConv::ID CC, Type *ResultType, SDValue Target, ArgListTy &&ArgsList)
CallLoweringInfo & setDebugLoc(const SDLoc &dl)
CallLoweringInfo & setChain(SDValue InChain)