LLVM 22.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
16#define GET_SDNODE_DESC
17#include "AArch64GenSDNodeInfo.inc"
18#undef GET_SDNODE_DESC
19
20using namespace llvm;
21
22#define DEBUG_TYPE "aarch64-selectiondag-info"
23
24static cl::opt<bool>
25 LowerToSMERoutines("aarch64-lower-to-sme-routines", cl::Hidden,
26 cl::desc("Enable AArch64 SME memory operations "
27 "to lower to librt functions"),
28 cl::init(true));
29
32
34 const SDNode *N) const {
35 switch (N->getOpcode()) {
36 case AArch64ISD::WrapperLarge:
37 // operand #0 must have type i32, but has type i64
38 return;
39 }
40
42
43#ifndef NDEBUG
44 // Some additional checks not yet implemented by verifyTargetNode.
45 switch (N->getOpcode()) {
46 case AArch64ISD::SADDWT:
47 case AArch64ISD::SADDWB:
48 case AArch64ISD::UADDWT:
49 case AArch64ISD::UADDWB: {
50 EVT VT = N->getValueType(0);
51 EVT Op0VT = N->getOperand(0).getValueType();
52 EVT Op1VT = N->getOperand(1).getValueType();
53 assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() &&
54 VT.isInteger() && Op0VT.isInteger() && Op1VT.isInteger() &&
55 "Expected integer vectors!");
56 assert(VT == Op0VT &&
57 "Expected result and first input to have the same type!");
58 assert(Op0VT.getSizeInBits() == Op1VT.getSizeInBits() &&
59 "Expected vectors of equal size!");
60 assert(Op0VT.getVectorElementCount() * 2 == Op1VT.getVectorElementCount() &&
61 "Expected result vector and first input vector to have half the "
62 "lanes of the second input vector!");
63 break;
64 }
65 case AArch64ISD::SUNPKLO:
66 case AArch64ISD::SUNPKHI:
67 case AArch64ISD::UUNPKLO:
68 case AArch64ISD::UUNPKHI: {
69 EVT VT = N->getValueType(0);
70 EVT OpVT = N->getOperand(0).getValueType();
71 assert(OpVT.isVector() && VT.isVector() && OpVT.isInteger() &&
72 VT.isInteger() && "Expected integer vectors!");
73 assert(OpVT.getSizeInBits() == VT.getSizeInBits() &&
74 "Expected vectors of equal size!");
76 "Expected result vector with half the lanes of its input!");
77 break;
78 }
79 case AArch64ISD::TRN1:
80 case AArch64ISD::TRN2:
81 case AArch64ISD::UZP1:
82 case AArch64ISD::UZP2:
83 case AArch64ISD::ZIP1:
84 case AArch64ISD::ZIP2: {
85 EVT VT = N->getValueType(0);
86 EVT Op0VT = N->getOperand(0).getValueType();
87 EVT Op1VT = N->getOperand(1).getValueType();
88 assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() &&
89 "Expected vectors!");
90 assert(VT == Op0VT && VT == Op1VT && "Expected matching vectors!");
91 break;
92 }
93 case AArch64ISD::RSHRNB_I: {
94 EVT VT = N->getValueType(0);
95 EVT Op0VT = N->getOperand(0).getValueType();
96 assert(VT.isVector() && VT.isInteger() &&
97 "Expected integer vector result type!");
98 assert(Op0VT.isVector() && Op0VT.isInteger() &&
99 "Expected first operand to be an integer vector!");
100 assert(VT.getSizeInBits() == Op0VT.getSizeInBits() &&
101 "Expected vectors of equal size!");
103 "Expected input vector with half the lanes of its result!");
104 assert(isa<ConstantSDNode>(N->getOperand(1)) &&
105 "Expected second operand to be a constant!");
106 break;
107 }
108 }
109#endif
110}
111
113 const SDLoc &DL, SDValue Chain,
114 SDValue Dst, SDValue SrcOrValue,
115 SDValue Size, Align Alignment,
116 bool isVolatile,
117 MachinePointerInfo DstPtrInfo,
118 MachinePointerInfo SrcPtrInfo) const {
119
120 // Get the constant size of the copy/set.
121 uint64_t ConstSize = 0;
122 if (auto *C = dyn_cast<ConstantSDNode>(Size))
123 ConstSize = C->getZExtValue();
124
125 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
126 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
127
129
130 auto Vol =
132 auto DstFlags = MachineMemOperand::MOStore | Vol;
133 auto *DstOp =
134 MF.getMachineMemOperand(DstPtrInfo, DstFlags, ConstSize, Alignment);
135
136 if (IsSet) {
137 // Extend value to i64, if required.
138 if (SrcOrValue.getValueType() != MVT::i64)
139 SrcOrValue = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, SrcOrValue);
140 SDValue Ops[] = {Dst, Size, SrcOrValue, Chain};
141 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::Other};
142 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
143 DAG.setNodeMemRefs(Node, {DstOp});
144 return SDValue(Node, 2);
145 } else {
146 SDValue Ops[] = {Dst, SrcOrValue, Size, Chain};
147 const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::i64, MVT::Other};
148 MachineSDNode *Node = DAG.getMachineNode(Opcode, DL, ResultTys, Ops);
149
150 auto SrcFlags = MachineMemOperand::MOLoad | Vol;
151 auto *SrcOp =
152 MF.getMachineMemOperand(SrcPtrInfo, SrcFlags, ConstSize, Alignment);
154 return SDValue(Node, 3);
155 }
156}
157
159 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
160 SDValue Size, RTLIB::Libcall LC) const {
161 const AArch64Subtarget &STI =
163 const AArch64TargetLowering *TLI = STI.getTargetLowering();
165 Args.emplace_back(Dst, PointerType::getUnqual(*DAG.getContext()));
166
167 RTLIB::Libcall NewLC;
168 switch (LC) {
169 case RTLIB::MEMCPY: {
170 NewLC = RTLIB::SC_MEMCPY;
171 Args.emplace_back(Src, PointerType::getUnqual(*DAG.getContext()));
172 break;
173 }
174 case RTLIB::MEMMOVE: {
175 NewLC = RTLIB::SC_MEMMOVE;
176 Args.emplace_back(Src, PointerType::getUnqual(*DAG.getContext()));
177 break;
178 }
179 case RTLIB::MEMSET: {
180 NewLC = RTLIB::SC_MEMSET;
181 Args.emplace_back(DAG.getZExtOrTrunc(Src, DL, MVT::i32),
183 break;
184 }
185 default:
186 return SDValue();
187 }
188
189 EVT PointerVT = TLI->getPointerTy(DAG.getDataLayout());
190 SDValue Symbol = DAG.getExternalSymbol(TLI->getLibcallName(NewLC), PointerVT);
191 Args.emplace_back(Size, DAG.getDataLayout().getIntPtrType(*DAG.getContext()));
192
196 TLI->getLibcallCallingConv(NewLC), RetTy, Symbol, std::move(Args));
197 return TLI->LowerCallTo(CLI).second;
198}
199
201 SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
202 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
203 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
204 const AArch64Subtarget &STI =
206
207 if (STI.hasMOPS())
208 return EmitMOPS(AArch64::MOPSMemoryCopyPseudo, DAG, DL, Chain, Dst, Src,
209 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
210
212 SMEAttrs Attrs = AFI->getSMEFnAttrs();
213 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
214 return EmitStreamingCompatibleMemLibCall(DAG, DL, Chain, Dst, Src, Size,
215 RTLIB::MEMCPY);
216 return SDValue();
217}
218
220 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
221 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
222 MachinePointerInfo DstPtrInfo) const {
223 const AArch64Subtarget &STI =
225
226 if (STI.hasMOPS())
227 return EmitMOPS(AArch64::MOPSMemorySetPseudo, DAG, dl, Chain, Dst, Src,
228 Size, Alignment, isVolatile, DstPtrInfo,
230
232 SMEAttrs Attrs = AFI->getSMEFnAttrs();
233 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
234 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
235 RTLIB::MEMSET);
236 return SDValue();
237}
238
240 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
241 SDValue Size, Align Alignment, bool isVolatile,
242 MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
243 const AArch64Subtarget &STI =
245
246 if (STI.hasMOPS())
247 return EmitMOPS(AArch64::MOPSMemoryMovePseudo, DAG, dl, Chain, Dst, Src,
248 Size, Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
249
251 SMEAttrs Attrs = AFI->getSMEFnAttrs();
252 if (LowerToSMERoutines && !Attrs.hasNonStreamingInterfaceAndBody())
253 return EmitStreamingCompatibleMemLibCall(DAG, dl, Chain, Dst, Src, Size,
254 RTLIB::MEMMOVE);
255 return SDValue();
256}
257
258static const int kSetTagLoopThreshold = 176;
259
261 SDValue Chain, SDValue Ptr, uint64_t ObjSize,
262 const MachineMemOperand *BaseMemOperand,
263 bool ZeroData) {
265 unsigned ObjSizeScaled = ObjSize / 16;
266
267 SDValue TagSrc = Ptr;
268 if (Ptr.getOpcode() == ISD::FrameIndex) {
269 int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
270 Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
271 // A frame index operand may end up as [SP + offset] => it is fine to use SP
272 // register as the tag source.
273 TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
274 }
275
276 const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
277 const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
278
279 SmallVector<SDValue, 8> OutChains;
280 unsigned OffsetScaled = 0;
281 while (OffsetScaled < ObjSizeScaled) {
282 if (ObjSizeScaled - OffsetScaled >= 2) {
283 SDValue AddrNode = DAG.getMemBasePlusOffset(
284 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
286 OpCode2, dl, DAG.getVTList(MVT::Other),
287 {Chain, TagSrc, AddrNode},
288 MVT::v4i64,
289 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
290 OffsetScaled += 2;
291 OutChains.push_back(St);
292 continue;
293 }
294
295 if (ObjSizeScaled - OffsetScaled > 0) {
296 SDValue AddrNode = DAG.getMemBasePlusOffset(
297 Ptr, TypeSize::getFixed(OffsetScaled * 16), dl);
299 OpCode1, dl, DAG.getVTList(MVT::Other),
300 {Chain, TagSrc, AddrNode},
301 MVT::v2i64,
302 MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
303 OffsetScaled += 1;
304 OutChains.push_back(St);
305 }
306 }
307
308 SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
309 return Res;
310}
311
313 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
314 SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
315 uint64_t ObjSize = Size->getAsZExtVal();
316 assert(ObjSize % 16 == 0);
317
319 MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
320 DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
321
322 bool UseSetTagRangeLoop =
323 kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
324 if (!UseSetTagRangeLoop)
325 return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
326 ZeroData);
327
328 const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
329
330 unsigned Opcode;
331 if (Addr.getOpcode() == ISD::FrameIndex) {
332 int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
333 Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
334 Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
335 } else {
336 Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
337 }
338 SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
339 SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
340
341 DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
342 return SDValue(St, 2);
343}
return SDValue()
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
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.
void verifyTargetNode(const SelectionDAG &DAG, const SDNode *N) const override
Checks that the given target-specific node is valid. Aborts if it is not.
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
LLVM_ABI 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.
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.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
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.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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.
unsigned getOpcode() const
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
SelectionDAGGenTargetInfo(const SDNodeInfo &GenNodeInfo)
void verifyTargetNode(const SelectionDAG &DAG, const SDNode *N) const override
Checks that the given target-specific node is valid. Aborts if it is not.
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI 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),...
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
LLVM_ABI 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=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
const DataLayout & getDataLayout() const
SDValue getTargetFrameIndex(int FI, EVT VT)
LLVM_ABI SDValue getMemBasePlusOffset(SDValue Base, TypeSize Offset, const SDLoc &DL, const SDNodeFlags Flags=SDNodeFlags())
Returns sum of the base pointer and offset.
LLVM_ABI SDValue getExternalSymbol(const char *Sym, EVT VT)
LLVM_ABI 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)
MachineFunction & getMachineFunction() const
LLVM_ABI 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
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::vector< ArgListEntry > ArgListTy
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:343
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:296
@ 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:841
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:53
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
#define N
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
ElementCount getVectorElementCount() const
Definition ValueTypes.h:350
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:373
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:168
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:152
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)