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