AArch64GlobalISelUtils.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //===- AArch64GlobalISelUtils.cpp --------------------------------*- C++ -*-==//
  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. /// \file Implementations of AArch64-specific helper functions used in the
  9. /// GlobalISel pipeline.
  10. //===----------------------------------------------------------------------===//
  11. #include "AArch64GlobalISelUtils.h"
  12. #include "AArch64InstrInfo.h"
  13. #include "llvm/CodeGen/GlobalISel/Utils.h"
  14. #include "llvm/CodeGen/TargetLowering.h"
  15. #include "llvm/IR/InstrTypes.h"
  16. #include "llvm/Support/raw_ostream.h"
  17. using namespace llvm;
  18. std::optional<RegOrConstant>
  19. AArch64GISelUtils::getAArch64VectorSplat(const MachineInstr &MI,
  20. const MachineRegisterInfo &MRI) {
  21. if (auto Splat = getVectorSplat(MI, MRI))
  22. return Splat;
  23. if (MI.getOpcode() != AArch64::G_DUP)
  24. return std::nullopt;
  25. Register Src = MI.getOperand(1).getReg();
  26. if (auto ValAndVReg =
  27. getAnyConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI))
  28. return RegOrConstant(ValAndVReg->Value.getSExtValue());
  29. return RegOrConstant(Src);
  30. }
  31. std::optional<int64_t>
  32. AArch64GISelUtils::getAArch64VectorSplatScalar(const MachineInstr &MI,
  33. const MachineRegisterInfo &MRI) {
  34. auto Splat = getAArch64VectorSplat(MI, MRI);
  35. if (!Splat || Splat->isReg())
  36. return std::nullopt;
  37. return Splat->getCst();
  38. }
  39. bool AArch64GISelUtils::isCMN(const MachineInstr *MaybeSub,
  40. const CmpInst::Predicate &Pred,
  41. const MachineRegisterInfo &MRI) {
  42. // Match:
  43. //
  44. // %sub = G_SUB 0, %y
  45. // %cmp = G_ICMP eq/ne, %sub, %z
  46. //
  47. // Or
  48. //
  49. // %sub = G_SUB 0, %y
  50. // %cmp = G_ICMP eq/ne, %z, %sub
  51. if (!MaybeSub || MaybeSub->getOpcode() != TargetOpcode::G_SUB ||
  52. !CmpInst::isEquality(Pred))
  53. return false;
  54. auto MaybeZero =
  55. getIConstantVRegValWithLookThrough(MaybeSub->getOperand(1).getReg(), MRI);
  56. return MaybeZero && MaybeZero->Value.getZExtValue() == 0;
  57. }
  58. bool AArch64GISelUtils::tryEmitBZero(MachineInstr &MI,
  59. MachineIRBuilder &MIRBuilder,
  60. bool MinSize) {
  61. assert(MI.getOpcode() == TargetOpcode::G_MEMSET);
  62. MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
  63. auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
  64. if (!TLI.getLibcallName(RTLIB::BZERO))
  65. return false;
  66. auto Zero =
  67. getIConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI);
  68. if (!Zero || Zero->Value.getSExtValue() != 0)
  69. return false;
  70. // It's not faster to use bzero rather than memset for sizes <= 256.
  71. // However, it *does* save us a mov from wzr, so if we're going for
  72. // minsize, use bzero even if it's slower.
  73. if (!MinSize) {
  74. // If the size is known, check it. If it is not known, assume using bzero is
  75. // better.
  76. if (auto Size = getIConstantVRegValWithLookThrough(
  77. MI.getOperand(2).getReg(), MRI)) {
  78. if (Size->Value.getSExtValue() <= 256)
  79. return false;
  80. }
  81. }
  82. MIRBuilder.setInstrAndDebugLoc(MI);
  83. MIRBuilder
  84. .buildInstr(TargetOpcode::G_BZERO, {},
  85. {MI.getOperand(0), MI.getOperand(2)})
  86. .addImm(MI.getOperand(3).getImm())
  87. .addMemOperand(*MI.memoperands_begin());
  88. MI.eraseFromParent();
  89. return true;
  90. }
  91. void AArch64GISelUtils::changeFCMPPredToAArch64CC(
  92. const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,
  93. AArch64CC::CondCode &CondCode2) {
  94. CondCode2 = AArch64CC::AL;
  95. switch (P) {
  96. default:
  97. llvm_unreachable("Unknown FP condition!");
  98. case CmpInst::FCMP_OEQ:
  99. CondCode = AArch64CC::EQ;
  100. break;
  101. case CmpInst::FCMP_OGT:
  102. CondCode = AArch64CC::GT;
  103. break;
  104. case CmpInst::FCMP_OGE:
  105. CondCode = AArch64CC::GE;
  106. break;
  107. case CmpInst::FCMP_OLT:
  108. CondCode = AArch64CC::MI;
  109. break;
  110. case CmpInst::FCMP_OLE:
  111. CondCode = AArch64CC::LS;
  112. break;
  113. case CmpInst::FCMP_ONE:
  114. CondCode = AArch64CC::MI;
  115. CondCode2 = AArch64CC::GT;
  116. break;
  117. case CmpInst::FCMP_ORD:
  118. CondCode = AArch64CC::VC;
  119. break;
  120. case CmpInst::FCMP_UNO:
  121. CondCode = AArch64CC::VS;
  122. break;
  123. case CmpInst::FCMP_UEQ:
  124. CondCode = AArch64CC::EQ;
  125. CondCode2 = AArch64CC::VS;
  126. break;
  127. case CmpInst::FCMP_UGT:
  128. CondCode = AArch64CC::HI;
  129. break;
  130. case CmpInst::FCMP_UGE:
  131. CondCode = AArch64CC::PL;
  132. break;
  133. case CmpInst::FCMP_ULT:
  134. CondCode = AArch64CC::LT;
  135. break;
  136. case CmpInst::FCMP_ULE:
  137. CondCode = AArch64CC::LE;
  138. break;
  139. case CmpInst::FCMP_UNE:
  140. CondCode = AArch64CC::NE;
  141. break;
  142. }
  143. }
  144. void AArch64GISelUtils::changeVectorFCMPPredToAArch64CC(
  145. const CmpInst::Predicate P, AArch64CC::CondCode &CondCode,
  146. AArch64CC::CondCode &CondCode2, bool &Invert) {
  147. Invert = false;
  148. switch (P) {
  149. default:
  150. // Mostly the scalar mappings work fine.
  151. changeFCMPPredToAArch64CC(P, CondCode, CondCode2);
  152. break;
  153. case CmpInst::FCMP_UNO:
  154. Invert = true;
  155. [[fallthrough]];
  156. case CmpInst::FCMP_ORD:
  157. CondCode = AArch64CC::MI;
  158. CondCode2 = AArch64CC::GE;
  159. break;
  160. case CmpInst::FCMP_UEQ:
  161. case CmpInst::FCMP_ULT:
  162. case CmpInst::FCMP_ULE:
  163. case CmpInst::FCMP_UGT:
  164. case CmpInst::FCMP_UGE:
  165. // All of the compare-mask comparisons are ordered, but we can switch
  166. // between the two by a double inversion. E.g. ULE == !OGT.
  167. Invert = true;
  168. changeFCMPPredToAArch64CC(CmpInst::getInversePredicate(P), CondCode,
  169. CondCode2);
  170. break;
  171. }
  172. }