AArch64CondBrTuning.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. //===-- AArch64CondBrTuning.cpp --- Conditional branch tuning for AArch64 -===//
  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
  9. /// This file contains a pass that transforms CBZ/CBNZ/TBZ/TBNZ instructions
  10. /// into a conditional branch (B.cond), when the NZCV flags can be set for
  11. /// "free". This is preferred on targets that have more flexibility when
  12. /// scheduling B.cond instructions as compared to CBZ/CBNZ/TBZ/TBNZ (assuming
  13. /// all other variables are equal). This can also reduce register pressure.
  14. ///
  15. /// A few examples:
  16. ///
  17. /// 1) add w8, w0, w1 -> cmn w0, w1 ; CMN is an alias of ADDS.
  18. /// cbz w8, .LBB_2 -> b.eq .LBB0_2
  19. ///
  20. /// 2) add w8, w0, w1 -> adds w8, w0, w1 ; w8 has multiple uses.
  21. /// cbz w8, .LBB1_2 -> b.eq .LBB1_2
  22. ///
  23. /// 3) sub w8, w0, w1 -> subs w8, w0, w1 ; w8 has multiple uses.
  24. /// tbz w8, #31, .LBB6_2 -> b.pl .LBB6_2
  25. ///
  26. //===----------------------------------------------------------------------===//
  27. #include "AArch64.h"
  28. #include "AArch64Subtarget.h"
  29. #include "llvm/CodeGen/MachineFunction.h"
  30. #include "llvm/CodeGen/MachineFunctionPass.h"
  31. #include "llvm/CodeGen/MachineInstrBuilder.h"
  32. #include "llvm/CodeGen/MachineRegisterInfo.h"
  33. #include "llvm/CodeGen/Passes.h"
  34. #include "llvm/CodeGen/TargetInstrInfo.h"
  35. #include "llvm/CodeGen/TargetRegisterInfo.h"
  36. #include "llvm/CodeGen/TargetSubtargetInfo.h"
  37. #include "llvm/Support/Debug.h"
  38. #include "llvm/Support/raw_ostream.h"
  39. using namespace llvm;
  40. #define DEBUG_TYPE "aarch64-cond-br-tuning"
  41. #define AARCH64_CONDBR_TUNING_NAME "AArch64 Conditional Branch Tuning"
  42. namespace {
  43. class AArch64CondBrTuning : public MachineFunctionPass {
  44. const AArch64InstrInfo *TII;
  45. const TargetRegisterInfo *TRI;
  46. MachineRegisterInfo *MRI;
  47. public:
  48. static char ID;
  49. AArch64CondBrTuning() : MachineFunctionPass(ID) {
  50. initializeAArch64CondBrTuningPass(*PassRegistry::getPassRegistry());
  51. }
  52. void getAnalysisUsage(AnalysisUsage &AU) const override;
  53. bool runOnMachineFunction(MachineFunction &MF) override;
  54. StringRef getPassName() const override { return AARCH64_CONDBR_TUNING_NAME; }
  55. private:
  56. MachineInstr *getOperandDef(const MachineOperand &MO);
  57. MachineInstr *convertToFlagSetting(MachineInstr &MI, bool IsFlagSetting);
  58. MachineInstr *convertToCondBr(MachineInstr &MI);
  59. bool tryToTuneBranch(MachineInstr &MI, MachineInstr &DefMI);
  60. };
  61. } // end anonymous namespace
  62. char AArch64CondBrTuning::ID = 0;
  63. INITIALIZE_PASS(AArch64CondBrTuning, "aarch64-cond-br-tuning",
  64. AARCH64_CONDBR_TUNING_NAME, false, false)
  65. void AArch64CondBrTuning::getAnalysisUsage(AnalysisUsage &AU) const {
  66. AU.setPreservesCFG();
  67. MachineFunctionPass::getAnalysisUsage(AU);
  68. }
  69. MachineInstr *AArch64CondBrTuning::getOperandDef(const MachineOperand &MO) {
  70. if (!Register::isVirtualRegister(MO.getReg()))
  71. return nullptr;
  72. return MRI->getUniqueVRegDef(MO.getReg());
  73. }
  74. MachineInstr *AArch64CondBrTuning::convertToFlagSetting(MachineInstr &MI,
  75. bool IsFlagSetting) {
  76. // If this is already the flag setting version of the instruction (e.g., SUBS)
  77. // just make sure the implicit-def of NZCV isn't marked dead.
  78. if (IsFlagSetting) {
  79. for (MachineOperand &MO : MI.implicit_operands())
  80. if (MO.isReg() && MO.isDead() && MO.getReg() == AArch64::NZCV)
  81. MO.setIsDead(false);
  82. return &MI;
  83. }
  84. bool Is64Bit;
  85. unsigned NewOpc = TII->convertToFlagSettingOpc(MI.getOpcode(), Is64Bit);
  86. Register NewDestReg = MI.getOperand(0).getReg();
  87. if (MRI->hasOneNonDBGUse(MI.getOperand(0).getReg()))
  88. NewDestReg = Is64Bit ? AArch64::XZR : AArch64::WZR;
  89. MachineInstrBuilder MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
  90. TII->get(NewOpc), NewDestReg);
  91. for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
  92. MIB.add(MO);
  93. return MIB;
  94. }
  95. MachineInstr *AArch64CondBrTuning::convertToCondBr(MachineInstr &MI) {
  96. AArch64CC::CondCode CC;
  97. MachineBasicBlock *TargetMBB = TII->getBranchDestBlock(MI);
  98. switch (MI.getOpcode()) {
  99. default:
  100. llvm_unreachable("Unexpected opcode!");
  101. case AArch64::CBZW:
  102. case AArch64::CBZX:
  103. CC = AArch64CC::EQ;
  104. break;
  105. case AArch64::CBNZW:
  106. case AArch64::CBNZX:
  107. CC = AArch64CC::NE;
  108. break;
  109. case AArch64::TBZW:
  110. case AArch64::TBZX:
  111. CC = AArch64CC::PL;
  112. break;
  113. case AArch64::TBNZW:
  114. case AArch64::TBNZX:
  115. CC = AArch64CC::MI;
  116. break;
  117. }
  118. return BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::Bcc))
  119. .addImm(CC)
  120. .addMBB(TargetMBB);
  121. }
  122. bool AArch64CondBrTuning::tryToTuneBranch(MachineInstr &MI,
  123. MachineInstr &DefMI) {
  124. // We don't want NZCV bits live across blocks.
  125. if (MI.getParent() != DefMI.getParent())
  126. return false;
  127. bool IsFlagSetting = true;
  128. unsigned MIOpc = MI.getOpcode();
  129. MachineInstr *NewCmp = nullptr, *NewBr = nullptr;
  130. switch (DefMI.getOpcode()) {
  131. default:
  132. return false;
  133. case AArch64::ADDWri:
  134. case AArch64::ADDWrr:
  135. case AArch64::ADDWrs:
  136. case AArch64::ADDWrx:
  137. case AArch64::ANDWri:
  138. case AArch64::ANDWrr:
  139. case AArch64::ANDWrs:
  140. case AArch64::BICWrr:
  141. case AArch64::BICWrs:
  142. case AArch64::SUBWri:
  143. case AArch64::SUBWrr:
  144. case AArch64::SUBWrs:
  145. case AArch64::SUBWrx:
  146. IsFlagSetting = false;
  147. LLVM_FALLTHROUGH;
  148. case AArch64::ADDSWri:
  149. case AArch64::ADDSWrr:
  150. case AArch64::ADDSWrs:
  151. case AArch64::ADDSWrx:
  152. case AArch64::ANDSWri:
  153. case AArch64::ANDSWrr:
  154. case AArch64::ANDSWrs:
  155. case AArch64::BICSWrr:
  156. case AArch64::BICSWrs:
  157. case AArch64::SUBSWri:
  158. case AArch64::SUBSWrr:
  159. case AArch64::SUBSWrs:
  160. case AArch64::SUBSWrx:
  161. switch (MIOpc) {
  162. default:
  163. llvm_unreachable("Unexpected opcode!");
  164. case AArch64::CBZW:
  165. case AArch64::CBNZW:
  166. case AArch64::TBZW:
  167. case AArch64::TBNZW:
  168. // Check to see if the TBZ/TBNZ is checking the sign bit.
  169. if ((MIOpc == AArch64::TBZW || MIOpc == AArch64::TBNZW) &&
  170. MI.getOperand(1).getImm() != 31)
  171. return false;
  172. // There must not be any instruction between DefMI and MI that clobbers or
  173. // reads NZCV.
  174. if (isNZCVTouchedInInstructionRange(DefMI, MI, TRI))
  175. return false;
  176. LLVM_DEBUG(dbgs() << " Replacing instructions:\n ");
  177. LLVM_DEBUG(DefMI.print(dbgs()));
  178. LLVM_DEBUG(dbgs() << " ");
  179. LLVM_DEBUG(MI.print(dbgs()));
  180. NewCmp = convertToFlagSetting(DefMI, IsFlagSetting);
  181. NewBr = convertToCondBr(MI);
  182. break;
  183. }
  184. break;
  185. case AArch64::ADDXri:
  186. case AArch64::ADDXrr:
  187. case AArch64::ADDXrs:
  188. case AArch64::ADDXrx:
  189. case AArch64::ANDXri:
  190. case AArch64::ANDXrr:
  191. case AArch64::ANDXrs:
  192. case AArch64::BICXrr:
  193. case AArch64::BICXrs:
  194. case AArch64::SUBXri:
  195. case AArch64::SUBXrr:
  196. case AArch64::SUBXrs:
  197. case AArch64::SUBXrx:
  198. IsFlagSetting = false;
  199. LLVM_FALLTHROUGH;
  200. case AArch64::ADDSXri:
  201. case AArch64::ADDSXrr:
  202. case AArch64::ADDSXrs:
  203. case AArch64::ADDSXrx:
  204. case AArch64::ANDSXri:
  205. case AArch64::ANDSXrr:
  206. case AArch64::ANDSXrs:
  207. case AArch64::BICSXrr:
  208. case AArch64::BICSXrs:
  209. case AArch64::SUBSXri:
  210. case AArch64::SUBSXrr:
  211. case AArch64::SUBSXrs:
  212. case AArch64::SUBSXrx:
  213. switch (MIOpc) {
  214. default:
  215. llvm_unreachable("Unexpected opcode!");
  216. case AArch64::CBZX:
  217. case AArch64::CBNZX:
  218. case AArch64::TBZX:
  219. case AArch64::TBNZX: {
  220. // Check to see if the TBZ/TBNZ is checking the sign bit.
  221. if ((MIOpc == AArch64::TBZX || MIOpc == AArch64::TBNZX) &&
  222. MI.getOperand(1).getImm() != 63)
  223. return false;
  224. // There must not be any instruction between DefMI and MI that clobbers or
  225. // reads NZCV.
  226. if (isNZCVTouchedInInstructionRange(DefMI, MI, TRI))
  227. return false;
  228. LLVM_DEBUG(dbgs() << " Replacing instructions:\n ");
  229. LLVM_DEBUG(DefMI.print(dbgs()));
  230. LLVM_DEBUG(dbgs() << " ");
  231. LLVM_DEBUG(MI.print(dbgs()));
  232. NewCmp = convertToFlagSetting(DefMI, IsFlagSetting);
  233. NewBr = convertToCondBr(MI);
  234. break;
  235. }
  236. }
  237. break;
  238. }
  239. (void)NewCmp; (void)NewBr;
  240. assert(NewCmp && NewBr && "Expected new instructions.");
  241. LLVM_DEBUG(dbgs() << " with instruction:\n ");
  242. LLVM_DEBUG(NewCmp->print(dbgs()));
  243. LLVM_DEBUG(dbgs() << " ");
  244. LLVM_DEBUG(NewBr->print(dbgs()));
  245. // If this was a flag setting version of the instruction, we use the original
  246. // instruction by just clearing the dead marked on the implicit-def of NCZV.
  247. // Therefore, we should not erase this instruction.
  248. if (!IsFlagSetting)
  249. DefMI.eraseFromParent();
  250. MI.eraseFromParent();
  251. return true;
  252. }
  253. bool AArch64CondBrTuning::runOnMachineFunction(MachineFunction &MF) {
  254. if (skipFunction(MF.getFunction()))
  255. return false;
  256. LLVM_DEBUG(
  257. dbgs() << "********** AArch64 Conditional Branch Tuning **********\n"
  258. << "********** Function: " << MF.getName() << '\n');
  259. TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
  260. TRI = MF.getSubtarget().getRegisterInfo();
  261. MRI = &MF.getRegInfo();
  262. bool Changed = false;
  263. for (MachineBasicBlock &MBB : MF) {
  264. bool LocalChange = false;
  265. for (MachineInstr &MI : MBB.terminators()) {
  266. switch (MI.getOpcode()) {
  267. default:
  268. break;
  269. case AArch64::CBZW:
  270. case AArch64::CBZX:
  271. case AArch64::CBNZW:
  272. case AArch64::CBNZX:
  273. case AArch64::TBZW:
  274. case AArch64::TBZX:
  275. case AArch64::TBNZW:
  276. case AArch64::TBNZX:
  277. MachineInstr *DefMI = getOperandDef(MI.getOperand(0));
  278. LocalChange = (DefMI && tryToTuneBranch(MI, *DefMI));
  279. break;
  280. }
  281. // If the optimization was successful, we can't optimize any other
  282. // branches because doing so would clobber the NZCV flags.
  283. if (LocalChange) {
  284. Changed = true;
  285. break;
  286. }
  287. }
  288. }
  289. return Changed;
  290. }
  291. FunctionPass *llvm::createAArch64CondBrTuning() {
  292. return new AArch64CondBrTuning();
  293. }