1 //===-- AArch64SelectionDAGInfo.cpp - AArch64 SelectionDAG Info -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the AArch64SelectionDAGInfo class.
11 //===----------------------------------------------------------------------===//
13 #include "AArch64TargetMachine.h"
16 #define DEBUG_TYPE "aarch64-selectiondag-info"
18 SDValue
AArch64SelectionDAGInfo::EmitTargetCodeForMemset(
19 SelectionDAG
&DAG
, const SDLoc
&dl
, SDValue Chain
, SDValue Dst
, SDValue Src
,
20 SDValue Size
, unsigned Align
, bool isVolatile
,
21 MachinePointerInfo DstPtrInfo
) const {
22 // Check to see if there is a specialized entry-point for memory zeroing.
23 ConstantSDNode
*V
= dyn_cast
<ConstantSDNode
>(Src
);
24 ConstantSDNode
*SizeValue
= dyn_cast
<ConstantSDNode
>(Size
);
25 const AArch64Subtarget
&STI
=
26 DAG
.getMachineFunction().getSubtarget
<AArch64Subtarget
>();
27 const char *bzeroName
= (V
&& V
->isNullValue())
28 ? DAG
.getTargetLoweringInfo().getLibcallName(RTLIB::BZERO
) : nullptr;
29 // For small size (< 256), it is not beneficial to use bzero
31 if (bzeroName
&& (!SizeValue
|| SizeValue
->getZExtValue() > 256)) {
32 const AArch64TargetLowering
&TLI
= *STI
.getTargetLowering();
34 EVT IntPtr
= TLI
.getPointerTy(DAG
.getDataLayout());
35 Type
*IntPtrTy
= Type::getInt8PtrTy(*DAG
.getContext());
36 TargetLowering::ArgListTy Args
;
37 TargetLowering::ArgListEntry Entry
;
40 Args
.push_back(Entry
);
42 Args
.push_back(Entry
);
43 TargetLowering::CallLoweringInfo
CLI(DAG
);
46 .setLibCallee(CallingConv::C
, Type::getVoidTy(*DAG
.getContext()),
47 DAG
.getExternalSymbol(bzeroName
, IntPtr
),
50 std::pair
<SDValue
, SDValue
> CallResult
= TLI
.LowerCallTo(CLI
);
51 return CallResult
.second
;
55 bool AArch64SelectionDAGInfo::generateFMAsInMachineCombiner(
56 CodeGenOpt::Level OptLevel
) const {
57 return OptLevel
>= CodeGenOpt::Aggressive
;
60 static const int kSetTagLoopThreshold
= 176;
62 static SDValue
EmitUnrolledSetTag(SelectionDAG
&DAG
, const SDLoc
&dl
,
63 SDValue Chain
, SDValue Ptr
, uint64_t ObjSize
,
64 const MachineMemOperand
*BaseMemOperand
,
66 MachineFunction
&MF
= DAG
.getMachineFunction();
67 unsigned ObjSizeScaled
= ObjSize
/ 16;
70 if (Ptr
.getOpcode() == ISD::FrameIndex
) {
71 int FI
= cast
<FrameIndexSDNode
>(Ptr
)->getIndex();
72 Ptr
= DAG
.getTargetFrameIndex(FI
, MVT::i64
);
73 // A frame index operand may end up as [SP + offset] => it is fine to use SP
74 // register as the tag source.
75 TagSrc
= DAG
.getRegister(AArch64::SP
, MVT::i64
);
78 const unsigned OpCode1
= ZeroData
? AArch64ISD::STZG
: AArch64ISD::STG
;
79 const unsigned OpCode2
= ZeroData
? AArch64ISD::STZ2G
: AArch64ISD::ST2G
;
81 SmallVector
<SDValue
, 8> OutChains
;
82 unsigned OffsetScaled
= 0;
83 while (OffsetScaled
< ObjSizeScaled
) {
84 if (ObjSizeScaled
- OffsetScaled
>= 2) {
85 SDValue AddrNode
= DAG
.getMemBasePlusOffset(Ptr
, OffsetScaled
* 16, dl
);
86 SDValue St
= DAG
.getMemIntrinsicNode(
87 OpCode2
, dl
, DAG
.getVTList(MVT::Other
),
88 {Chain
, TagSrc
, AddrNode
},
90 MF
.getMachineMemOperand(BaseMemOperand
, OffsetScaled
* 16, 16 * 2));
92 OutChains
.push_back(St
);
96 if (ObjSizeScaled
- OffsetScaled
> 0) {
97 SDValue AddrNode
= DAG
.getMemBasePlusOffset(Ptr
, OffsetScaled
* 16, dl
);
98 SDValue St
= DAG
.getMemIntrinsicNode(
99 OpCode1
, dl
, DAG
.getVTList(MVT::Other
),
100 {Chain
, TagSrc
, AddrNode
},
102 MF
.getMachineMemOperand(BaseMemOperand
, OffsetScaled
* 16, 16));
104 OutChains
.push_back(St
);
108 SDValue Res
= DAG
.getNode(ISD::TokenFactor
, dl
, MVT::Other
, OutChains
);
112 SDValue
AArch64SelectionDAGInfo::EmitTargetCodeForSetTag(
113 SelectionDAG
&DAG
, const SDLoc
&dl
, SDValue Chain
, SDValue Addr
,
114 SDValue Size
, MachinePointerInfo DstPtrInfo
, bool ZeroData
) const {
115 uint64_t ObjSize
= cast
<ConstantSDNode
>(Size
)->getZExtValue();
116 assert(ObjSize
% 16 == 0);
118 MachineFunction
&MF
= DAG
.getMachineFunction();
119 MachineMemOperand
*BaseMemOperand
= MF
.getMachineMemOperand(
120 DstPtrInfo
, MachineMemOperand::MOStore
, ObjSize
, 16);
122 bool UseSetTagRangeLoop
=
123 kSetTagLoopThreshold
>= 0 && (int)ObjSize
>= kSetTagLoopThreshold
;
124 if (!UseSetTagRangeLoop
)
125 return EmitUnrolledSetTag(DAG
, dl
, Chain
, Addr
, ObjSize
, BaseMemOperand
,
128 if (ObjSize
% 32 != 0) {
129 SDNode
*St1
= DAG
.getMachineNode(
130 ZeroData
? AArch64::STZGPostIndex
: AArch64::STGPostIndex
, dl
,
131 {MVT::i64
, MVT::Other
},
132 {Addr
, Addr
, DAG
.getTargetConstant(1, dl
, MVT::i64
), Chain
});
133 DAG
.setNodeMemRefs(cast
<MachineSDNode
>(St1
), {BaseMemOperand
});
135 Addr
= SDValue(St1
, 0);
136 Chain
= SDValue(St1
, 1);
139 const EVT ResTys
[] = {MVT::i64
, MVT::i64
, MVT::Other
};
140 SDValue Ops
[] = {DAG
.getConstant(ObjSize
, dl
, MVT::i64
), Addr
, Chain
};
141 SDNode
*St
= DAG
.getMachineNode(
142 ZeroData
? AArch64::STZGloop
: AArch64::STGloop
, dl
, ResTys
, Ops
);
144 DAG
.setNodeMemRefs(cast
<MachineSDNode
>(St
), {BaseMemOperand
});
145 return SDValue(St
, 2);