1 //===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This pass takes existing conditional branches and expands them into longer 10 // range conditional branches. 11 //===----------------------------------------------------------------------===// 12 13 #define DEBUG_TYPE "arc-branch-finalize" 14 15 #include "ARCInstrInfo.h" 16 #include "ARCTargetMachine.h" 17 #include "MCTargetDesc/ARCInfo.h" 18 #include "llvm/CodeGen/MachineFunctionPass.h" 19 #include "llvm/CodeGen/MachineInstrBuilder.h" 20 #include "llvm/CodeGen/MachineRegisterInfo.h" 21 #include "llvm/CodeGen/Passes.h" 22 #include "llvm/CodeGen/TargetInstrInfo.h" 23 #include "llvm/Support/Debug.h" 24 #include <vector> 25 26 using namespace llvm; 27 28 namespace llvm { 29 30 void initializeARCBranchFinalizePass(PassRegistry &Registry); 31 FunctionPass *createARCBranchFinalizePass(); 32 33 } // end namespace llvm 34 35 namespace { 36 37 class ARCBranchFinalize : public MachineFunctionPass { 38 public: 39 static char ID; 40 41 ARCBranchFinalize() : MachineFunctionPass(ID) { 42 initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry()); 43 } 44 45 StringRef getPassName() const override { 46 return "ARC Branch Finalization Pass"; 47 } 48 49 bool runOnMachineFunction(MachineFunction &MF) override; 50 void replaceWithBRcc(MachineInstr *MI) const; 51 void replaceWithCmpBcc(MachineInstr *MI) const; 52 53 private: 54 const ARCInstrInfo *TII{nullptr}; 55 }; 56 57 char ARCBranchFinalize::ID = 0; 58 59 } // end anonymous namespace 60 61 INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize", 62 "ARC finalize branches", false, false) 63 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) 64 INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize", 65 "ARC finalize branches", false, false) 66 67 // BRcc has 6 supported condition codes, which differ from the 16 68 // condition codes supported in the predicated instructions: 69 // EQ -- 000 70 // NE -- 001 71 // LT -- 010 72 // GE -- 011 73 // LO -- 100 74 // HS -- 101 75 static unsigned getCCForBRcc(unsigned CC) { 76 switch (CC) { 77 case ARCCC::EQ: 78 return 0; 79 case ARCCC::NE: 80 return 1; 81 case ARCCC::LT: 82 return 2; 83 case ARCCC::GE: 84 return 3; 85 case ARCCC::LO: 86 return 4; 87 case ARCCC::HS: 88 return 5; 89 default: 90 return -1U; 91 } 92 } 93 94 static bool isBRccPseudo(MachineInstr *MI) { 95 return !(MI->getOpcode() != ARC::BRcc_rr_p && 96 MI->getOpcode() != ARC::BRcc_ru6_p); 97 } 98 99 static unsigned getBRccForPseudo(MachineInstr *MI) { 100 assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction."); 101 if (MI->getOpcode() == ARC::BRcc_rr_p) 102 return ARC::BRcc_rr; 103 return ARC::BRcc_ru6; 104 } 105 106 static unsigned getCmpForPseudo(MachineInstr *MI) { 107 assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction."); 108 if (MI->getOpcode() == ARC::BRcc_rr_p) 109 return ARC::CMP_rr; 110 return ARC::CMP_ru6; 111 } 112 113 void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const { 114 LLVM_DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n"); 115 unsigned CC = getCCForBRcc(MI->getOperand(3).getImm()); 116 if (CC != -1U) { 117 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 118 TII->get(getBRccForPseudo(MI))) 119 .addMBB(MI->getOperand(0).getMBB()) 120 .addReg(MI->getOperand(1).getReg()) 121 .add(MI->getOperand(2)) 122 .addImm(getCCForBRcc(MI->getOperand(3).getImm())); 123 MI->eraseFromParent(); 124 } else { 125 replaceWithCmpBcc(MI); 126 } 127 } 128 129 void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const { 130 LLVM_DEBUG(dbgs() << "Branch: " << *MI << "\n"); 131 LLVM_DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n"); 132 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 133 TII->get(getCmpForPseudo(MI))) 134 .addReg(MI->getOperand(1).getReg()) 135 .add(MI->getOperand(2)); 136 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc)) 137 .addMBB(MI->getOperand(0).getMBB()) 138 .addImm(MI->getOperand(3).getImm()); 139 MI->eraseFromParent(); 140 } 141 142 bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) { 143 LLVM_DEBUG(dbgs() << "Running ARC Branch Finalize on " << MF.getName() 144 << "\n"); 145 std::vector<MachineInstr *> Branches; 146 bool Changed = false; 147 unsigned MaxSize = 0; 148 TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); 149 std::map<MachineBasicBlock *, unsigned> BlockToPCMap; 150 std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList; 151 unsigned PC = 0; 152 153 for (auto &MBB : MF) { 154 BlockToPCMap.insert(std::make_pair(&MBB, PC)); 155 for (auto &MI : MBB) { 156 unsigned Size = TII->getInstSizeInBytes(MI); 157 if (Size > 8 || Size == 0) { 158 LLVM_DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n"); 159 } else { 160 MaxSize += Size; 161 } 162 if (MI.isBranch()) { 163 Branches.push_back(&MI); 164 BranchToPCList.emplace_back(&MI, PC); 165 } 166 PC += Size; 167 } 168 } 169 for (auto P : BranchToPCList) { 170 if (isBRccPseudo(P.first)) 171 isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first); 172 } 173 174 LLVM_DEBUG(dbgs() << "Estimated function size for " << MF.getName() << ": " 175 << MaxSize << "\n"); 176 177 return Changed; 178 } 179 180 FunctionPass *llvm::createARCBranchFinalizePass() { 181 return new ARCBranchFinalize(); 182 } 183