xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARC/ARCBranchFinalize.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass takes existing conditional branches and expands them into longer
100b57cec5SDimitry Andric // range conditional branches.
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARCInstrInfo.h"
140b57cec5SDimitry Andric #include "ARCTargetMachine.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/ARCInfo.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
21480093f4SDimitry Andric #include "llvm/InitializePasses.h"
220b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
230b57cec5SDimitry Andric #include <vector>
240b57cec5SDimitry Andric 
25fe6060f1SDimitry Andric #define DEBUG_TYPE "arc-branch-finalize"
26fe6060f1SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace llvm {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric void initializeARCBranchFinalizePass(PassRegistry &Registry);
320b57cec5SDimitry Andric FunctionPass *createARCBranchFinalizePass();
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric } // end namespace llvm
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric namespace {
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric class ARCBranchFinalize : public MachineFunctionPass {
390b57cec5SDimitry Andric public:
400b57cec5SDimitry Andric   static char ID;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   ARCBranchFinalize() : MachineFunctionPass(ID) {
430b57cec5SDimitry Andric     initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry());
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   StringRef getPassName() const override {
470b57cec5SDimitry Andric     return "ARC Branch Finalization Pass";
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
510b57cec5SDimitry Andric   void replaceWithBRcc(MachineInstr *MI) const;
520b57cec5SDimitry Andric   void replaceWithCmpBcc(MachineInstr *MI) const;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric private:
550b57cec5SDimitry Andric   const ARCInstrInfo *TII{nullptr};
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric char ARCBranchFinalize::ID = 0;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric } // end anonymous namespace
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize",
630b57cec5SDimitry Andric                       "ARC finalize branches", false, false)
64*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
650b57cec5SDimitry Andric INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize",
660b57cec5SDimitry Andric                     "ARC finalize branches", false, false)
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric // BRcc has 6 supported condition codes, which differ from the 16
690b57cec5SDimitry Andric // condition codes supported in the predicated instructions:
700b57cec5SDimitry Andric // EQ -- 000
710b57cec5SDimitry Andric // NE -- 001
720b57cec5SDimitry Andric // LT -- 010
730b57cec5SDimitry Andric // GE -- 011
740b57cec5SDimitry Andric // LO -- 100
750b57cec5SDimitry Andric // HS -- 101
760b57cec5SDimitry Andric static unsigned getCCForBRcc(unsigned CC) {
770b57cec5SDimitry Andric   switch (CC) {
780b57cec5SDimitry Andric   case ARCCC::EQ:
790b57cec5SDimitry Andric     return 0;
800b57cec5SDimitry Andric   case ARCCC::NE:
810b57cec5SDimitry Andric     return 1;
820b57cec5SDimitry Andric   case ARCCC::LT:
830b57cec5SDimitry Andric     return 2;
840b57cec5SDimitry Andric   case ARCCC::GE:
850b57cec5SDimitry Andric     return 3;
860b57cec5SDimitry Andric   case ARCCC::LO:
870b57cec5SDimitry Andric     return 4;
880b57cec5SDimitry Andric   case ARCCC::HS:
890b57cec5SDimitry Andric     return 5;
900b57cec5SDimitry Andric   default:
910b57cec5SDimitry Andric     return -1U;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric static bool isBRccPseudo(MachineInstr *MI) {
960b57cec5SDimitry Andric   return !(MI->getOpcode() != ARC::BRcc_rr_p &&
970b57cec5SDimitry Andric            MI->getOpcode() != ARC::BRcc_ru6_p);
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric static unsigned getBRccForPseudo(MachineInstr *MI) {
1010b57cec5SDimitry Andric   assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
1020b57cec5SDimitry Andric   if (MI->getOpcode() == ARC::BRcc_rr_p)
1030b57cec5SDimitry Andric     return ARC::BRcc_rr;
1040b57cec5SDimitry Andric   return ARC::BRcc_ru6;
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric static unsigned getCmpForPseudo(MachineInstr *MI) {
1080b57cec5SDimitry Andric   assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
1090b57cec5SDimitry Andric   if (MI->getOpcode() == ARC::BRcc_rr_p)
1100b57cec5SDimitry Andric     return ARC::CMP_rr;
1110b57cec5SDimitry Andric   return ARC::CMP_ru6;
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const {
1150b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n");
1160b57cec5SDimitry Andric   unsigned CC = getCCForBRcc(MI->getOperand(3).getImm());
1170b57cec5SDimitry Andric   if (CC != -1U) {
1180b57cec5SDimitry Andric     BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1190b57cec5SDimitry Andric             TII->get(getBRccForPseudo(MI)))
1200b57cec5SDimitry Andric         .addMBB(MI->getOperand(0).getMBB())
1210b57cec5SDimitry Andric         .addReg(MI->getOperand(1).getReg())
1220b57cec5SDimitry Andric         .add(MI->getOperand(2))
1230b57cec5SDimitry Andric         .addImm(getCCForBRcc(MI->getOperand(3).getImm()));
1240b57cec5SDimitry Andric     MI->eraseFromParent();
1250b57cec5SDimitry Andric   } else {
1260b57cec5SDimitry Andric     replaceWithCmpBcc(MI);
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const {
1310b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Branch: " << *MI << "\n");
1320b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n");
1330b57cec5SDimitry Andric   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1340b57cec5SDimitry Andric           TII->get(getCmpForPseudo(MI)))
1350b57cec5SDimitry Andric       .addReg(MI->getOperand(1).getReg())
1360b57cec5SDimitry Andric       .add(MI->getOperand(2));
1370b57cec5SDimitry Andric   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc))
1380b57cec5SDimitry Andric       .addMBB(MI->getOperand(0).getMBB())
1390b57cec5SDimitry Andric       .addImm(MI->getOperand(3).getImm());
1400b57cec5SDimitry Andric   MI->eraseFromParent();
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) {
1440b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Running ARC Branch Finalize on " << MF.getName()
1450b57cec5SDimitry Andric                     << "\n");
1460b57cec5SDimitry Andric   std::vector<MachineInstr *> Branches;
1470b57cec5SDimitry Andric   bool Changed = false;
1480b57cec5SDimitry Andric   unsigned MaxSize = 0;
1490b57cec5SDimitry Andric   TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
1500b57cec5SDimitry Andric   std::map<MachineBasicBlock *, unsigned> BlockToPCMap;
1510b57cec5SDimitry Andric   std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList;
1520b57cec5SDimitry Andric   unsigned PC = 0;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   for (auto &MBB : MF) {
1550b57cec5SDimitry Andric     BlockToPCMap.insert(std::make_pair(&MBB, PC));
1560b57cec5SDimitry Andric     for (auto &MI : MBB) {
1570b57cec5SDimitry Andric       unsigned Size = TII->getInstSizeInBytes(MI);
1580b57cec5SDimitry Andric       if (Size > 8 || Size == 0) {
1590b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n");
1600b57cec5SDimitry Andric       } else {
1610b57cec5SDimitry Andric         MaxSize += Size;
1620b57cec5SDimitry Andric       }
1630b57cec5SDimitry Andric       if (MI.isBranch()) {
1640b57cec5SDimitry Andric         Branches.push_back(&MI);
1650b57cec5SDimitry Andric         BranchToPCList.emplace_back(&MI, PC);
1660b57cec5SDimitry Andric       }
1670b57cec5SDimitry Andric       PC += Size;
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric   for (auto P : BranchToPCList) {
1710b57cec5SDimitry Andric     if (isBRccPseudo(P.first))
1720b57cec5SDimitry Andric       isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first);
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Estimated function size for " << MF.getName() << ": "
1760b57cec5SDimitry Andric                     << MaxSize << "\n");
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   return Changed;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric FunctionPass *llvm::createARCBranchFinalizePass() {
1820b57cec5SDimitry Andric   return new ARCBranchFinalize();
1830b57cec5SDimitry Andric }
184