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