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