PPCMacroFusion.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //===- PPCMacroFusion.cpp - PowerPC Macro Fusion --------------------------===//
  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. /// \file This file contains the PowerPC implementation of the DAG scheduling
  10. /// mutation to pair instructions back to back.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "PPC.h"
  14. #include "PPCSubtarget.h"
  15. #include "llvm/ADT/DenseSet.h"
  16. #include "llvm/CodeGen/MacroFusion.h"
  17. #include "llvm/CodeGen/ScheduleDAGMutation.h"
  18. #include <optional>
  19. using namespace llvm;
  20. namespace {
  21. class FusionFeature {
  22. public:
  23. typedef SmallDenseSet<unsigned> FusionOpSet;
  24. enum FusionKind {
  25. #define FUSION_KIND(KIND) FK_##KIND
  26. #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
  27. FUSION_KIND(KIND),
  28. #include "PPCMacroFusion.def"
  29. FUSION_KIND(END)
  30. };
  31. private:
  32. // Each fusion feature is assigned with one fusion kind. All the
  33. // instructions with the same fusion kind have the same fusion characteristic.
  34. FusionKind Kd;
  35. // True if this feature is enabled.
  36. bool Supported;
  37. // li rx, si
  38. // load rt, ra, rx
  39. // The dependent operand index in the second op(load). And the negative means
  40. // it could be any one.
  41. int DepOpIdx;
  42. // The first fusion op set.
  43. FusionOpSet OpSet1;
  44. // The second fusion op set.
  45. FusionOpSet OpSet2;
  46. public:
  47. FusionFeature(FusionKind Kind, bool HasFeature, int Index,
  48. const FusionOpSet &First, const FusionOpSet &Second) :
  49. Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First),
  50. OpSet2(Second) {}
  51. bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
  52. bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
  53. bool isSupported() const { return Supported; }
  54. std::optional<unsigned> depOpIdx() const {
  55. if (DepOpIdx < 0)
  56. return std::nullopt;
  57. return DepOpIdx;
  58. }
  59. FusionKind getKind() const { return Kd; }
  60. };
  61. static bool matchingRegOps(const MachineInstr &FirstMI,
  62. int FirstMIOpIndex,
  63. const MachineInstr &SecondMI,
  64. int SecondMIOpIndex) {
  65. const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
  66. const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
  67. if (!Op1.isReg() || !Op2.isReg())
  68. return false;
  69. return Op1.getReg() == Op2.getReg();
  70. }
  71. static bool matchingImmOps(const MachineInstr &MI,
  72. int MIOpIndex,
  73. int64_t Expect,
  74. unsigned ExtendFrom = 64) {
  75. const MachineOperand &Op = MI.getOperand(MIOpIndex);
  76. if (!Op.isImm())
  77. return false;
  78. int64_t Imm = Op.getImm();
  79. if (ExtendFrom < 64)
  80. Imm = SignExtend64(Imm, ExtendFrom);
  81. return Imm == Expect;
  82. }
  83. // Return true if the FirstMI meets the constraints of SecondMI according to
  84. // fusion specification.
  85. static bool checkOpConstraints(FusionFeature::FusionKind Kd,
  86. const MachineInstr &FirstMI,
  87. const MachineInstr &SecondMI) {
  88. switch (Kd) {
  89. // The hardware didn't require any specific check for the fused instructions'
  90. // operands. Therefore, return true to indicate that, it is fusable.
  91. default: return true;
  92. // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
  93. case FusionFeature::FK_AddiLoad: {
  94. // lxvd2x(ra) cannot be zero
  95. const MachineOperand &RA = SecondMI.getOperand(1);
  96. if (!RA.isReg())
  97. return true;
  98. return RA.getReg().isVirtual() ||
  99. (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
  100. }
  101. // [addis rt,ra,si - ld rt,ds(ra)] etc.
  102. case FusionFeature::FK_AddisLoad: {
  103. const MachineOperand &RT = SecondMI.getOperand(0);
  104. if (!RT.isReg())
  105. return true;
  106. // Only check it for non-virtual register.
  107. if (!RT.getReg().isVirtual())
  108. // addis(rt) = ld(ra) = ld(rt)
  109. // ld(rt) cannot be zero
  110. if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
  111. (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
  112. return false;
  113. // addis(si) first 12 bits must be all 1s or all 0s
  114. const MachineOperand &SI = FirstMI.getOperand(2);
  115. if (!SI.isImm())
  116. return true;
  117. int64_t Imm = SI.getImm();
  118. if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
  119. return false;
  120. // If si = 1111111111110000 and the msb of the d/ds field of the load equals
  121. // 1, then fusion does not occur.
  122. if ((Imm & 0xFFF0) == 0xFFF0) {
  123. const MachineOperand &D = SecondMI.getOperand(1);
  124. if (!D.isImm())
  125. return true;
  126. // 14 bit for DS field, while 16 bit for D field.
  127. int MSB = 15;
  128. if (SecondMI.getOpcode() == PPC::LD)
  129. MSB = 13;
  130. return (D.getImm() & (1ULL << MSB)) == 0;
  131. }
  132. return true;
  133. }
  134. case FusionFeature::FK_SldiAdd:
  135. return (matchingImmOps(FirstMI, 2, 3) && matchingImmOps(FirstMI, 3, 60)) ||
  136. (matchingImmOps(FirstMI, 2, 6) && matchingImmOps(FirstMI, 3, 57));
  137. // rldicl rx, ra, 1, 0 - xor
  138. case FusionFeature::FK_RotateLeftXor:
  139. return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 0);
  140. // rldicr rx, ra, 1, 63 - xor
  141. case FusionFeature::FK_RotateRightXor:
  142. return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 63);
  143. // We actually use CMPW* and CMPD*, 'l' doesn't exist as an operand in instr.
  144. // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpi 0,1,rx,{ 0,1,-1 }
  145. // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpli 0,L,rx,{ 0,1 }
  146. case FusionFeature::FK_LoadCmp1:
  147. // { ld,ldx } - cmpi 0,1,rx,{ 0,1,-1 }
  148. // { ld,ldx } - cmpli 0,1,rx,{ 0,1 }
  149. case FusionFeature::FK_LoadCmp2: {
  150. const MachineOperand &BT = SecondMI.getOperand(0);
  151. if (!BT.isReg() || (!BT.getReg().isVirtual() && BT.getReg() != PPC::CR0))
  152. return false;
  153. if (SecondMI.getOpcode() == PPC::CMPDI &&
  154. matchingImmOps(SecondMI, 2, -1, 16))
  155. return true;
  156. return matchingImmOps(SecondMI, 2, 0) || matchingImmOps(SecondMI, 2, 1);
  157. }
  158. // { lha,lhax,lwa,lwax } - cmpi 0,L,rx,{ 0,1,-1 }
  159. case FusionFeature::FK_LoadCmp3: {
  160. const MachineOperand &BT = SecondMI.getOperand(0);
  161. if (!BT.isReg() || (!BT.getReg().isVirtual() && BT.getReg() != PPC::CR0))
  162. return false;
  163. return matchingImmOps(SecondMI, 2, 0) || matchingImmOps(SecondMI, 2, 1) ||
  164. matchingImmOps(SecondMI, 2, -1, 16);
  165. }
  166. // mtctr - { bcctr,bcctrl }
  167. case FusionFeature::FK_ZeroMoveCTR:
  168. // ( mtctr rx ) is alias of ( mtspr 9, rx )
  169. return (FirstMI.getOpcode() != PPC::MTSPR &&
  170. FirstMI.getOpcode() != PPC::MTSPR8) ||
  171. matchingImmOps(FirstMI, 0, 9);
  172. // mtlr - { bclr,bclrl }
  173. case FusionFeature::FK_ZeroMoveLR:
  174. // ( mtlr rx ) is alias of ( mtspr 8, rx )
  175. return (FirstMI.getOpcode() != PPC::MTSPR &&
  176. FirstMI.getOpcode() != PPC::MTSPR8) ||
  177. matchingImmOps(FirstMI, 0, 8);
  178. // addis rx,ra,si - addi rt,rx,SI, SI >= 0
  179. case FusionFeature::FK_AddisAddi: {
  180. const MachineOperand &RA = FirstMI.getOperand(1);
  181. const MachineOperand &SI = SecondMI.getOperand(2);
  182. if (!SI.isImm() || !RA.isReg())
  183. return false;
  184. if (RA.getReg() == PPC::ZERO || RA.getReg() == PPC::ZERO8)
  185. return false;
  186. return SignExtend64(SI.getImm(), 16) >= 0;
  187. }
  188. // addi rx,ra,si - addis rt,rx,SI, ra > 0, SI >= 2
  189. case FusionFeature::FK_AddiAddis: {
  190. const MachineOperand &RA = FirstMI.getOperand(1);
  191. const MachineOperand &SI = FirstMI.getOperand(2);
  192. if (!SI.isImm() || !RA.isReg())
  193. return false;
  194. if (RA.getReg() == PPC::ZERO || RA.getReg() == PPC::ZERO8)
  195. return false;
  196. int64_t ExtendedSI = SignExtend64(SI.getImm(), 16);
  197. return ExtendedSI >= 2;
  198. }
  199. }
  200. llvm_unreachable("All the cases should have been handled");
  201. return true;
  202. }
  203. /// Check if the instr pair, FirstMI and SecondMI, should be fused together.
  204. /// Given SecondMI, when FirstMI is unspecified, then check if SecondMI may be
  205. /// part of a fused pair at all.
  206. static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
  207. const TargetSubtargetInfo &TSI,
  208. const MachineInstr *FirstMI,
  209. const MachineInstr &SecondMI) {
  210. // We use the PPC namespace to avoid the need to prefix opcodes with PPC:: in
  211. // the def file.
  212. using namespace PPC;
  213. const PPCSubtarget &ST = static_cast<const PPCSubtarget&>(TSI);
  214. static const FusionFeature FusionFeatures[] = {
  215. #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) { \
  216. FusionFeature::FUSION_KIND(KIND), ST.HAS_FEATURE(), DEP_OP_IDX, { OPSET1 },\
  217. { OPSET2 } },
  218. #include "PPCMacroFusion.def"
  219. };
  220. #undef FUSION_KIND
  221. for (auto &Feature : FusionFeatures) {
  222. // Skip if the feature is not supported.
  223. if (!Feature.isSupported())
  224. continue;
  225. // Only when the SecondMI is fusable, we are starting to look for the
  226. // fusable FirstMI.
  227. if (Feature.hasOp2(SecondMI.getOpcode())) {
  228. // If FirstMI == nullptr, that means, we're only checking whether SecondMI
  229. // can be fused at all.
  230. if (!FirstMI)
  231. return true;
  232. // Checking if the FirstMI is fusable with the SecondMI.
  233. if (!Feature.hasOp1(FirstMI->getOpcode()))
  234. continue;
  235. auto DepOpIdx = Feature.depOpIdx();
  236. if (DepOpIdx) {
  237. // Checking if the result of the FirstMI is the desired operand of the
  238. // SecondMI if the DepOpIdx is set. Otherwise, ignore it.
  239. if (!matchingRegOps(*FirstMI, 0, SecondMI, *DepOpIdx))
  240. return false;
  241. }
  242. // Checking more on the instruction operands.
  243. if (checkOpConstraints(Feature.getKind(), *FirstMI, SecondMI))
  244. return true;
  245. }
  246. }
  247. return false;
  248. }
  249. } // end anonymous namespace
  250. namespace llvm {
  251. std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
  252. return createMacroFusionDAGMutation(shouldScheduleAdjacent);
  253. }
  254. } // end namespace llvm