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. using namespace llvm;
  18. namespace {
  19. class FusionFeature {
  20. public:
  21. typedef SmallDenseSet<unsigned> FusionOpSet;
  22. enum FusionKind {
  23. #define FUSION_KIND(KIND) FK_##KIND
  24. #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
  25. FUSION_KIND(KIND),
  26. #include "PPCMacroFusion.def"
  27. FUSION_KIND(END)
  28. };
  29. private:
  30. // Each fusion feature is assigned with one fusion kind. All the
  31. // instructions with the same fusion kind have the same fusion characteristic.
  32. FusionKind Kd;
  33. // True if this feature is enabled.
  34. bool Supported;
  35. // li rx, si
  36. // load rt, ra, rx
  37. // The dependent operand index in the second op(load). And the negative means
  38. // it could be any one.
  39. int DepOpIdx;
  40. // The first fusion op set.
  41. FusionOpSet OpSet1;
  42. // The second fusion op set.
  43. FusionOpSet OpSet2;
  44. public:
  45. FusionFeature(FusionKind Kind, bool HasFeature, int Index,
  46. const FusionOpSet &First, const FusionOpSet &Second) :
  47. Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First),
  48. OpSet2(Second) {}
  49. bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
  50. bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
  51. bool isSupported() const { return Supported; }
  52. Optional<unsigned> depOpIdx() const {
  53. if (DepOpIdx < 0)
  54. return None;
  55. return DepOpIdx;
  56. }
  57. FusionKind getKind() const { return Kd; }
  58. };
  59. static bool matchingRegOps(const MachineInstr &FirstMI,
  60. int FirstMIOpIndex,
  61. const MachineInstr &SecondMI,
  62. int SecondMIOpIndex) {
  63. const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
  64. const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
  65. if (!Op1.isReg() || !Op2.isReg())
  66. return false;
  67. return Op1.getReg() == Op2.getReg();
  68. }
  69. static bool matchingImmOps(const MachineInstr &MI,
  70. int MIOpIndex,
  71. int64_t Expect,
  72. unsigned ExtendFrom = 64) {
  73. const MachineOperand &Op = MI.getOperand(MIOpIndex);
  74. if (!Op.isImm())
  75. return false;
  76. int64_t Imm = Op.getImm();
  77. if (ExtendFrom < 64)
  78. Imm = SignExtend64(Imm, ExtendFrom);
  79. return Imm == Expect;
  80. }
  81. // Return true if the FirstMI meets the constraints of SecondMI according to
  82. // fusion specification.
  83. static bool checkOpConstraints(FusionFeature::FusionKind Kd,
  84. const MachineInstr &FirstMI,
  85. const MachineInstr &SecondMI) {
  86. switch (Kd) {
  87. // The hardware didn't require any specific check for the fused instructions'
  88. // operands. Therefore, return true to indicate that, it is fusable.
  89. default: return true;
  90. // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
  91. case FusionFeature::FK_AddiLoad: {
  92. // lxvd2x(ra) cannot be zero
  93. const MachineOperand &RA = SecondMI.getOperand(1);
  94. if (!RA.isReg())
  95. return true;
  96. return Register::isVirtualRegister(RA.getReg()) ||
  97. (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
  98. }
  99. // [addis rt,ra,si - ld rt,ds(ra)] etc.
  100. case FusionFeature::FK_AddisLoad: {
  101. const MachineOperand &RT = SecondMI.getOperand(0);
  102. if (!RT.isReg())
  103. return true;
  104. // Only check it for non-virtual register.
  105. if (!Register::isVirtualRegister(RT.getReg()))
  106. // addis(rt) = ld(ra) = ld(rt)
  107. // ld(rt) cannot be zero
  108. if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
  109. (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
  110. return false;
  111. // addis(si) first 12 bits must be all 1s or all 0s
  112. const MachineOperand &SI = FirstMI.getOperand(2);
  113. if (!SI.isImm())
  114. return true;
  115. int64_t Imm = SI.getImm();
  116. if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
  117. return false;
  118. // If si = 1111111111110000 and the msb of the d/ds field of the load equals
  119. // 1, then fusion does not occur.
  120. if ((Imm & 0xFFF0) == 0xFFF0) {
  121. const MachineOperand &D = SecondMI.getOperand(1);
  122. if (!D.isImm())
  123. return true;
  124. // 14 bit for DS field, while 16 bit for D field.
  125. int MSB = 15;
  126. if (SecondMI.getOpcode() == PPC::LD)
  127. MSB = 13;
  128. return (D.getImm() & (1ULL << MSB)) == 0;
  129. }
  130. return true;
  131. }
  132. case FusionFeature::FK_SldiAdd:
  133. return (matchingImmOps(FirstMI, 2, 3) && matchingImmOps(FirstMI, 3, 60)) ||
  134. (matchingImmOps(FirstMI, 2, 6) && matchingImmOps(FirstMI, 3, 57));
  135. // rldicl rx, ra, 1, 0 - xor
  136. case FusionFeature::FK_RotateLeftXor:
  137. return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 0);
  138. // rldicr rx, ra, 1, 63 - xor
  139. case FusionFeature::FK_RotateRightXor:
  140. return matchingImmOps(FirstMI, 2, 1) && matchingImmOps(FirstMI, 3, 63);
  141. // We actually use CMPW* and CMPD*, 'l' doesn't exist as an operand in instr.
  142. // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpi 0,1,rx,{ 0,1,-1 }
  143. // { lbz,lbzx,lhz,lhzx,lwz,lwzx } - cmpli 0,L,rx,{ 0,1 }
  144. case FusionFeature::FK_LoadCmp1:
  145. // { ld,ldx } - cmpi 0,1,rx,{ 0,1,-1 }
  146. // { ld,ldx } - cmpli 0,1,rx,{ 0,1 }
  147. case FusionFeature::FK_LoadCmp2: {
  148. const MachineOperand &BT = SecondMI.getOperand(0);
  149. if (!BT.isReg() ||
  150. (!Register::isVirtualRegister(BT.getReg()) && BT.getReg() != PPC::CR0))
  151. return false;
  152. if (SecondMI.getOpcode() == PPC::CMPDI &&
  153. matchingImmOps(SecondMI, 2, -1, 16))
  154. return true;
  155. return matchingImmOps(SecondMI, 2, 0) || matchingImmOps(SecondMI, 2, 1);
  156. }
  157. // { lha,lhax,lwa,lwax } - cmpi 0,L,rx,{ 0,1,-1 }
  158. case FusionFeature::FK_LoadCmp3: {
  159. const MachineOperand &BT = SecondMI.getOperand(0);
  160. if (!BT.isReg() ||
  161. (!Register::isVirtualRegister(BT.getReg()) && 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.hasValue()) {
  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