brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.4 KiB · 5344ed8 Raw
515 lines · cpp
1//===- HexagonGenPredicate.cpp --------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "Hexagon.h"10#include "HexagonInstrInfo.h"11#include "HexagonSubtarget.h"12#include "llvm/ADT/SetVector.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/CodeGen/MachineBasicBlock.h"15#include "llvm/CodeGen/MachineDominators.h"16#include "llvm/CodeGen/MachineFunction.h"17#include "llvm/CodeGen/MachineFunctionPass.h"18#include "llvm/CodeGen/MachineInstr.h"19#include "llvm/CodeGen/MachineInstrBuilder.h"20#include "llvm/CodeGen/MachineOperand.h"21#include "llvm/CodeGen/MachineRegisterInfo.h"22#include "llvm/CodeGen/TargetRegisterInfo.h"23#include "llvm/IR/DebugLoc.h"24#include "llvm/InitializePasses.h"25#include "llvm/Pass.h"26#include "llvm/Support/Compiler.h"27#include "llvm/Support/Debug.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Support/raw_ostream.h"30#include <cassert>31#include <iterator>32#include <queue>33 34#define DEBUG_TYPE "gen-pred"35 36using namespace llvm;37 38namespace {39 40using RegSubRegPair = TargetInstrInfo::RegSubRegPair;41 42struct PrintRegister {43  friend raw_ostream &operator<<(raw_ostream &OS, const PrintRegister &PR);44 45  PrintRegister(RegSubRegPair R, const TargetRegisterInfo &I)46      : Reg(R), TRI(I) {}47 48private:49  RegSubRegPair Reg;50  const TargetRegisterInfo &TRI;51};52 53[[maybe_unused]] raw_ostream &operator<<(raw_ostream &OS,54                                         const PrintRegister &PR);55raw_ostream &operator<<(raw_ostream &OS, const PrintRegister &PR) {56  return OS << printReg(PR.Reg.Reg, &PR.TRI, PR.Reg.SubReg);57}58 59  class HexagonGenPredicate : public MachineFunctionPass {60  public:61    static char ID;62 63    HexagonGenPredicate() : MachineFunctionPass(ID) {}64 65    StringRef getPassName() const override {66      return "Hexagon generate predicate operations";67    }68 69    void getAnalysisUsage(AnalysisUsage &AU) const override {70      AU.addRequired<MachineDominatorTreeWrapperPass>();71      AU.addPreserved<MachineDominatorTreeWrapperPass>();72      MachineFunctionPass::getAnalysisUsage(AU);73    }74 75    bool runOnMachineFunction(MachineFunction &MF) override;76 77  private:78    using VectOfInst = SetVector<MachineInstr *>;79    using SetOfReg = SetVector<RegSubRegPair>;80    using RegToRegMap = DenseMap<RegSubRegPair, RegSubRegPair>;81 82    const HexagonInstrInfo *TII = nullptr;83    const HexagonRegisterInfo *TRI = nullptr;84    MachineRegisterInfo *MRI = nullptr;85    SetOfReg PredGPRs;86    VectOfInst PUsers;87    RegToRegMap G2P;88 89    bool isPredReg(Register R);90    void collectPredicateGPR(MachineFunction &MF);91    void processPredicateGPR(const RegSubRegPair &Reg);92    unsigned getPredForm(unsigned Opc);93    bool isConvertibleToPredForm(const MachineInstr *MI);94    bool isScalarCmp(unsigned Opc);95    bool isScalarPred(RegSubRegPair PredReg);96    RegSubRegPair getPredRegFor(const RegSubRegPair &Reg);97    bool convertToPredForm(MachineInstr *MI);98    bool eliminatePredCopies(MachineFunction &MF);99  };100 101} // end anonymous namespace102 103char HexagonGenPredicate::ID = 0;104 105INITIALIZE_PASS_BEGIN(HexagonGenPredicate, "hexagon-gen-pred-pass",106                      "Hexagon generate predicate operations", false, false)107INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)108INITIALIZE_PASS_END(HexagonGenPredicate, "hexagon-gen-pred-pass",109                    "Hexagon generate predicate operations", false, false)110 111bool HexagonGenPredicate::isPredReg(Register R) {112  if (!R.isVirtual())113    return false;114  const TargetRegisterClass *RC = MRI->getRegClass(R);115  return RC == &Hexagon::PredRegsRegClass;116}117 118unsigned HexagonGenPredicate::getPredForm(unsigned Opc) {119  using namespace Hexagon;120 121  switch (Opc) {122    case A2_and:123    case A2_andp:124      return C2_and;125    case A4_andn:126    case A4_andnp:127      return C2_andn;128    case M4_and_and:129      return C4_and_and;130    case M4_and_andn:131      return C4_and_andn;132    case M4_and_or:133      return C4_and_or;134 135    case A2_or:136    case A2_orp:137      return C2_or;138    case A4_orn:139    case A4_ornp:140      return C2_orn;141    case M4_or_and:142      return C4_or_and;143    case M4_or_andn:144      return C4_or_andn;145    case M4_or_or:146      return C4_or_or;147 148    case A2_xor:149    case A2_xorp:150      return C2_xor;151 152    case C2_tfrrp:153      return COPY;154  }155  // The opcode corresponding to 0 is TargetOpcode::PHI. We can use 0 here156  // to denote "none", but we need to make sure that none of the valid opcodes157  // that we return will ever be 0.158  static_assert(PHI == 0, "Use different value for <none>");159  return 0;160}161 162bool HexagonGenPredicate::isConvertibleToPredForm(const MachineInstr *MI) {163  unsigned Opc = MI->getOpcode();164  if (getPredForm(Opc) != 0)165    return true;166 167  // Comparisons against 0 are also convertible. This does not apply to168  // A4_rcmpeqi or A4_rcmpneqi, since they produce values 0 or 1, which169  // may not match the value that the predicate register would have if170  // it was converted to a predicate form.171  switch (Opc) {172    case Hexagon::C2_cmpeqi:173    case Hexagon::C4_cmpneqi:174      if (MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0)175        return true;176      break;177  }178  return false;179}180 181void HexagonGenPredicate::collectPredicateGPR(MachineFunction &MF) {182  for (MachineBasicBlock &B : MF) {183    for (MachineInstr &MI : B) {184      unsigned Opc = MI.getOpcode();185      switch (Opc) {186        case Hexagon::C2_tfrpr:187        case TargetOpcode::COPY:188          if (isPredReg(MI.getOperand(1).getReg())) {189            RegSubRegPair RD = getRegSubRegPair(MI.getOperand(0));190            if (RD.Reg.isVirtual())191              PredGPRs.insert(RD);192          }193          break;194      }195    }196  }197}198 199void HexagonGenPredicate::processPredicateGPR(const RegSubRegPair &Reg) {200  LLVM_DEBUG(dbgs() << __func__ << ": " << printReg(Reg.Reg, TRI, Reg.SubReg)201                    << "\n");202  using use_iterator = MachineRegisterInfo::use_iterator;203 204  use_iterator I = MRI->use_begin(Reg.Reg), E = MRI->use_end();205  if (I == E) {206    LLVM_DEBUG(dbgs() << "Dead reg: " << printReg(Reg.Reg, TRI, Reg.SubReg)207                      << '\n');208    MachineInstr *DefI = MRI->getVRegDef(Reg.Reg);209    DefI->eraseFromParent();210    return;211  }212 213  for (; I != E; ++I) {214    MachineInstr *UseI = I->getParent();215    if (isConvertibleToPredForm(UseI))216      PUsers.insert(UseI);217  }218}219 220RegSubRegPair HexagonGenPredicate::getPredRegFor(const RegSubRegPair &Reg) {221  // Create a predicate register for a given Reg. The newly created register222  // will have its value copied from Reg, so that it can be later used as223  // an operand in other instructions.224  assert(Reg.Reg.isVirtual());225  RegToRegMap::iterator F = G2P.find(Reg);226  if (F != G2P.end())227    return F->second;228 229  LLVM_DEBUG(dbgs() << __func__ << ": " << PrintRegister(Reg, *TRI));230  MachineInstr *DefI = MRI->getVRegDef(Reg.Reg);231  assert(DefI);232  unsigned Opc = DefI->getOpcode();233  if (Opc == Hexagon::C2_tfrpr || Opc == TargetOpcode::COPY) {234    assert(DefI->getOperand(0).isDef() && DefI->getOperand(1).isUse());235    RegSubRegPair PR = getRegSubRegPair(DefI->getOperand(1));236    G2P.insert(std::make_pair(Reg, PR));237    LLVM_DEBUG(dbgs() << " -> " << PrintRegister(PR, *TRI) << '\n');238    return PR;239  }240 241  MachineBasicBlock &B = *DefI->getParent();242  DebugLoc DL = DefI->getDebugLoc();243  const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;244  Register NewPR = MRI->createVirtualRegister(PredRC);245 246  // For convertible instructions, do not modify them, so that they can247  // be converted later.  Generate a copy from Reg to NewPR.248  if (isConvertibleToPredForm(DefI)) {249    MachineBasicBlock::iterator DefIt = DefI;250    BuildMI(B, std::next(DefIt), DL, TII->get(TargetOpcode::COPY), NewPR)251        .addReg(Reg.Reg, 0, Reg.SubReg);252    G2P.insert(std::make_pair(Reg, RegSubRegPair(NewPR)));253    LLVM_DEBUG(dbgs() << " -> !" << PrintRegister(RegSubRegPair(NewPR), *TRI)254                      << '\n');255    return RegSubRegPair(NewPR);256  }257 258  llvm_unreachable("Invalid argument");259}260 261bool HexagonGenPredicate::isScalarCmp(unsigned Opc) {262  switch (Opc) {263    case Hexagon::C2_cmpeq:264    case Hexagon::C2_cmpgt:265    case Hexagon::C2_cmpgtu:266    case Hexagon::C2_cmpeqp:267    case Hexagon::C2_cmpgtp:268    case Hexagon::C2_cmpgtup:269    case Hexagon::C2_cmpeqi:270    case Hexagon::C2_cmpgti:271    case Hexagon::C2_cmpgtui:272    case Hexagon::C2_cmpgei:273    case Hexagon::C2_cmpgeui:274    case Hexagon::C4_cmpneqi:275    case Hexagon::C4_cmpltei:276    case Hexagon::C4_cmplteui:277    case Hexagon::C4_cmpneq:278    case Hexagon::C4_cmplte:279    case Hexagon::C4_cmplteu:280    case Hexagon::A4_cmpbeq:281    case Hexagon::A4_cmpbeqi:282    case Hexagon::A4_cmpbgtu:283    case Hexagon::A4_cmpbgtui:284    case Hexagon::A4_cmpbgt:285    case Hexagon::A4_cmpbgti:286    case Hexagon::A4_cmpheq:287    case Hexagon::A4_cmphgt:288    case Hexagon::A4_cmphgtu:289    case Hexagon::A4_cmpheqi:290    case Hexagon::A4_cmphgti:291    case Hexagon::A4_cmphgtui:292      return true;293  }294  return false;295}296 297bool HexagonGenPredicate::isScalarPred(RegSubRegPair PredReg) {298  std::queue<RegSubRegPair> WorkQ;299  WorkQ.push(PredReg);300 301  while (!WorkQ.empty()) {302    RegSubRegPair PR = WorkQ.front();303    WorkQ.pop();304    const MachineInstr *DefI = MRI->getVRegDef(PR.Reg);305    if (!DefI)306      return false;307    unsigned DefOpc = DefI->getOpcode();308    switch (DefOpc) {309      case TargetOpcode::COPY: {310        const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;311        if (MRI->getRegClass(PR.Reg) != PredRC)312          return false;313        // If it is a copy between two predicate registers, fall through.314        [[fallthrough]];315      }316      case Hexagon::C2_and:317      case Hexagon::C2_andn:318      case Hexagon::C4_and_and:319      case Hexagon::C4_and_andn:320      case Hexagon::C4_and_or:321      case Hexagon::C2_or:322      case Hexagon::C2_orn:323      case Hexagon::C4_or_and:324      case Hexagon::C4_or_andn:325      case Hexagon::C4_or_or:326      case Hexagon::C4_or_orn:327      case Hexagon::C2_xor:328        // Add operands to the queue.329        for (const MachineOperand &MO : DefI->operands())330          if (MO.isReg() && MO.isUse())331            WorkQ.push(RegSubRegPair(MO.getReg()));332        break;333 334      // All non-vector compares are ok, everything else is bad.335      default:336        return isScalarCmp(DefOpc);337    }338  }339 340  return true;341}342 343bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) {344  LLVM_DEBUG(dbgs() << __func__ << ": " << MI << " " << *MI);345 346  unsigned Opc = MI->getOpcode();347  assert(isConvertibleToPredForm(MI));348  unsigned NumOps = MI->getNumOperands();349  for (unsigned i = 0; i < NumOps; ++i) {350    MachineOperand &MO = MI->getOperand(i);351    if (!MO.isReg() || !MO.isUse())352      continue;353    RegSubRegPair Reg(getRegSubRegPair(MO));354    if (Reg.SubReg && Reg.SubReg != Hexagon::isub_lo)355      return false;356    if (!PredGPRs.count(Reg))357      return false;358  }359 360  MachineBasicBlock &B = *MI->getParent();361  DebugLoc DL = MI->getDebugLoc();362 363  unsigned NewOpc = getPredForm(Opc);364  // Special case for comparisons against 0.365  if (NewOpc == 0) {366    switch (Opc) {367      case Hexagon::C2_cmpeqi:368        NewOpc = Hexagon::C2_not;369        break;370      case Hexagon::C4_cmpneqi:371        NewOpc = TargetOpcode::COPY;372        break;373      default:374        return false;375    }376 377    // If it's a scalar predicate register, then all bits in it are378    // the same. Otherwise, to determine whether all bits are 0 or not379    // we would need to use any8.380    RegSubRegPair PR = getPredRegFor(getRegSubRegPair(MI->getOperand(1)));381    if (!isScalarPred(PR))382      return false;383    // This will skip the immediate argument when creating the predicate384    // version instruction.385    NumOps = 2;386  }387 388  // Check that def is in operand #0.389  MachineOperand &Op0 = MI->getOperand(0);390  assert(Op0.isDef());391  RegSubRegPair OutR(getRegSubRegPair(Op0));392 393  // Don't use getPredRegFor, since it will create an association between394  // the argument and a created predicate register (i.e. it will insert a395  // copy if a new predicate register is created).396  const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;397  RegSubRegPair NewPR = MRI->createVirtualRegister(PredRC);398  MachineInstrBuilder MIB = BuildMI(B, MI, DL, TII->get(NewOpc), NewPR.Reg);399 400  // Add predicate counterparts of the GPRs.401  for (unsigned i = 1; i < NumOps; ++i) {402    RegSubRegPair GPR = getRegSubRegPair(MI->getOperand(i));403    RegSubRegPair Pred = getPredRegFor(GPR);404    MIB.addReg(Pred.Reg, 0, Pred.SubReg);405  }406  LLVM_DEBUG(dbgs() << "generated: " << *MIB);407 408  // Generate a copy-out: NewGPR = NewPR, and replace all uses of OutR409  // with NewGPR.410  const TargetRegisterClass *RC = MRI->getRegClass(OutR.Reg);411  Register NewOutR = MRI->createVirtualRegister(RC);412  BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), NewOutR)413      .addReg(NewPR.Reg, 0, NewPR.SubReg);414  MRI->replaceRegWith(OutR.Reg, NewOutR);415  MI->eraseFromParent();416 417  // If the processed instruction was C2_tfrrp (i.e. Rn = Pm; Pk = Rn),418  // then the output will be a predicate register.  Do not visit the419  // users of it.420  if (!isPredReg(NewOutR)) {421    RegSubRegPair R(NewOutR);422    PredGPRs.insert(R);423    processPredicateGPR(R);424  }425  return true;426}427 428bool HexagonGenPredicate::eliminatePredCopies(MachineFunction &MF) {429  LLVM_DEBUG(dbgs() << __func__ << "\n");430  const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;431  bool Changed = false;432  VectOfInst Erase;433 434  // First, replace copies435  //   IntR = PredR1436  //   PredR2 = IntR437  // with438  //   PredR2 = PredR1439  // Such sequences can be generated when a copy-into-pred is generated from440  // a gpr register holding a result of a convertible instruction. After441  // the convertible instruction is converted, its predicate result will be442  // copied back into the original gpr.443 444  for (MachineBasicBlock &MBB : MF) {445    for (MachineInstr &MI : MBB) {446      if (MI.getOpcode() != TargetOpcode::COPY)447        continue;448      RegSubRegPair DR = getRegSubRegPair(MI.getOperand(0));449      RegSubRegPair SR = getRegSubRegPair(MI.getOperand(1));450      if (!DR.Reg.isVirtual())451        continue;452      if (!SR.Reg.isVirtual())453        continue;454      if (MRI->getRegClass(DR.Reg) != PredRC)455        continue;456      if (MRI->getRegClass(SR.Reg) != PredRC)457        continue;458      assert(!DR.SubReg && !SR.SubReg && "Unexpected subregister");459      MRI->replaceRegWith(DR.Reg, SR.Reg);460      Erase.insert(&MI);461      Changed = true;462    }463  }464 465  for (MachineInstr *MI : Erase)466    MI->eraseFromParent();467 468  return Changed;469}470 471bool HexagonGenPredicate::runOnMachineFunction(MachineFunction &MF) {472  if (skipFunction(MF.getFunction()))473    return false;474 475  TII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo();476  TRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();477  MRI = &MF.getRegInfo();478  PredGPRs.clear();479  PUsers.clear();480  G2P.clear();481 482  bool Changed = false;483  collectPredicateGPR(MF);484  for (const RegSubRegPair &R : PredGPRs)485    processPredicateGPR(R);486 487  bool Again;488  do {489    Again = false;490    VectOfInst Processed, Copy;491 492    Copy = PUsers;493    for (MachineInstr *MI : Copy) {494      bool Done = convertToPredForm(MI);495      if (Done) {496        Processed.insert(MI);497        Again = true;498      }499    }500    Changed |= Again;501 502    auto Done = [Processed] (MachineInstr *MI) -> bool {503      return Processed.count(MI);504    };505    PUsers.remove_if(Done);506  } while (Again);507 508  Changed |= eliminatePredCopies(MF);509  return Changed;510}511 512FunctionPass *llvm::createHexagonGenPredicate() {513  return new HexagonGenPredicate();514}515