10b57cec5SDimitry Andric //===- HexagonGenPredicate.cpp --------------------------------------------===// 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 #include "HexagonInstrInfo.h" 100b57cec5SDimitry Andric #include "HexagonSubtarget.h" 110b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h" 120b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 130b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 220b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 23480093f4SDimitry Andric #include "llvm/InitializePasses.h" 240b57cec5SDimitry Andric #include "llvm/Pass.h" 250b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 260b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 290b57cec5SDimitry Andric #include <cassert> 300b57cec5SDimitry Andric #include <iterator> 310b57cec5SDimitry Andric #include <map> 320b57cec5SDimitry Andric #include <queue> 330b57cec5SDimitry Andric #include <set> 340b57cec5SDimitry Andric #include <utility> 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric #define DEBUG_TYPE "gen-pred" 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric using namespace llvm; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric namespace llvm { 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric void initializeHexagonGenPredicatePass(PassRegistry& Registry); 430b57cec5SDimitry Andric FunctionPass *createHexagonGenPredicate(); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric } // end namespace llvm 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric namespace { 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric // FIXME: Use TargetInstrInfo::RegSubRegPair 500b57cec5SDimitry Andric struct RegisterSubReg { 51e8d8bef9SDimitry Andric Register R; 52e8d8bef9SDimitry Andric unsigned S; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric RegisterSubReg(unsigned r = 0, unsigned s = 0) : R(r), S(s) {} 550b57cec5SDimitry Andric RegisterSubReg(const MachineOperand &MO) : R(MO.getReg()), S(MO.getSubReg()) {} 560b57cec5SDimitry Andric RegisterSubReg(const Register &Reg) : R(Reg), S(0) {} 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool operator== (const RegisterSubReg &Reg) const { 590b57cec5SDimitry Andric return R == Reg.R && S == Reg.S; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric bool operator< (const RegisterSubReg &Reg) const { 630b57cec5SDimitry Andric return R < Reg.R || (R == Reg.R && S < Reg.S); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric }; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric struct PrintRegister { 680b57cec5SDimitry Andric friend raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR); 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric PrintRegister(RegisterSubReg R, const TargetRegisterInfo &I) : Reg(R), TRI(I) {} 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric private: 730b57cec5SDimitry Andric RegisterSubReg Reg; 740b57cec5SDimitry Andric const TargetRegisterInfo &TRI; 750b57cec5SDimitry Andric }; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR) 780b57cec5SDimitry Andric LLVM_ATTRIBUTE_UNUSED; 790b57cec5SDimitry Andric raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR) { 800b57cec5SDimitry Andric return OS << printReg(PR.Reg.R, &PR.TRI, PR.Reg.S); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric class HexagonGenPredicate : public MachineFunctionPass { 840b57cec5SDimitry Andric public: 850b57cec5SDimitry Andric static char ID; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric HexagonGenPredicate() : MachineFunctionPass(ID) { 880b57cec5SDimitry Andric initializeHexagonGenPredicatePass(*PassRegistry::getPassRegistry()); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric StringRef getPassName() const override { 920b57cec5SDimitry Andric return "Hexagon generate predicate operations"; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 96*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 97*0fca6ea1SDimitry Andric AU.addPreserved<MachineDominatorTreeWrapperPass>(); 980b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric private: 1040b57cec5SDimitry Andric using VectOfInst = SetVector<MachineInstr *>; 1050b57cec5SDimitry Andric using SetOfReg = std::set<RegisterSubReg>; 1060b57cec5SDimitry Andric using RegToRegMap = std::map<RegisterSubReg, RegisterSubReg>; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric const HexagonInstrInfo *TII = nullptr; 1090b57cec5SDimitry Andric const HexagonRegisterInfo *TRI = nullptr; 1100b57cec5SDimitry Andric MachineRegisterInfo *MRI = nullptr; 1110b57cec5SDimitry Andric SetOfReg PredGPRs; 1120b57cec5SDimitry Andric VectOfInst PUsers; 1130b57cec5SDimitry Andric RegToRegMap G2P; 1140b57cec5SDimitry Andric 115e8d8bef9SDimitry Andric bool isPredReg(Register R); 1160b57cec5SDimitry Andric void collectPredicateGPR(MachineFunction &MF); 1170b57cec5SDimitry Andric void processPredicateGPR(const RegisterSubReg &Reg); 1180b57cec5SDimitry Andric unsigned getPredForm(unsigned Opc); 1190b57cec5SDimitry Andric bool isConvertibleToPredForm(const MachineInstr *MI); 1200b57cec5SDimitry Andric bool isScalarCmp(unsigned Opc); 1210b57cec5SDimitry Andric bool isScalarPred(RegisterSubReg PredReg); 1220b57cec5SDimitry Andric RegisterSubReg getPredRegFor(const RegisterSubReg &Reg); 1230b57cec5SDimitry Andric bool convertToPredForm(MachineInstr *MI); 1240b57cec5SDimitry Andric bool eliminatePredCopies(MachineFunction &MF); 1250b57cec5SDimitry Andric }; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric } // end anonymous namespace 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric char HexagonGenPredicate::ID = 0; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonGenPredicate, "hexagon-gen-pred", 1320b57cec5SDimitry Andric "Hexagon generate predicate operations", false, false) 133*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 1340b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonGenPredicate, "hexagon-gen-pred", 1350b57cec5SDimitry Andric "Hexagon generate predicate operations", false, false) 1360b57cec5SDimitry Andric 137e8d8bef9SDimitry Andric bool HexagonGenPredicate::isPredReg(Register R) { 138e8d8bef9SDimitry Andric if (!R.isVirtual()) 1390b57cec5SDimitry Andric return false; 1400b57cec5SDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(R); 1410b57cec5SDimitry Andric return RC == &Hexagon::PredRegsRegClass; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric unsigned HexagonGenPredicate::getPredForm(unsigned Opc) { 1450b57cec5SDimitry Andric using namespace Hexagon; 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric switch (Opc) { 1480b57cec5SDimitry Andric case A2_and: 1490b57cec5SDimitry Andric case A2_andp: 1500b57cec5SDimitry Andric return C2_and; 1510b57cec5SDimitry Andric case A4_andn: 1520b57cec5SDimitry Andric case A4_andnp: 1530b57cec5SDimitry Andric return C2_andn; 1540b57cec5SDimitry Andric case M4_and_and: 1550b57cec5SDimitry Andric return C4_and_and; 1560b57cec5SDimitry Andric case M4_and_andn: 1570b57cec5SDimitry Andric return C4_and_andn; 1580b57cec5SDimitry Andric case M4_and_or: 1590b57cec5SDimitry Andric return C4_and_or; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric case A2_or: 1620b57cec5SDimitry Andric case A2_orp: 1630b57cec5SDimitry Andric return C2_or; 1640b57cec5SDimitry Andric case A4_orn: 1650b57cec5SDimitry Andric case A4_ornp: 1660b57cec5SDimitry Andric return C2_orn; 1670b57cec5SDimitry Andric case M4_or_and: 1680b57cec5SDimitry Andric return C4_or_and; 1690b57cec5SDimitry Andric case M4_or_andn: 1700b57cec5SDimitry Andric return C4_or_andn; 1710b57cec5SDimitry Andric case M4_or_or: 1720b57cec5SDimitry Andric return C4_or_or; 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric case A2_xor: 1750b57cec5SDimitry Andric case A2_xorp: 1760b57cec5SDimitry Andric return C2_xor; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric case C2_tfrrp: 1790b57cec5SDimitry Andric return COPY; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric // The opcode corresponding to 0 is TargetOpcode::PHI. We can use 0 here 1820b57cec5SDimitry Andric // to denote "none", but we need to make sure that none of the valid opcodes 1830b57cec5SDimitry Andric // that we return will ever be 0. 1840b57cec5SDimitry Andric static_assert(PHI == 0, "Use different value for <none>"); 1850b57cec5SDimitry Andric return 0; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric bool HexagonGenPredicate::isConvertibleToPredForm(const MachineInstr *MI) { 1890b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 1900b57cec5SDimitry Andric if (getPredForm(Opc) != 0) 1910b57cec5SDimitry Andric return true; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // Comparisons against 0 are also convertible. This does not apply to 1940b57cec5SDimitry Andric // A4_rcmpeqi or A4_rcmpneqi, since they produce values 0 or 1, which 1950b57cec5SDimitry Andric // may not match the value that the predicate register would have if 1960b57cec5SDimitry Andric // it was converted to a predicate form. 1970b57cec5SDimitry Andric switch (Opc) { 1980b57cec5SDimitry Andric case Hexagon::C2_cmpeqi: 1990b57cec5SDimitry Andric case Hexagon::C4_cmpneqi: 2000b57cec5SDimitry Andric if (MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0) 2010b57cec5SDimitry Andric return true; 2020b57cec5SDimitry Andric break; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric return false; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric void HexagonGenPredicate::collectPredicateGPR(MachineFunction &MF) { 2084824e7fdSDimitry Andric for (MachineBasicBlock &B : MF) { 2094824e7fdSDimitry Andric for (MachineInstr &MI : B) { 2104824e7fdSDimitry Andric unsigned Opc = MI.getOpcode(); 2110b57cec5SDimitry Andric switch (Opc) { 2120b57cec5SDimitry Andric case Hexagon::C2_tfrpr: 2130b57cec5SDimitry Andric case TargetOpcode::COPY: 2144824e7fdSDimitry Andric if (isPredReg(MI.getOperand(1).getReg())) { 2154824e7fdSDimitry Andric RegisterSubReg RD = MI.getOperand(0); 216e8d8bef9SDimitry Andric if (RD.R.isVirtual()) 2170b57cec5SDimitry Andric PredGPRs.insert(RD); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric break; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void HexagonGenPredicate::processPredicateGPR(const RegisterSubReg &Reg) { 2260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << ": " << printReg(Reg.R, TRI, Reg.S) << "\n"); 2270b57cec5SDimitry Andric using use_iterator = MachineRegisterInfo::use_iterator; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric use_iterator I = MRI->use_begin(Reg.R), E = MRI->use_end(); 2300b57cec5SDimitry Andric if (I == E) { 2310b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Dead reg: " << printReg(Reg.R, TRI, Reg.S) << '\n'); 2320b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(Reg.R); 2330b57cec5SDimitry Andric DefI->eraseFromParent(); 2340b57cec5SDimitry Andric return; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric for (; I != E; ++I) { 2380b57cec5SDimitry Andric MachineInstr *UseI = I->getParent(); 2390b57cec5SDimitry Andric if (isConvertibleToPredForm(UseI)) 2400b57cec5SDimitry Andric PUsers.insert(UseI); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric RegisterSubReg HexagonGenPredicate::getPredRegFor(const RegisterSubReg &Reg) { 2450b57cec5SDimitry Andric // Create a predicate register for a given Reg. The newly created register 2460b57cec5SDimitry Andric // will have its value copied from Reg, so that it can be later used as 2470b57cec5SDimitry Andric // an operand in other instructions. 248e8d8bef9SDimitry Andric assert(Reg.R.isVirtual()); 2490b57cec5SDimitry Andric RegToRegMap::iterator F = G2P.find(Reg); 2500b57cec5SDimitry Andric if (F != G2P.end()) 2510b57cec5SDimitry Andric return F->second; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << ": " << PrintRegister(Reg, *TRI)); 2540b57cec5SDimitry Andric MachineInstr *DefI = MRI->getVRegDef(Reg.R); 2550b57cec5SDimitry Andric assert(DefI); 2560b57cec5SDimitry Andric unsigned Opc = DefI->getOpcode(); 2570b57cec5SDimitry Andric if (Opc == Hexagon::C2_tfrpr || Opc == TargetOpcode::COPY) { 2580b57cec5SDimitry Andric assert(DefI->getOperand(0).isDef() && DefI->getOperand(1).isUse()); 2590b57cec5SDimitry Andric RegisterSubReg PR = DefI->getOperand(1); 2600b57cec5SDimitry Andric G2P.insert(std::make_pair(Reg, PR)); 2610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " -> " << PrintRegister(PR, *TRI) << '\n'); 2620b57cec5SDimitry Andric return PR; 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric MachineBasicBlock &B = *DefI->getParent(); 2660b57cec5SDimitry Andric DebugLoc DL = DefI->getDebugLoc(); 2670b57cec5SDimitry Andric const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass; 2688bcb0991SDimitry Andric Register NewPR = MRI->createVirtualRegister(PredRC); 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // For convertible instructions, do not modify them, so that they can 2710b57cec5SDimitry Andric // be converted later. Generate a copy from Reg to NewPR. 2720b57cec5SDimitry Andric if (isConvertibleToPredForm(DefI)) { 2730b57cec5SDimitry Andric MachineBasicBlock::iterator DefIt = DefI; 2740b57cec5SDimitry Andric BuildMI(B, std::next(DefIt), DL, TII->get(TargetOpcode::COPY), NewPR) 2750b57cec5SDimitry Andric .addReg(Reg.R, 0, Reg.S); 2760b57cec5SDimitry Andric G2P.insert(std::make_pair(Reg, RegisterSubReg(NewPR))); 2770b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " -> !" << PrintRegister(RegisterSubReg(NewPR), *TRI) 2780b57cec5SDimitry Andric << '\n'); 2790b57cec5SDimitry Andric return RegisterSubReg(NewPR); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric llvm_unreachable("Invalid argument"); 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric bool HexagonGenPredicate::isScalarCmp(unsigned Opc) { 2860b57cec5SDimitry Andric switch (Opc) { 2870b57cec5SDimitry Andric case Hexagon::C2_cmpeq: 2880b57cec5SDimitry Andric case Hexagon::C2_cmpgt: 2890b57cec5SDimitry Andric case Hexagon::C2_cmpgtu: 2900b57cec5SDimitry Andric case Hexagon::C2_cmpeqp: 2910b57cec5SDimitry Andric case Hexagon::C2_cmpgtp: 2920b57cec5SDimitry Andric case Hexagon::C2_cmpgtup: 2930b57cec5SDimitry Andric case Hexagon::C2_cmpeqi: 2940b57cec5SDimitry Andric case Hexagon::C2_cmpgti: 2950b57cec5SDimitry Andric case Hexagon::C2_cmpgtui: 2960b57cec5SDimitry Andric case Hexagon::C2_cmpgei: 2970b57cec5SDimitry Andric case Hexagon::C2_cmpgeui: 2980b57cec5SDimitry Andric case Hexagon::C4_cmpneqi: 2990b57cec5SDimitry Andric case Hexagon::C4_cmpltei: 3000b57cec5SDimitry Andric case Hexagon::C4_cmplteui: 3010b57cec5SDimitry Andric case Hexagon::C4_cmpneq: 3020b57cec5SDimitry Andric case Hexagon::C4_cmplte: 3030b57cec5SDimitry Andric case Hexagon::C4_cmplteu: 3040b57cec5SDimitry Andric case Hexagon::A4_cmpbeq: 3050b57cec5SDimitry Andric case Hexagon::A4_cmpbeqi: 3060b57cec5SDimitry Andric case Hexagon::A4_cmpbgtu: 3070b57cec5SDimitry Andric case Hexagon::A4_cmpbgtui: 3080b57cec5SDimitry Andric case Hexagon::A4_cmpbgt: 3090b57cec5SDimitry Andric case Hexagon::A4_cmpbgti: 3100b57cec5SDimitry Andric case Hexagon::A4_cmpheq: 3110b57cec5SDimitry Andric case Hexagon::A4_cmphgt: 3120b57cec5SDimitry Andric case Hexagon::A4_cmphgtu: 3130b57cec5SDimitry Andric case Hexagon::A4_cmpheqi: 3140b57cec5SDimitry Andric case Hexagon::A4_cmphgti: 3150b57cec5SDimitry Andric case Hexagon::A4_cmphgtui: 3160b57cec5SDimitry Andric return true; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric return false; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric bool HexagonGenPredicate::isScalarPred(RegisterSubReg PredReg) { 3220b57cec5SDimitry Andric std::queue<RegisterSubReg> WorkQ; 3230b57cec5SDimitry Andric WorkQ.push(PredReg); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric while (!WorkQ.empty()) { 3260b57cec5SDimitry Andric RegisterSubReg PR = WorkQ.front(); 3270b57cec5SDimitry Andric WorkQ.pop(); 3280b57cec5SDimitry Andric const MachineInstr *DefI = MRI->getVRegDef(PR.R); 3290b57cec5SDimitry Andric if (!DefI) 3300b57cec5SDimitry Andric return false; 3310b57cec5SDimitry Andric unsigned DefOpc = DefI->getOpcode(); 3320b57cec5SDimitry Andric switch (DefOpc) { 3330b57cec5SDimitry Andric case TargetOpcode::COPY: { 3340b57cec5SDimitry Andric const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass; 3350b57cec5SDimitry Andric if (MRI->getRegClass(PR.R) != PredRC) 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric // If it is a copy between two predicate registers, fall through. 338bdd1243dSDimitry Andric [[fallthrough]]; 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric case Hexagon::C2_and: 3410b57cec5SDimitry Andric case Hexagon::C2_andn: 3420b57cec5SDimitry Andric case Hexagon::C4_and_and: 3430b57cec5SDimitry Andric case Hexagon::C4_and_andn: 3440b57cec5SDimitry Andric case Hexagon::C4_and_or: 3450b57cec5SDimitry Andric case Hexagon::C2_or: 3460b57cec5SDimitry Andric case Hexagon::C2_orn: 3470b57cec5SDimitry Andric case Hexagon::C4_or_and: 3480b57cec5SDimitry Andric case Hexagon::C4_or_andn: 3490b57cec5SDimitry Andric case Hexagon::C4_or_or: 3500b57cec5SDimitry Andric case Hexagon::C4_or_orn: 3510b57cec5SDimitry Andric case Hexagon::C2_xor: 3520b57cec5SDimitry Andric // Add operands to the queue. 3530b57cec5SDimitry Andric for (const MachineOperand &MO : DefI->operands()) 3540b57cec5SDimitry Andric if (MO.isReg() && MO.isUse()) 3550b57cec5SDimitry Andric WorkQ.push(RegisterSubReg(MO.getReg())); 3560b57cec5SDimitry Andric break; 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric // All non-vector compares are ok, everything else is bad. 3590b57cec5SDimitry Andric default: 3600b57cec5SDimitry Andric return isScalarCmp(DefOpc); 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric return true; 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) { 3680b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << ": " << MI << " " << *MI); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 3710b57cec5SDimitry Andric assert(isConvertibleToPredForm(MI)); 3720b57cec5SDimitry Andric unsigned NumOps = MI->getNumOperands(); 3730b57cec5SDimitry Andric for (unsigned i = 0; i < NumOps; ++i) { 3740b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand(i); 3750b57cec5SDimitry Andric if (!MO.isReg() || !MO.isUse()) 3760b57cec5SDimitry Andric continue; 3770b57cec5SDimitry Andric RegisterSubReg Reg(MO); 3780b57cec5SDimitry Andric if (Reg.S && Reg.S != Hexagon::isub_lo) 3790b57cec5SDimitry Andric return false; 3800b57cec5SDimitry Andric if (!PredGPRs.count(Reg)) 3810b57cec5SDimitry Andric return false; 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 3850b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric unsigned NewOpc = getPredForm(Opc); 3880b57cec5SDimitry Andric // Special case for comparisons against 0. 3890b57cec5SDimitry Andric if (NewOpc == 0) { 3900b57cec5SDimitry Andric switch (Opc) { 3910b57cec5SDimitry Andric case Hexagon::C2_cmpeqi: 3920b57cec5SDimitry Andric NewOpc = Hexagon::C2_not; 3930b57cec5SDimitry Andric break; 3940b57cec5SDimitry Andric case Hexagon::C4_cmpneqi: 3950b57cec5SDimitry Andric NewOpc = TargetOpcode::COPY; 3960b57cec5SDimitry Andric break; 3970b57cec5SDimitry Andric default: 3980b57cec5SDimitry Andric return false; 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric // If it's a scalar predicate register, then all bits in it are 4020b57cec5SDimitry Andric // the same. Otherwise, to determine whether all bits are 0 or not 4030b57cec5SDimitry Andric // we would need to use any8. 4040b57cec5SDimitry Andric RegisterSubReg PR = getPredRegFor(MI->getOperand(1)); 4050b57cec5SDimitry Andric if (!isScalarPred(PR)) 4060b57cec5SDimitry Andric return false; 4070b57cec5SDimitry Andric // This will skip the immediate argument when creating the predicate 4080b57cec5SDimitry Andric // version instruction. 4090b57cec5SDimitry Andric NumOps = 2; 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric 4124824e7fdSDimitry Andric // Check that def is in operand #0. 4130b57cec5SDimitry Andric MachineOperand &Op0 = MI->getOperand(0); 4140b57cec5SDimitry Andric assert(Op0.isDef()); 4150b57cec5SDimitry Andric RegisterSubReg OutR(Op0); 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric // Don't use getPredRegFor, since it will create an association between 4180b57cec5SDimitry Andric // the argument and a created predicate register (i.e. it will insert a 4190b57cec5SDimitry Andric // copy if a new predicate register is created). 4200b57cec5SDimitry Andric const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass; 4210b57cec5SDimitry Andric RegisterSubReg NewPR = MRI->createVirtualRegister(PredRC); 4220b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(B, MI, DL, TII->get(NewOpc), NewPR.R); 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric // Add predicate counterparts of the GPRs. 4250b57cec5SDimitry Andric for (unsigned i = 1; i < NumOps; ++i) { 4260b57cec5SDimitry Andric RegisterSubReg GPR = MI->getOperand(i); 4270b57cec5SDimitry Andric RegisterSubReg Pred = getPredRegFor(GPR); 4280b57cec5SDimitry Andric MIB.addReg(Pred.R, 0, Pred.S); 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "generated: " << *MIB); 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // Generate a copy-out: NewGPR = NewPR, and replace all uses of OutR 4330b57cec5SDimitry Andric // with NewGPR. 4340b57cec5SDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(OutR.R); 4358bcb0991SDimitry Andric Register NewOutR = MRI->createVirtualRegister(RC); 4360b57cec5SDimitry Andric BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), NewOutR) 4370b57cec5SDimitry Andric .addReg(NewPR.R, 0, NewPR.S); 4380b57cec5SDimitry Andric MRI->replaceRegWith(OutR.R, NewOutR); 4390b57cec5SDimitry Andric MI->eraseFromParent(); 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric // If the processed instruction was C2_tfrrp (i.e. Rn = Pm; Pk = Rn), 4420b57cec5SDimitry Andric // then the output will be a predicate register. Do not visit the 4430b57cec5SDimitry Andric // users of it. 4440b57cec5SDimitry Andric if (!isPredReg(NewOutR)) { 4450b57cec5SDimitry Andric RegisterSubReg R(NewOutR); 4460b57cec5SDimitry Andric PredGPRs.insert(R); 4470b57cec5SDimitry Andric processPredicateGPR(R); 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric return true; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric bool HexagonGenPredicate::eliminatePredCopies(MachineFunction &MF) { 4530b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << __func__ << "\n"); 4540b57cec5SDimitry Andric const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass; 4550b57cec5SDimitry Andric bool Changed = false; 4560b57cec5SDimitry Andric VectOfInst Erase; 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric // First, replace copies 4590b57cec5SDimitry Andric // IntR = PredR1 4600b57cec5SDimitry Andric // PredR2 = IntR 4610b57cec5SDimitry Andric // with 4620b57cec5SDimitry Andric // PredR2 = PredR1 4630b57cec5SDimitry Andric // Such sequences can be generated when a copy-into-pred is generated from 4640b57cec5SDimitry Andric // a gpr register holding a result of a convertible instruction. After 4650b57cec5SDimitry Andric // the convertible instruction is converted, its predicate result will be 4660b57cec5SDimitry Andric // copied back into the original gpr. 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) { 4690b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 4700b57cec5SDimitry Andric if (MI.getOpcode() != TargetOpcode::COPY) 4710b57cec5SDimitry Andric continue; 4720b57cec5SDimitry Andric RegisterSubReg DR = MI.getOperand(0); 4730b57cec5SDimitry Andric RegisterSubReg SR = MI.getOperand(1); 474e8d8bef9SDimitry Andric if (!DR.R.isVirtual()) 4750b57cec5SDimitry Andric continue; 476e8d8bef9SDimitry Andric if (!SR.R.isVirtual()) 4770b57cec5SDimitry Andric continue; 4780b57cec5SDimitry Andric if (MRI->getRegClass(DR.R) != PredRC) 4790b57cec5SDimitry Andric continue; 4800b57cec5SDimitry Andric if (MRI->getRegClass(SR.R) != PredRC) 4810b57cec5SDimitry Andric continue; 4820b57cec5SDimitry Andric assert(!DR.S && !SR.S && "Unexpected subregister"); 4830b57cec5SDimitry Andric MRI->replaceRegWith(DR.R, SR.R); 4840b57cec5SDimitry Andric Erase.insert(&MI); 4850b57cec5SDimitry Andric Changed = true; 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4894824e7fdSDimitry Andric for (MachineInstr *MI : Erase) 4904824e7fdSDimitry Andric MI->eraseFromParent(); 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric return Changed; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric bool HexagonGenPredicate::runOnMachineFunction(MachineFunction &MF) { 4960b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 4970b57cec5SDimitry Andric return false; 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric TII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); 5000b57cec5SDimitry Andric TRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 5010b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 5020b57cec5SDimitry Andric PredGPRs.clear(); 5030b57cec5SDimitry Andric PUsers.clear(); 5040b57cec5SDimitry Andric G2P.clear(); 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric bool Changed = false; 5070b57cec5SDimitry Andric collectPredicateGPR(MF); 50804eeddc0SDimitry Andric for (const RegisterSubReg &R : PredGPRs) 50904eeddc0SDimitry Andric processPredicateGPR(R); 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric bool Again; 5120b57cec5SDimitry Andric do { 5130b57cec5SDimitry Andric Again = false; 5140b57cec5SDimitry Andric VectOfInst Processed, Copy; 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric Copy = PUsers; 5174824e7fdSDimitry Andric for (MachineInstr *MI : Copy) { 5180b57cec5SDimitry Andric bool Done = convertToPredForm(MI); 5190b57cec5SDimitry Andric if (Done) { 5200b57cec5SDimitry Andric Processed.insert(MI); 5210b57cec5SDimitry Andric Again = true; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric Changed |= Again; 5250b57cec5SDimitry Andric 5260b57cec5SDimitry Andric auto Done = [Processed] (MachineInstr *MI) -> bool { 5270b57cec5SDimitry Andric return Processed.count(MI); 5280b57cec5SDimitry Andric }; 5290b57cec5SDimitry Andric PUsers.remove_if(Done); 5300b57cec5SDimitry Andric } while (Again); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric Changed |= eliminatePredCopies(MF); 5330b57cec5SDimitry Andric return Changed; 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric FunctionPass *llvm::createHexagonGenPredicate() { 5370b57cec5SDimitry Andric return new HexagonGenPredicate(); 5380b57cec5SDimitry Andric } 539