AArch64SelectionDAGInfo.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #include "AArch64TargetMachine.h"
  13. using namespace llvm;
  14. #define DEBUG_TYPE "aarch64-selectiondag-info"
  15. SDValue AArch64SelectionDAGInfo::EmitMOPS(AArch64ISD::NodeType SDOpcode,
  16. SelectionDAG &DAG, const SDLoc &DL,
  17. SDValue Chain, SDValue Dst,
  18. SDValue SrcOrValue, SDValue Size,
  19. Align Alignment, bool isVolatile,
  20. MachinePointerInfo DstPtrInfo,
  21. MachinePointerInfo SrcPtrInfo) const {
  22. // Get the constant size of the copy/set.
  23. uint64_t ConstSize = 0;
  24. if (auto *C = dyn_cast<ConstantSDNode>(Size))
  25. ConstSize = C->getZExtValue();
  26. const bool IsSet = SDOpcode == AArch64ISD::MOPS_MEMSET ||
  27. SDOpcode == AArch64ISD::MOPS_MEMSET_TAGGING;
  28. const auto MachineOpcode = [&]() {
  29. switch (SDOpcode) {
  30. case AArch64ISD::MOPS_MEMSET:
  31. return AArch64::MOPSMemorySetPseudo;
  32. case AArch64ISD::MOPS_MEMSET_TAGGING:
  33. return AArch64::MOPSMemorySetTaggingPseudo;
  34. case AArch64ISD::MOPS_MEMCOPY:
  35. return AArch64::MOPSMemoryCopyPseudo;
  36. case AArch64ISD::MOPS_MEMMOVE:
  37. return AArch64::MOPSMemoryMovePseudo;
  38. default:
  39. llvm_unreachable("Unhandled MOPS ISD Opcode");
  40. }
  41. }();
  42. MachineMemOperand::Flags Flags = MachineMemOperand::MOStore;
  43. if (isVolatile)
  44. Flags |= MachineMemOperand::MOVolatile;
  45. if (!IsSet)
  46. Flags |= MachineMemOperand::MOLoad;
  47. MachineFunction &MF = DAG.getMachineFunction();
  48. auto *DstOp =
  49. MF.getMachineMemOperand(DstPtrInfo, Flags, ConstSize, Alignment);
  50. auto *SrcOp =
  51. MF.getMachineMemOperand(SrcPtrInfo, Flags, ConstSize, Alignment);
  52. if (IsSet) {
  53. // Extend value to i64 if required
  54. if (SrcOrValue.getValueType() != MVT::i64)
  55. SrcOrValue = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, SrcOrValue);
  56. SDValue Ops[] = {Dst, Size, SrcOrValue, Chain};
  57. const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::Other};
  58. MachineSDNode *Node = DAG.getMachineNode(MachineOpcode, DL, ResultTys, Ops);
  59. DAG.setNodeMemRefs(Node, {DstOp});
  60. return SDValue(Node, 2);
  61. } else {
  62. SDValue Ops[] = {Dst, SrcOrValue, Size, Chain};
  63. const EVT ResultTys[] = {MVT::i64, MVT::i64, MVT::i64, MVT::Other};
  64. MachineSDNode *Node = DAG.getMachineNode(MachineOpcode, DL, ResultTys, Ops);
  65. DAG.setNodeMemRefs(Node, {DstOp, SrcOp});
  66. return SDValue(Node, 3);
  67. }
  68. }
  69. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemcpy(
  70. SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src,
  71. SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
  72. MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
  73. const AArch64Subtarget &STI =
  74. DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
  75. if (STI.hasMOPS())
  76. return EmitMOPS(AArch64ISD::MOPS_MEMCOPY, DAG, DL, Chain, Dst, Src, Size,
  77. Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
  78. return SDValue();
  79. }
  80. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemset(
  81. SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
  82. SDValue Size, Align Alignment, bool isVolatile,
  83. MachinePointerInfo DstPtrInfo) const {
  84. const AArch64Subtarget &STI =
  85. DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
  86. if (STI.hasMOPS()) {
  87. return EmitMOPS(AArch64ISD::MOPS_MEMSET, DAG, dl, Chain, Dst, Src, Size,
  88. Alignment, isVolatile, DstPtrInfo, MachinePointerInfo{});
  89. }
  90. // Check to see if there is a specialized entry-point for memory zeroing.
  91. ConstantSDNode *V = dyn_cast<ConstantSDNode>(Src);
  92. ConstantSDNode *SizeValue = dyn_cast<ConstantSDNode>(Size);
  93. const char *bzeroName =
  94. (V && V->isZero())
  95. ? DAG.getTargetLoweringInfo().getLibcallName(RTLIB::BZERO)
  96. : nullptr;
  97. // For small size (< 256), it is not beneficial to use bzero
  98. // instead of memset.
  99. if (bzeroName && (!SizeValue || SizeValue->getZExtValue() > 256)) {
  100. const AArch64TargetLowering &TLI = *STI.getTargetLowering();
  101. EVT IntPtr = TLI.getPointerTy(DAG.getDataLayout());
  102. Type *IntPtrTy = Type::getInt8PtrTy(*DAG.getContext());
  103. TargetLowering::ArgListTy Args;
  104. TargetLowering::ArgListEntry Entry;
  105. Entry.Node = Dst;
  106. Entry.Ty = IntPtrTy;
  107. Args.push_back(Entry);
  108. Entry.Node = Size;
  109. Args.push_back(Entry);
  110. TargetLowering::CallLoweringInfo CLI(DAG);
  111. CLI.setDebugLoc(dl)
  112. .setChain(Chain)
  113. .setLibCallee(CallingConv::C, Type::getVoidTy(*DAG.getContext()),
  114. DAG.getExternalSymbol(bzeroName, IntPtr),
  115. std::move(Args))
  116. .setDiscardResult();
  117. std::pair<SDValue, SDValue> CallResult = TLI.LowerCallTo(CLI);
  118. return CallResult.second;
  119. }
  120. return SDValue();
  121. }
  122. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemmove(
  123. SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
  124. SDValue Size, Align Alignment, bool isVolatile,
  125. MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
  126. const AArch64Subtarget &STI =
  127. DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
  128. if (STI.hasMOPS()) {
  129. return EmitMOPS(AArch64ISD::MOPS_MEMMOVE, DAG, dl, Chain, Dst, Src, Size,
  130. Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
  131. }
  132. return SDValue();
  133. }
  134. static const int kSetTagLoopThreshold = 176;
  135. static SDValue EmitUnrolledSetTag(SelectionDAG &DAG, const SDLoc &dl,
  136. SDValue Chain, SDValue Ptr, uint64_t ObjSize,
  137. const MachineMemOperand *BaseMemOperand,
  138. bool ZeroData) {
  139. MachineFunction &MF = DAG.getMachineFunction();
  140. unsigned ObjSizeScaled = ObjSize / 16;
  141. SDValue TagSrc = Ptr;
  142. if (Ptr.getOpcode() == ISD::FrameIndex) {
  143. int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
  144. Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
  145. // A frame index operand may end up as [SP + offset] => it is fine to use SP
  146. // register as the tag source.
  147. TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
  148. }
  149. const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
  150. const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
  151. SmallVector<SDValue, 8> OutChains;
  152. unsigned OffsetScaled = 0;
  153. while (OffsetScaled < ObjSizeScaled) {
  154. if (ObjSizeScaled - OffsetScaled >= 2) {
  155. SDValue AddrNode =
  156. DAG.getMemBasePlusOffset(Ptr, TypeSize::Fixed(OffsetScaled * 16), dl);
  157. SDValue St = DAG.getMemIntrinsicNode(
  158. OpCode2, dl, DAG.getVTList(MVT::Other),
  159. {Chain, TagSrc, AddrNode},
  160. MVT::v4i64,
  161. MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
  162. OffsetScaled += 2;
  163. OutChains.push_back(St);
  164. continue;
  165. }
  166. if (ObjSizeScaled - OffsetScaled > 0) {
  167. SDValue AddrNode =
  168. DAG.getMemBasePlusOffset(Ptr, TypeSize::Fixed(OffsetScaled * 16), dl);
  169. SDValue St = DAG.getMemIntrinsicNode(
  170. OpCode1, dl, DAG.getVTList(MVT::Other),
  171. {Chain, TagSrc, AddrNode},
  172. MVT::v2i64,
  173. MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
  174. OffsetScaled += 1;
  175. OutChains.push_back(St);
  176. }
  177. }
  178. SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
  179. return Res;
  180. }
  181. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForSetTag(
  182. SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
  183. SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
  184. uint64_t ObjSize = cast<ConstantSDNode>(Size)->getZExtValue();
  185. assert(ObjSize % 16 == 0);
  186. MachineFunction &MF = DAG.getMachineFunction();
  187. MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
  188. DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
  189. bool UseSetTagRangeLoop =
  190. kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
  191. if (!UseSetTagRangeLoop)
  192. return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
  193. ZeroData);
  194. const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
  195. unsigned Opcode;
  196. if (Addr.getOpcode() == ISD::FrameIndex) {
  197. int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
  198. Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
  199. Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
  200. } else {
  201. Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
  202. }
  203. SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
  204. SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
  205. DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
  206. return SDValue(St, 2);
  207. }