12d1f6d67SPete Couperus //===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===//
22d1f6d67SPete Couperus //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62d1f6d67SPete Couperus //
72d1f6d67SPete Couperus //===----------------------------------------------------------------------===//
82d1f6d67SPete Couperus //
92d1f6d67SPete Couperus // This pass takes existing conditional branches and expands them into longer
102d1f6d67SPete Couperus // range conditional branches.
112d1f6d67SPete Couperus //===----------------------------------------------------------------------===//
122d1f6d67SPete Couperus 
132d1f6d67SPete Couperus #include "ARCInstrInfo.h"
142d1f6d67SPete Couperus #include "ARCTargetMachine.h"
152d1f6d67SPete Couperus #include "MCTargetDesc/ARCInfo.h"
162d1f6d67SPete Couperus #include "llvm/CodeGen/MachineFunctionPass.h"
172d1f6d67SPete Couperus #include "llvm/CodeGen/MachineInstrBuilder.h"
182d1f6d67SPete Couperus #include "llvm/CodeGen/MachineRegisterInfo.h"
192d1f6d67SPete Couperus #include "llvm/CodeGen/Passes.h"
203f833edcSDavid Blaikie #include "llvm/CodeGen/TargetInstrInfo.h"
2185435bddSPete Couperus #include "llvm/InitializePasses.h"
222d1f6d67SPete Couperus #include "llvm/Support/Debug.h"
232d1f6d67SPete Couperus #include <vector>
242d1f6d67SPete Couperus 
25*71acce68SMindong Chen #define DEBUG_TYPE "arc-branch-finalize"
26*71acce68SMindong Chen 
272d1f6d67SPete Couperus using namespace llvm;
282d1f6d67SPete Couperus 
292d1f6d67SPete Couperus namespace llvm {
302d1f6d67SPete Couperus 
312d1f6d67SPete Couperus void initializeARCBranchFinalizePass(PassRegistry &Registry);
322d1f6d67SPete Couperus FunctionPass *createARCBranchFinalizePass();
332d1f6d67SPete Couperus 
342d1f6d67SPete Couperus } // end namespace llvm
352d1f6d67SPete Couperus 
362d1f6d67SPete Couperus namespace {
372d1f6d67SPete Couperus 
382d1f6d67SPete Couperus class ARCBranchFinalize : public MachineFunctionPass {
392d1f6d67SPete Couperus public:
402d1f6d67SPete Couperus   static char ID;
412d1f6d67SPete Couperus 
ARCBranchFinalize()422d1f6d67SPete Couperus   ARCBranchFinalize() : MachineFunctionPass(ID) {
432d1f6d67SPete Couperus     initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry());
442d1f6d67SPete Couperus   }
452d1f6d67SPete Couperus 
getPassName() const462d1f6d67SPete Couperus   StringRef getPassName() const override {
472d1f6d67SPete Couperus     return "ARC Branch Finalization Pass";
482d1f6d67SPete Couperus   }
492d1f6d67SPete Couperus 
502d1f6d67SPete Couperus   bool runOnMachineFunction(MachineFunction &MF) override;
512d1f6d67SPete Couperus   void replaceWithBRcc(MachineInstr *MI) const;
522d1f6d67SPete Couperus   void replaceWithCmpBcc(MachineInstr *MI) const;
532d1f6d67SPete Couperus 
542d1f6d67SPete Couperus private:
552d1f6d67SPete Couperus   const ARCInstrInfo *TII{nullptr};
562d1f6d67SPete Couperus };
572d1f6d67SPete Couperus 
582d1f6d67SPete Couperus char ARCBranchFinalize::ID = 0;
592d1f6d67SPete Couperus 
602d1f6d67SPete Couperus } // end anonymous namespace
612d1f6d67SPete Couperus 
622d1f6d67SPete Couperus INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize",
632d1f6d67SPete Couperus                       "ARC finalize branches", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)642d1f6d67SPete Couperus INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
652d1f6d67SPete Couperus INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize",
662d1f6d67SPete Couperus                     "ARC finalize branches", false, false)
672d1f6d67SPete Couperus 
682d1f6d67SPete Couperus // BRcc has 6 supported condition codes, which differ from the 16
692d1f6d67SPete Couperus // condition codes supported in the predicated instructions:
702d1f6d67SPete Couperus // EQ -- 000
712d1f6d67SPete Couperus // NE -- 001
722d1f6d67SPete Couperus // LT -- 010
732d1f6d67SPete Couperus // GE -- 011
742d1f6d67SPete Couperus // LO -- 100
752d1f6d67SPete Couperus // HS -- 101
762d1f6d67SPete Couperus static unsigned getCCForBRcc(unsigned CC) {
772d1f6d67SPete Couperus   switch (CC) {
782d1f6d67SPete Couperus   case ARCCC::EQ:
792d1f6d67SPete Couperus     return 0;
802d1f6d67SPete Couperus   case ARCCC::NE:
812d1f6d67SPete Couperus     return 1;
822d1f6d67SPete Couperus   case ARCCC::LT:
832d1f6d67SPete Couperus     return 2;
842d1f6d67SPete Couperus   case ARCCC::GE:
852d1f6d67SPete Couperus     return 3;
862d1f6d67SPete Couperus   case ARCCC::LO:
872d1f6d67SPete Couperus     return 4;
882d1f6d67SPete Couperus   case ARCCC::HS:
892d1f6d67SPete Couperus     return 5;
902d1f6d67SPete Couperus   default:
912d1f6d67SPete Couperus     return -1U;
922d1f6d67SPete Couperus   }
932d1f6d67SPete Couperus }
942d1f6d67SPete Couperus 
isBRccPseudo(MachineInstr * MI)952d1f6d67SPete Couperus static bool isBRccPseudo(MachineInstr *MI) {
962d1f6d67SPete Couperus   return !(MI->getOpcode() != ARC::BRcc_rr_p &&
972d1f6d67SPete Couperus            MI->getOpcode() != ARC::BRcc_ru6_p);
982d1f6d67SPete Couperus }
992d1f6d67SPete Couperus 
getBRccForPseudo(MachineInstr * MI)1002d1f6d67SPete Couperus static unsigned getBRccForPseudo(MachineInstr *MI) {
1012d1f6d67SPete Couperus   assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
1022d1f6d67SPete Couperus   if (MI->getOpcode() == ARC::BRcc_rr_p)
1032d1f6d67SPete Couperus     return ARC::BRcc_rr;
1042d1f6d67SPete Couperus   return ARC::BRcc_ru6;
1052d1f6d67SPete Couperus }
1062d1f6d67SPete Couperus 
getCmpForPseudo(MachineInstr * MI)1072d1f6d67SPete Couperus static unsigned getCmpForPseudo(MachineInstr *MI) {
1082d1f6d67SPete Couperus   assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
1092d1f6d67SPete Couperus   if (MI->getOpcode() == ARC::BRcc_rr_p)
1102d1f6d67SPete Couperus     return ARC::CMP_rr;
1112d1f6d67SPete Couperus   return ARC::CMP_ru6;
1122d1f6d67SPete Couperus }
1132d1f6d67SPete Couperus 
replaceWithBRcc(MachineInstr * MI) const1142d1f6d67SPete Couperus void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const {
115d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n");
1162d1f6d67SPete Couperus   unsigned CC = getCCForBRcc(MI->getOperand(3).getImm());
1172d1f6d67SPete Couperus   if (CC != -1U) {
1182d1f6d67SPete Couperus     BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1192d1f6d67SPete Couperus             TII->get(getBRccForPseudo(MI)))
1202d1f6d67SPete Couperus         .addMBB(MI->getOperand(0).getMBB())
1212d1f6d67SPete Couperus         .addReg(MI->getOperand(1).getReg())
1222d1f6d67SPete Couperus         .add(MI->getOperand(2))
1232d1f6d67SPete Couperus         .addImm(getCCForBRcc(MI->getOperand(3).getImm()));
1242d1f6d67SPete Couperus     MI->eraseFromParent();
1252d1f6d67SPete Couperus   } else {
1262d1f6d67SPete Couperus     replaceWithCmpBcc(MI);
1272d1f6d67SPete Couperus   }
1282d1f6d67SPete Couperus }
1292d1f6d67SPete Couperus 
replaceWithCmpBcc(MachineInstr * MI) const1302d1f6d67SPete Couperus void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const {
131d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Branch: " << *MI << "\n");
132d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n");
1332d1f6d67SPete Couperus   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1342d1f6d67SPete Couperus           TII->get(getCmpForPseudo(MI)))
1352d1f6d67SPete Couperus       .addReg(MI->getOperand(1).getReg())
1362d1f6d67SPete Couperus       .add(MI->getOperand(2));
1372d1f6d67SPete Couperus   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc))
1382d1f6d67SPete Couperus       .addMBB(MI->getOperand(0).getMBB())
1392d1f6d67SPete Couperus       .addImm(MI->getOperand(3).getImm());
1402d1f6d67SPete Couperus   MI->eraseFromParent();
1412d1f6d67SPete Couperus }
1422d1f6d67SPete Couperus 
runOnMachineFunction(MachineFunction & MF)1432d1f6d67SPete Couperus bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) {
144d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Running ARC Branch Finalize on " << MF.getName()
145d34e60caSNicola Zaghen                     << "\n");
1462d1f6d67SPete Couperus   std::vector<MachineInstr *> Branches;
1472d1f6d67SPete Couperus   bool Changed = false;
1482d1f6d67SPete Couperus   unsigned MaxSize = 0;
1492d1f6d67SPete Couperus   TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
1502d1f6d67SPete Couperus   std::map<MachineBasicBlock *, unsigned> BlockToPCMap;
1512d1f6d67SPete Couperus   std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList;
1522d1f6d67SPete Couperus   unsigned PC = 0;
1532d1f6d67SPete Couperus 
1542d1f6d67SPete Couperus   for (auto &MBB : MF) {
1552d1f6d67SPete Couperus     BlockToPCMap.insert(std::make_pair(&MBB, PC));
1562d1f6d67SPete Couperus     for (auto &MI : MBB) {
1572d1f6d67SPete Couperus       unsigned Size = TII->getInstSizeInBytes(MI);
1582d1f6d67SPete Couperus       if (Size > 8 || Size == 0) {
159d34e60caSNicola Zaghen         LLVM_DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n");
1602d1f6d67SPete Couperus       } else {
1612d1f6d67SPete Couperus         MaxSize += Size;
1622d1f6d67SPete Couperus       }
1632d1f6d67SPete Couperus       if (MI.isBranch()) {
1642d1f6d67SPete Couperus         Branches.push_back(&MI);
1652d1f6d67SPete Couperus         BranchToPCList.emplace_back(&MI, PC);
1662d1f6d67SPete Couperus       }
1672d1f6d67SPete Couperus       PC += Size;
1682d1f6d67SPete Couperus     }
1692d1f6d67SPete Couperus   }
1702d1f6d67SPete Couperus   for (auto P : BranchToPCList) {
1712d1f6d67SPete Couperus     if (isBRccPseudo(P.first))
1722d1f6d67SPete Couperus       isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first);
1732d1f6d67SPete Couperus   }
1742d1f6d67SPete Couperus 
175d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Estimated function size for " << MF.getName() << ": "
176d34e60caSNicola Zaghen                     << MaxSize << "\n");
1772d1f6d67SPete Couperus 
1782d1f6d67SPete Couperus   return Changed;
1792d1f6d67SPete Couperus }
1802d1f6d67SPete Couperus 
createARCBranchFinalizePass()1812d1f6d67SPete Couperus FunctionPass *llvm::createARCBranchFinalizePass() {
1822d1f6d67SPete Couperus   return new ARCBranchFinalize();
1832d1f6d67SPete Couperus }
184