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