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 const SDLoc &DL, SDValue Chain,
28 SDValue Dst, SDValue SrcOrValue,
29 SDValue Size, Align Alignment,
30 bool isVolatile,
31 MachinePointerInfo DstPtrInfo,
32 MachinePointerInfo SrcPtrInfo) const {
33
34 // Get the constant size of the copy/set.
35 uint64_t ConstSize = 0;
36 if (auto *C = dyn_cast<ConstantSDNode>(Size))
37 ConstSize = C->getZExtValue();
38
39 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
40 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
41
43
44 auto Vol =
46 auto DstFlags = MachineMemOperand::MOStore | Vol;
47 auto *DstOp =
48 MF.getMachineMemOperand(DstPtrInfo, DstFlags, ConstSize, Alignment);
49
50 if (IsSet) {
51 // Extend value to i64, if required.
52 if (SrcOrValue.getValueType() != MVT::i64)
53 SrcOrValue = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, SrcOrValue);
54 SDValue Ops[] = {Dst, Size, SrcOrValue, Chain};
55 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::Other};
56 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
57 DAG.setNodeMemRefs(Node, {DstOp});
58 return SDValue(Node, 2);
59 } else {
60 SDValue Ops[] = {Dst, SrcOrValue, Size, Chain};
61 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::i64, MVT::Other};
62 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
63
64 auto SrcFlags = MachineMemOperand::MOLoad | Vol;
65 auto *SrcOp =
66 MF.getMachineMemOperand(SrcPtrInfo, SrcFlags, ConstSize, Alignment);
67 DAG.setNodeMemRefs(Node, {DstOp, SrcOp});
68 return SDValue(Node, 3);
69 }
70}
71
73 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
74 SDValue Size, RTLIB::Libcall LC) const {
75 const AArch64Subtarget &STI =
78 SDValue Symbol;
80 DstEntry.Ty = PointerType::getUnqual(*DAG.getContext());
81 DstEntry.Node = Dst;
83 Args.push_back(DstEntry);
84 EVT PointerVT = TLI->getPointerTy(DAG.getDataLayout());
85
86 switch (LC) {
87 case RTLIB::MEMCPY: {
89 Entry.Ty = PointerType::getUnqual(*DAG.getContext());
90 Symbol = DAG.getExternalSymbol("__arm_sc_memcpy", PointerVT);
91 Entry.Node = Src;
92 Args.push_back(Entry);
93 break;
94 }
95 case RTLIB::MEMMOVE: {
97 Entry.Ty = PointerType::getUnqual(*DAG.getContext());
98 Symbol = DAG.getExternalSymbol("__arm_sc_memmove", PointerVT);
99 Entry.Node = Src;
100 Args.push_back(Entry);
101 break;
102 }
103 case RTLIB::MEMSET: {
105 Entry.Ty = Type::getInt32Ty(*DAG.getContext());
106 Symbol = DAG.getExternalSymbol("__arm_sc_memset", PointerVT);
107 Src = DAG.getZExtOrTrunc(Src, DL, MVT::i32);
108 Entry.Node = Src;
109 Args.push_back(Entry);
110 break;
111 }
112 default:
113 return SDValue();
114 }
115
117 SizeEntry.Node = Size;
118 SizeEntry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
119 Args.push_back(SizeEntry);
120 assert(Symbol->getOpcode() == ISD::ExternalSymbol &&
121 "Function name is not set");
122
126 TLI->getLibcallCallingConv(LC), RetTy, Symbol, std::move(Args));
127 return TLI->LowerCallTo(CLI).second;
128}
129
131 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
132 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
133 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
134 const AArch64Subtarget &STI =
136
137 if (STI.hasMOPS())
138 return EmitMOPS(AArch64::MOPSMemoryCopyPseudo, DAG, DL, Chain, Dst, Src,
139 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
140
142 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
143 return EmitStreamingCompatibleMemLibCall(DAG, DL, Chain, Dst, Src, Size,
144 RTLIB::MEMCPY);
145 return SDValue();
146}
147
149 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
150 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
151 MachinePointerInfo DstPtrInfo) const {
152 const AArch64Subtarget &STI =
154
155 if (STI.hasMOPS())
156 return EmitMOPS(AArch64::MOPSMemorySetPseudo, DAG, dl, Chain, Dst, Src,
157 Size, Alignment, isVolatile, DstPtrInfo,
159
161 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
162 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
163 RTLIB::MEMSET);
164 return SDValue();
165}
166
168 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
169 SDValue Size, Align Alignment, bool isVolatile,
170 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
171 const AArch64Subtarget &STI =
173
174 if (STI.hasMOPS())
175 return EmitMOPS(AArch64::MOPSMemoryMovePseudo, DAG, dl, Chain, Dst, Src,
176 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
177
179 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
180 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
181 RTLIB::MEMMOVE);
182 return SDValue();
183}
184
185static const int kSetTagLoopThreshold = 176;
186
188 SDValue Chain, SDValue Ptr, uint64_t ObjSize,
189 const MachineMemOperand *BaseMemOperand,
190 bool ZeroData) {
192 unsigned ObjSizeScaled = ObjSize / 16;
193
194 SDValue TagSrc = Ptr;
195 if (Ptr.getOpcode() == ISD::FrameIndex) {
196 int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
197 Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
198 // A frame index operand may end up as [SP + offset] => it is fine to use SP
199 // register as the tag source.
200 TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
201 }
202
203 const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
204 const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
205
206 SmallVector<SDValue, 8> OutChains;
207 unsigned OffsetScaled = 0;
208 while (OffsetScaled < ObjSizeScaled) {
209 if (ObjSizeScaled - OffsetScaled >= 2) {
210 SDValue AddrNode = DAG.getMemBasePlusOffset(
211 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
213 OpCode2, dl, DAG.getVTList(MVT::Other),
214 {Chain, TagSrc, AddrNode},
215 MVT::v4i64,
216 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
217 OffsetScaled += 2;
218 OutChains.push_back(St);
219 continue;
220 }
221
222 if (ObjSizeScaled - OffsetScaled > 0) {
223 SDValue AddrNode = DAG.getMemBasePlusOffset(
224 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
226 OpCode1, dl, DAG.getVTList(MVT::Other),
227 {Chain, TagSrc, AddrNode},
228 MVT::v2i64,
229 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
230 OffsetScaled += 1;
231 OutChains.push_back(St);
232 }
233 }
234
235 SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
236 return Res;
237}
238
240 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
241 SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
242 uint64_t ObjSize = Size->getAsZExtVal();
243 assert(ObjSize % 16 == 0);
244
246 MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
247 DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
248
249 bool UseSetTagRangeLoop =
250 kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
251 if (!UseSetTagRangeLoop)
252 return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
253 ZeroData);
254
255 const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
256
257 unsigned Opcode;
258 if (Addr.getOpcode() == ISD::FrameIndex) {
259 int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
260 Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
261 Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
262 } else {
263 Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
264 }
265 SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
266 SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
267
268 DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
269 return SDValue(St, 2);
270}
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.
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)