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
ARCBranchFinalize()420b57cec5SDimitry Andric ARCBranchFinalize() : MachineFunctionPass(ID) {
430b57cec5SDimitry Andric initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry());
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric
getPassName() const460b57cec5SDimitry 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)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)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
isBRccPseudo(MachineInstr * MI)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
getBRccForPseudo(MachineInstr * MI)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
getCmpForPseudo(MachineInstr * MI)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
replaceWithBRcc(MachineInstr * MI) const1140b57cec5SDimitry 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
replaceWithCmpBcc(MachineInstr * MI) const1300b57cec5SDimitry 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
runOnMachineFunction(MachineFunction & MF)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
createARCBranchFinalizePass()1810b57cec5SDimitry Andric FunctionPass *llvm::createARCBranchFinalizePass() {
1820b57cec5SDimitry Andric return new ARCBranchFinalize();
1830b57cec5SDimitry Andric }
184