AArch64SelectionDAGInfo.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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, bool AlwaysInline,
  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. return SDValue();
  91. }
  92. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForMemmove(
  93. SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
  94. SDValue Size, Align Alignment, bool isVolatile,
  95. MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
  96. const AArch64Subtarget &STI =
  97. DAG.getMachineFunction().getSubtarget<AArch64Subtarget>();
  98. if (STI.hasMOPS()) {
  99. return EmitMOPS(AArch64ISD::MOPS_MEMMOVE, DAG, dl, Chain, Dst, Src, Size,
  100. Alignment, isVolatile, DstPtrInfo, SrcPtrInfo);
  101. }
  102. return SDValue();
  103. }
  104. static const int kSetTagLoopThreshold = 176;
  105. static SDValue EmitUnrolledSetTag(SelectionDAG &DAG, const SDLoc &dl,
  106. SDValue Chain, SDValue Ptr, uint64_t ObjSize,
  107. const MachineMemOperand *BaseMemOperand,
  108. bool ZeroData) {
  109. MachineFunction &MF = DAG.getMachineFunction();
  110. unsigned ObjSizeScaled = ObjSize / 16;
  111. SDValue TagSrc = Ptr;
  112. if (Ptr.getOpcode() == ISD::FrameIndex) {
  113. int FI = cast<FrameIndexSDNode>(Ptr)->getIndex();
  114. Ptr = DAG.getTargetFrameIndex(FI, MVT::i64);
  115. // A frame index operand may end up as [SP + offset] => it is fine to use SP
  116. // register as the tag source.
  117. TagSrc = DAG.getRegister(AArch64::SP, MVT::i64);
  118. }
  119. const unsigned OpCode1 = ZeroData ? AArch64ISD::STZG : AArch64ISD::STG;
  120. const unsigned OpCode2 = ZeroData ? AArch64ISD::STZ2G : AArch64ISD::ST2G;
  121. SmallVector<SDValue, 8> OutChains;
  122. unsigned OffsetScaled = 0;
  123. while (OffsetScaled < ObjSizeScaled) {
  124. if (ObjSizeScaled - OffsetScaled >= 2) {
  125. SDValue AddrNode =
  126. DAG.getMemBasePlusOffset(Ptr, TypeSize::Fixed(OffsetScaled * 16), dl);
  127. SDValue St = DAG.getMemIntrinsicNode(
  128. OpCode2, dl, DAG.getVTList(MVT::Other),
  129. {Chain, TagSrc, AddrNode},
  130. MVT::v4i64,
  131. MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16 * 2));
  132. OffsetScaled += 2;
  133. OutChains.push_back(St);
  134. continue;
  135. }
  136. if (ObjSizeScaled - OffsetScaled > 0) {
  137. SDValue AddrNode =
  138. DAG.getMemBasePlusOffset(Ptr, TypeSize::Fixed(OffsetScaled * 16), dl);
  139. SDValue St = DAG.getMemIntrinsicNode(
  140. OpCode1, dl, DAG.getVTList(MVT::Other),
  141. {Chain, TagSrc, AddrNode},
  142. MVT::v2i64,
  143. MF.getMachineMemOperand(BaseMemOperand, OffsetScaled * 16, 16));
  144. OffsetScaled += 1;
  145. OutChains.push_back(St);
  146. }
  147. }
  148. SDValue Res = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
  149. return Res;
  150. }
  151. SDValue AArch64SelectionDAGInfo::EmitTargetCodeForSetTag(
  152. SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Addr,
  153. SDValue Size, MachinePointerInfo DstPtrInfo, bool ZeroData) const {
  154. uint64_t ObjSize = cast<ConstantSDNode>(Size)->getZExtValue();
  155. assert(ObjSize % 16 == 0);
  156. MachineFunction &MF = DAG.getMachineFunction();
  157. MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
  158. DstPtrInfo, MachineMemOperand::MOStore, ObjSize, Align(16));
  159. bool UseSetTagRangeLoop =
  160. kSetTagLoopThreshold >= 0 && (int)ObjSize >= kSetTagLoopThreshold;
  161. if (!UseSetTagRangeLoop)
  162. return EmitUnrolledSetTag(DAG, dl, Chain, Addr, ObjSize, BaseMemOperand,
  163. ZeroData);
  164. const EVT ResTys[] = {MVT::i64, MVT::i64, MVT::Other};
  165. unsigned Opcode;
  166. if (Addr.getOpcode() == ISD::FrameIndex) {
  167. int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
  168. Addr = DAG.getTargetFrameIndex(FI, MVT::i64);
  169. Opcode = ZeroData ? AArch64::STZGloop : AArch64::STGloop;
  170. } else {
  171. Opcode = ZeroData ? AArch64::STZGloop_wback : AArch64::STGloop_wback;
  172. }
  173. SDValue Ops[] = {DAG.getTargetConstant(ObjSize, dl, MVT::i64), Addr, Chain};
  174. SDNode *St = DAG.getMachineNode(Opcode, dl, ResTys, Ops);
  175. DAG.setNodeMemRefs(cast<MachineSDNode>(St), {BaseMemOperand});
  176. return SDValue(St, 2);
  177. }