AArch64MacroFusion.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. //===- AArch64MacroFusion.cpp - AArch64 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 AArch64 implementation of the DAG scheduling
  10. /// mutation to pair instructions back to back.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "AArch64MacroFusion.h"
  14. #include "AArch64Subtarget.h"
  15. #include "llvm/CodeGen/MacroFusion.h"
  16. #include "llvm/CodeGen/TargetInstrInfo.h"
  17. using namespace llvm;
  18. /// CMN, CMP, TST followed by Bcc
  19. static bool isArithmeticBccPair(const MachineInstr *FirstMI,
  20. const MachineInstr &SecondMI, bool CmpOnly) {
  21. if (SecondMI.getOpcode() != AArch64::Bcc)
  22. return false;
  23. // Assume the 1st instr to be a wildcard if it is unspecified.
  24. if (FirstMI == nullptr)
  25. return true;
  26. // If we're in CmpOnly mode, we only fuse arithmetic instructions that
  27. // discard their result.
  28. if (CmpOnly && FirstMI->getOperand(0).isReg() &&
  29. !(FirstMI->getOperand(0).getReg() == AArch64::XZR ||
  30. FirstMI->getOperand(0).getReg() == AArch64::WZR)) {
  31. return false;
  32. }
  33. switch (FirstMI->getOpcode()) {
  34. case AArch64::ADDSWri:
  35. case AArch64::ADDSWrr:
  36. case AArch64::ADDSXri:
  37. case AArch64::ADDSXrr:
  38. case AArch64::ANDSWri:
  39. case AArch64::ANDSWrr:
  40. case AArch64::ANDSXri:
  41. case AArch64::ANDSXrr:
  42. case AArch64::SUBSWri:
  43. case AArch64::SUBSWrr:
  44. case AArch64::SUBSXri:
  45. case AArch64::SUBSXrr:
  46. case AArch64::BICSWrr:
  47. case AArch64::BICSXrr:
  48. return true;
  49. case AArch64::ADDSWrs:
  50. case AArch64::ADDSXrs:
  51. case AArch64::ANDSWrs:
  52. case AArch64::ANDSXrs:
  53. case AArch64::SUBSWrs:
  54. case AArch64::SUBSXrs:
  55. case AArch64::BICSWrs:
  56. case AArch64::BICSXrs:
  57. // Shift value can be 0 making these behave like the "rr" variant...
  58. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  59. }
  60. return false;
  61. }
  62. /// ALU operations followed by CBZ/CBNZ.
  63. static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
  64. const MachineInstr &SecondMI) {
  65. if (SecondMI.getOpcode() != AArch64::CBZW &&
  66. SecondMI.getOpcode() != AArch64::CBZX &&
  67. SecondMI.getOpcode() != AArch64::CBNZW &&
  68. SecondMI.getOpcode() != AArch64::CBNZX)
  69. return false;
  70. // Assume the 1st instr to be a wildcard if it is unspecified.
  71. if (FirstMI == nullptr)
  72. return true;
  73. switch (FirstMI->getOpcode()) {
  74. case AArch64::ADDWri:
  75. case AArch64::ADDWrr:
  76. case AArch64::ADDXri:
  77. case AArch64::ADDXrr:
  78. case AArch64::ANDWri:
  79. case AArch64::ANDWrr:
  80. case AArch64::ANDXri:
  81. case AArch64::ANDXrr:
  82. case AArch64::EORWri:
  83. case AArch64::EORWrr:
  84. case AArch64::EORXri:
  85. case AArch64::EORXrr:
  86. case AArch64::ORRWri:
  87. case AArch64::ORRWrr:
  88. case AArch64::ORRXri:
  89. case AArch64::ORRXrr:
  90. case AArch64::SUBWri:
  91. case AArch64::SUBWrr:
  92. case AArch64::SUBXri:
  93. case AArch64::SUBXrr:
  94. return true;
  95. case AArch64::ADDWrs:
  96. case AArch64::ADDXrs:
  97. case AArch64::ANDWrs:
  98. case AArch64::ANDXrs:
  99. case AArch64::SUBWrs:
  100. case AArch64::SUBXrs:
  101. case AArch64::BICWrs:
  102. case AArch64::BICXrs:
  103. // Shift value can be 0 making these behave like the "rr" variant...
  104. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  105. }
  106. return false;
  107. }
  108. /// AES crypto encoding or decoding.
  109. static bool isAESPair(const MachineInstr *FirstMI,
  110. const MachineInstr &SecondMI) {
  111. // Assume the 1st instr to be a wildcard if it is unspecified.
  112. switch (SecondMI.getOpcode()) {
  113. // AES encode.
  114. case AArch64::AESMCrr:
  115. case AArch64::AESMCrrTied:
  116. return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESErr;
  117. // AES decode.
  118. case AArch64::AESIMCrr:
  119. case AArch64::AESIMCrrTied:
  120. return FirstMI == nullptr || FirstMI->getOpcode() == AArch64::AESDrr;
  121. }
  122. return false;
  123. }
  124. /// AESE/AESD/PMULL + EOR.
  125. static bool isCryptoEORPair(const MachineInstr *FirstMI,
  126. const MachineInstr &SecondMI) {
  127. if (SecondMI.getOpcode() != AArch64::EORv16i8)
  128. return false;
  129. // Assume the 1st instr to be a wildcard if it is unspecified.
  130. if (FirstMI == nullptr)
  131. return true;
  132. switch (FirstMI->getOpcode()) {
  133. case AArch64::AESErr:
  134. case AArch64::AESDrr:
  135. case AArch64::PMULLv16i8:
  136. case AArch64::PMULLv8i8:
  137. case AArch64::PMULLv1i64:
  138. case AArch64::PMULLv2i64:
  139. return true;
  140. }
  141. return false;
  142. }
  143. static bool isAdrpAddPair(const MachineInstr *FirstMI,
  144. const MachineInstr &SecondMI) {
  145. // Assume the 1st instr to be a wildcard if it is unspecified.
  146. if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&
  147. SecondMI.getOpcode() == AArch64::ADDXri)
  148. return true;
  149. return false;
  150. }
  151. /// Literal generation.
  152. static bool isLiteralsPair(const MachineInstr *FirstMI,
  153. const MachineInstr &SecondMI) {
  154. // Assume the 1st instr to be a wildcard if it is unspecified.
  155. // 32 bit immediate.
  156. if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
  157. (SecondMI.getOpcode() == AArch64::MOVKWi &&
  158. SecondMI.getOperand(3).getImm() == 16))
  159. return true;
  160. // Lower half of 64 bit immediate.
  161. if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
  162. (SecondMI.getOpcode() == AArch64::MOVKXi &&
  163. SecondMI.getOperand(3).getImm() == 16))
  164. return true;
  165. // Upper half of 64 bit immediate.
  166. if ((FirstMI == nullptr ||
  167. (FirstMI->getOpcode() == AArch64::MOVKXi &&
  168. FirstMI->getOperand(3).getImm() == 32)) &&
  169. (SecondMI.getOpcode() == AArch64::MOVKXi &&
  170. SecondMI.getOperand(3).getImm() == 48))
  171. return true;
  172. return false;
  173. }
  174. /// Fuse address generation and loads or stores.
  175. static bool isAddressLdStPair(const MachineInstr *FirstMI,
  176. const MachineInstr &SecondMI) {
  177. switch (SecondMI.getOpcode()) {
  178. case AArch64::STRBBui:
  179. case AArch64::STRBui:
  180. case AArch64::STRDui:
  181. case AArch64::STRHHui:
  182. case AArch64::STRHui:
  183. case AArch64::STRQui:
  184. case AArch64::STRSui:
  185. case AArch64::STRWui:
  186. case AArch64::STRXui:
  187. case AArch64::LDRBBui:
  188. case AArch64::LDRBui:
  189. case AArch64::LDRDui:
  190. case AArch64::LDRHHui:
  191. case AArch64::LDRHui:
  192. case AArch64::LDRQui:
  193. case AArch64::LDRSui:
  194. case AArch64::LDRWui:
  195. case AArch64::LDRXui:
  196. case AArch64::LDRSBWui:
  197. case AArch64::LDRSBXui:
  198. case AArch64::LDRSHWui:
  199. case AArch64::LDRSHXui:
  200. case AArch64::LDRSWui:
  201. // Assume the 1st instr to be a wildcard if it is unspecified.
  202. if (FirstMI == nullptr)
  203. return true;
  204. switch (FirstMI->getOpcode()) {
  205. case AArch64::ADR:
  206. return SecondMI.getOperand(2).getImm() == 0;
  207. case AArch64::ADRP:
  208. return true;
  209. }
  210. }
  211. return false;
  212. }
  213. /// Compare and conditional select.
  214. static bool isCCSelectPair(const MachineInstr *FirstMI,
  215. const MachineInstr &SecondMI) {
  216. // 32 bits
  217. if (SecondMI.getOpcode() == AArch64::CSELWr) {
  218. // Assume the 1st instr to be a wildcard if it is unspecified.
  219. if (FirstMI == nullptr)
  220. return true;
  221. if (FirstMI->definesRegister(AArch64::WZR))
  222. switch (FirstMI->getOpcode()) {
  223. case AArch64::SUBSWrs:
  224. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  225. case AArch64::SUBSWrx:
  226. return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
  227. case AArch64::SUBSWrr:
  228. case AArch64::SUBSWri:
  229. return true;
  230. }
  231. }
  232. // 64 bits
  233. if (SecondMI.getOpcode() == AArch64::CSELXr) {
  234. // Assume the 1st instr to be a wildcard if it is unspecified.
  235. if (FirstMI == nullptr)
  236. return true;
  237. if (FirstMI->definesRegister(AArch64::XZR))
  238. switch (FirstMI->getOpcode()) {
  239. case AArch64::SUBSXrs:
  240. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  241. case AArch64::SUBSXrx:
  242. case AArch64::SUBSXrx64:
  243. return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
  244. case AArch64::SUBSXrr:
  245. case AArch64::SUBSXri:
  246. return true;
  247. }
  248. }
  249. return false;
  250. }
  251. // Arithmetic and logic.
  252. static bool isArithmeticLogicPair(const MachineInstr *FirstMI,
  253. const MachineInstr &SecondMI) {
  254. if (AArch64InstrInfo::hasShiftedReg(SecondMI))
  255. return false;
  256. switch (SecondMI.getOpcode()) {
  257. // Arithmetic
  258. case AArch64::ADDWrr:
  259. case AArch64::ADDXrr:
  260. case AArch64::SUBWrr:
  261. case AArch64::SUBXrr:
  262. case AArch64::ADDWrs:
  263. case AArch64::ADDXrs:
  264. case AArch64::SUBWrs:
  265. case AArch64::SUBXrs:
  266. // Logic
  267. case AArch64::ANDWrr:
  268. case AArch64::ANDXrr:
  269. case AArch64::BICWrr:
  270. case AArch64::BICXrr:
  271. case AArch64::EONWrr:
  272. case AArch64::EONXrr:
  273. case AArch64::EORWrr:
  274. case AArch64::EORXrr:
  275. case AArch64::ORNWrr:
  276. case AArch64::ORNXrr:
  277. case AArch64::ORRWrr:
  278. case AArch64::ORRXrr:
  279. case AArch64::ANDWrs:
  280. case AArch64::ANDXrs:
  281. case AArch64::BICWrs:
  282. case AArch64::BICXrs:
  283. case AArch64::EONWrs:
  284. case AArch64::EONXrs:
  285. case AArch64::EORWrs:
  286. case AArch64::EORXrs:
  287. case AArch64::ORNWrs:
  288. case AArch64::ORNXrs:
  289. case AArch64::ORRWrs:
  290. case AArch64::ORRXrs:
  291. // Assume the 1st instr to be a wildcard if it is unspecified.
  292. if (FirstMI == nullptr)
  293. return true;
  294. // Arithmetic
  295. switch (FirstMI->getOpcode()) {
  296. case AArch64::ADDWrr:
  297. case AArch64::ADDXrr:
  298. case AArch64::ADDSWrr:
  299. case AArch64::ADDSXrr:
  300. case AArch64::SUBWrr:
  301. case AArch64::SUBXrr:
  302. case AArch64::SUBSWrr:
  303. case AArch64::SUBSXrr:
  304. return true;
  305. case AArch64::ADDWrs:
  306. case AArch64::ADDXrs:
  307. case AArch64::ADDSWrs:
  308. case AArch64::ADDSXrs:
  309. case AArch64::SUBWrs:
  310. case AArch64::SUBXrs:
  311. case AArch64::SUBSWrs:
  312. case AArch64::SUBSXrs:
  313. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  314. }
  315. break;
  316. // Arithmetic, setting flags.
  317. case AArch64::ADDSWrr:
  318. case AArch64::ADDSXrr:
  319. case AArch64::SUBSWrr:
  320. case AArch64::SUBSXrr:
  321. case AArch64::ADDSWrs:
  322. case AArch64::ADDSXrs:
  323. case AArch64::SUBSWrs:
  324. case AArch64::SUBSXrs:
  325. // Assume the 1st instr to be a wildcard if it is unspecified.
  326. if (FirstMI == nullptr)
  327. return true;
  328. // Arithmetic, not setting flags.
  329. switch (FirstMI->getOpcode()) {
  330. case AArch64::ADDWrr:
  331. case AArch64::ADDXrr:
  332. case AArch64::SUBWrr:
  333. case AArch64::SUBXrr:
  334. return true;
  335. case AArch64::ADDWrs:
  336. case AArch64::ADDXrs:
  337. case AArch64::SUBWrs:
  338. case AArch64::SUBXrs:
  339. return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
  340. }
  341. break;
  342. }
  343. return false;
  344. }
  345. /// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
  346. /// together. Given SecondMI, when FirstMI is unspecified, then check if
  347. /// SecondMI may be part of a fused pair at all.
  348. static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
  349. const TargetSubtargetInfo &TSI,
  350. const MachineInstr *FirstMI,
  351. const MachineInstr &SecondMI) {
  352. const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
  353. // All checking functions assume that the 1st instr is a wildcard if it is
  354. // unspecified.
  355. if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {
  356. bool CmpOnly = !ST.hasArithmeticBccFusion();
  357. if (isArithmeticBccPair(FirstMI, SecondMI, CmpOnly))
  358. return true;
  359. }
  360. if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI))
  361. return true;
  362. if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
  363. return true;
  364. if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI))
  365. return true;
  366. if (ST.hasFuseAdrpAdd() && isAdrpAddPair(FirstMI, SecondMI))
  367. return true;
  368. if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
  369. return true;
  370. if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))
  371. return true;
  372. if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI))
  373. return true;
  374. if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI))
  375. return true;
  376. return false;
  377. }
  378. std::unique_ptr<ScheduleDAGMutation>
  379. llvm::createAArch64MacroFusionDAGMutation() {
  380. return createMacroFusionDAGMutation(shouldScheduleAdjacent);
  381. }