Path: blob/main/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp
35294 views
//===- HexagonGenPredicate.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "HexagonInstrInfo.h"9#include "HexagonSubtarget.h"10#include "llvm/ADT/SetVector.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/CodeGen/MachineBasicBlock.h"13#include "llvm/CodeGen/MachineDominators.h"14#include "llvm/CodeGen/MachineFunction.h"15#include "llvm/CodeGen/MachineFunctionPass.h"16#include "llvm/CodeGen/MachineInstr.h"17#include "llvm/CodeGen/MachineInstrBuilder.h"18#include "llvm/CodeGen/MachineOperand.h"19#include "llvm/CodeGen/MachineRegisterInfo.h"20#include "llvm/CodeGen/TargetRegisterInfo.h"21#include "llvm/IR/DebugLoc.h"22#include "llvm/InitializePasses.h"23#include "llvm/Pass.h"24#include "llvm/Support/Compiler.h"25#include "llvm/Support/Debug.h"26#include "llvm/Support/ErrorHandling.h"27#include "llvm/Support/raw_ostream.h"28#include <cassert>29#include <iterator>30#include <map>31#include <queue>32#include <set>33#include <utility>3435#define DEBUG_TYPE "gen-pred"3637using namespace llvm;3839namespace llvm {4041void initializeHexagonGenPredicatePass(PassRegistry& Registry);42FunctionPass *createHexagonGenPredicate();4344} // end namespace llvm4546namespace {4748// FIXME: Use TargetInstrInfo::RegSubRegPair49struct RegisterSubReg {50Register R;51unsigned S;5253RegisterSubReg(unsigned r = 0, unsigned s = 0) : R(r), S(s) {}54RegisterSubReg(const MachineOperand &MO) : R(MO.getReg()), S(MO.getSubReg()) {}55RegisterSubReg(const Register &Reg) : R(Reg), S(0) {}5657bool operator== (const RegisterSubReg &Reg) const {58return R == Reg.R && S == Reg.S;59}6061bool operator< (const RegisterSubReg &Reg) const {62return R < Reg.R || (R == Reg.R && S < Reg.S);63}64};6566struct PrintRegister {67friend raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR);6869PrintRegister(RegisterSubReg R, const TargetRegisterInfo &I) : Reg(R), TRI(I) {}7071private:72RegisterSubReg Reg;73const TargetRegisterInfo &TRI;74};7576raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR)77LLVM_ATTRIBUTE_UNUSED;78raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR) {79return OS << printReg(PR.Reg.R, &PR.TRI, PR.Reg.S);80}8182class HexagonGenPredicate : public MachineFunctionPass {83public:84static char ID;8586HexagonGenPredicate() : MachineFunctionPass(ID) {87initializeHexagonGenPredicatePass(*PassRegistry::getPassRegistry());88}8990StringRef getPassName() const override {91return "Hexagon generate predicate operations";92}9394void getAnalysisUsage(AnalysisUsage &AU) const override {95AU.addRequired<MachineDominatorTreeWrapperPass>();96AU.addPreserved<MachineDominatorTreeWrapperPass>();97MachineFunctionPass::getAnalysisUsage(AU);98}99100bool runOnMachineFunction(MachineFunction &MF) override;101102private:103using VectOfInst = SetVector<MachineInstr *>;104using SetOfReg = std::set<RegisterSubReg>;105using RegToRegMap = std::map<RegisterSubReg, RegisterSubReg>;106107const HexagonInstrInfo *TII = nullptr;108const HexagonRegisterInfo *TRI = nullptr;109MachineRegisterInfo *MRI = nullptr;110SetOfReg PredGPRs;111VectOfInst PUsers;112RegToRegMap G2P;113114bool isPredReg(Register R);115void collectPredicateGPR(MachineFunction &MF);116void processPredicateGPR(const RegisterSubReg &Reg);117unsigned getPredForm(unsigned Opc);118bool isConvertibleToPredForm(const MachineInstr *MI);119bool isScalarCmp(unsigned Opc);120bool isScalarPred(RegisterSubReg PredReg);121RegisterSubReg getPredRegFor(const RegisterSubReg &Reg);122bool convertToPredForm(MachineInstr *MI);123bool eliminatePredCopies(MachineFunction &MF);124};125126} // end anonymous namespace127128char HexagonGenPredicate::ID = 0;129130INITIALIZE_PASS_BEGIN(HexagonGenPredicate, "hexagon-gen-pred",131"Hexagon generate predicate operations", false, false)132INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)133INITIALIZE_PASS_END(HexagonGenPredicate, "hexagon-gen-pred",134"Hexagon generate predicate operations", false, false)135136bool HexagonGenPredicate::isPredReg(Register R) {137if (!R.isVirtual())138return false;139const TargetRegisterClass *RC = MRI->getRegClass(R);140return RC == &Hexagon::PredRegsRegClass;141}142143unsigned HexagonGenPredicate::getPredForm(unsigned Opc) {144using namespace Hexagon;145146switch (Opc) {147case A2_and:148case A2_andp:149return C2_and;150case A4_andn:151case A4_andnp:152return C2_andn;153case M4_and_and:154return C4_and_and;155case M4_and_andn:156return C4_and_andn;157case M4_and_or:158return C4_and_or;159160case A2_or:161case A2_orp:162return C2_or;163case A4_orn:164case A4_ornp:165return C2_orn;166case M4_or_and:167return C4_or_and;168case M4_or_andn:169return C4_or_andn;170case M4_or_or:171return C4_or_or;172173case A2_xor:174case A2_xorp:175return C2_xor;176177case C2_tfrrp:178return COPY;179}180// The opcode corresponding to 0 is TargetOpcode::PHI. We can use 0 here181// to denote "none", but we need to make sure that none of the valid opcodes182// that we return will ever be 0.183static_assert(PHI == 0, "Use different value for <none>");184return 0;185}186187bool HexagonGenPredicate::isConvertibleToPredForm(const MachineInstr *MI) {188unsigned Opc = MI->getOpcode();189if (getPredForm(Opc) != 0)190return true;191192// Comparisons against 0 are also convertible. This does not apply to193// A4_rcmpeqi or A4_rcmpneqi, since they produce values 0 or 1, which194// may not match the value that the predicate register would have if195// it was converted to a predicate form.196switch (Opc) {197case Hexagon::C2_cmpeqi:198case Hexagon::C4_cmpneqi:199if (MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0)200return true;201break;202}203return false;204}205206void HexagonGenPredicate::collectPredicateGPR(MachineFunction &MF) {207for (MachineBasicBlock &B : MF) {208for (MachineInstr &MI : B) {209unsigned Opc = MI.getOpcode();210switch (Opc) {211case Hexagon::C2_tfrpr:212case TargetOpcode::COPY:213if (isPredReg(MI.getOperand(1).getReg())) {214RegisterSubReg RD = MI.getOperand(0);215if (RD.R.isVirtual())216PredGPRs.insert(RD);217}218break;219}220}221}222}223224void HexagonGenPredicate::processPredicateGPR(const RegisterSubReg &Reg) {225LLVM_DEBUG(dbgs() << __func__ << ": " << printReg(Reg.R, TRI, Reg.S) << "\n");226using use_iterator = MachineRegisterInfo::use_iterator;227228use_iterator I = MRI->use_begin(Reg.R), E = MRI->use_end();229if (I == E) {230LLVM_DEBUG(dbgs() << "Dead reg: " << printReg(Reg.R, TRI, Reg.S) << '\n');231MachineInstr *DefI = MRI->getVRegDef(Reg.R);232DefI->eraseFromParent();233return;234}235236for (; I != E; ++I) {237MachineInstr *UseI = I->getParent();238if (isConvertibleToPredForm(UseI))239PUsers.insert(UseI);240}241}242243RegisterSubReg HexagonGenPredicate::getPredRegFor(const RegisterSubReg &Reg) {244// Create a predicate register for a given Reg. The newly created register245// will have its value copied from Reg, so that it can be later used as246// an operand in other instructions.247assert(Reg.R.isVirtual());248RegToRegMap::iterator F = G2P.find(Reg);249if (F != G2P.end())250return F->second;251252LLVM_DEBUG(dbgs() << __func__ << ": " << PrintRegister(Reg, *TRI));253MachineInstr *DefI = MRI->getVRegDef(Reg.R);254assert(DefI);255unsigned Opc = DefI->getOpcode();256if (Opc == Hexagon::C2_tfrpr || Opc == TargetOpcode::COPY) {257assert(DefI->getOperand(0).isDef() && DefI->getOperand(1).isUse());258RegisterSubReg PR = DefI->getOperand(1);259G2P.insert(std::make_pair(Reg, PR));260LLVM_DEBUG(dbgs() << " -> " << PrintRegister(PR, *TRI) << '\n');261return PR;262}263264MachineBasicBlock &B = *DefI->getParent();265DebugLoc DL = DefI->getDebugLoc();266const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;267Register NewPR = MRI->createVirtualRegister(PredRC);268269// For convertible instructions, do not modify them, so that they can270// be converted later. Generate a copy from Reg to NewPR.271if (isConvertibleToPredForm(DefI)) {272MachineBasicBlock::iterator DefIt = DefI;273BuildMI(B, std::next(DefIt), DL, TII->get(TargetOpcode::COPY), NewPR)274.addReg(Reg.R, 0, Reg.S);275G2P.insert(std::make_pair(Reg, RegisterSubReg(NewPR)));276LLVM_DEBUG(dbgs() << " -> !" << PrintRegister(RegisterSubReg(NewPR), *TRI)277<< '\n');278return RegisterSubReg(NewPR);279}280281llvm_unreachable("Invalid argument");282}283284bool HexagonGenPredicate::isScalarCmp(unsigned Opc) {285switch (Opc) {286case Hexagon::C2_cmpeq:287case Hexagon::C2_cmpgt:288case Hexagon::C2_cmpgtu:289case Hexagon::C2_cmpeqp:290case Hexagon::C2_cmpgtp:291case Hexagon::C2_cmpgtup:292case Hexagon::C2_cmpeqi:293case Hexagon::C2_cmpgti:294case Hexagon::C2_cmpgtui:295case Hexagon::C2_cmpgei:296case Hexagon::C2_cmpgeui:297case Hexagon::C4_cmpneqi:298case Hexagon::C4_cmpltei:299case Hexagon::C4_cmplteui:300case Hexagon::C4_cmpneq:301case Hexagon::C4_cmplte:302case Hexagon::C4_cmplteu:303case Hexagon::A4_cmpbeq:304case Hexagon::A4_cmpbeqi:305case Hexagon::A4_cmpbgtu:306case Hexagon::A4_cmpbgtui:307case Hexagon::A4_cmpbgt:308case Hexagon::A4_cmpbgti:309case Hexagon::A4_cmpheq:310case Hexagon::A4_cmphgt:311case Hexagon::A4_cmphgtu:312case Hexagon::A4_cmpheqi:313case Hexagon::A4_cmphgti:314case Hexagon::A4_cmphgtui:315return true;316}317return false;318}319320bool HexagonGenPredicate::isScalarPred(RegisterSubReg PredReg) {321std::queue<RegisterSubReg> WorkQ;322WorkQ.push(PredReg);323324while (!WorkQ.empty()) {325RegisterSubReg PR = WorkQ.front();326WorkQ.pop();327const MachineInstr *DefI = MRI->getVRegDef(PR.R);328if (!DefI)329return false;330unsigned DefOpc = DefI->getOpcode();331switch (DefOpc) {332case TargetOpcode::COPY: {333const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;334if (MRI->getRegClass(PR.R) != PredRC)335return false;336// If it is a copy between two predicate registers, fall through.337[[fallthrough]];338}339case Hexagon::C2_and:340case Hexagon::C2_andn:341case Hexagon::C4_and_and:342case Hexagon::C4_and_andn:343case Hexagon::C4_and_or:344case Hexagon::C2_or:345case Hexagon::C2_orn:346case Hexagon::C4_or_and:347case Hexagon::C4_or_andn:348case Hexagon::C4_or_or:349case Hexagon::C4_or_orn:350case Hexagon::C2_xor:351// Add operands to the queue.352for (const MachineOperand &MO : DefI->operands())353if (MO.isReg() && MO.isUse())354WorkQ.push(RegisterSubReg(MO.getReg()));355break;356357// All non-vector compares are ok, everything else is bad.358default:359return isScalarCmp(DefOpc);360}361}362363return true;364}365366bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) {367LLVM_DEBUG(dbgs() << __func__ << ": " << MI << " " << *MI);368369unsigned Opc = MI->getOpcode();370assert(isConvertibleToPredForm(MI));371unsigned NumOps = MI->getNumOperands();372for (unsigned i = 0; i < NumOps; ++i) {373MachineOperand &MO = MI->getOperand(i);374if (!MO.isReg() || !MO.isUse())375continue;376RegisterSubReg Reg(MO);377if (Reg.S && Reg.S != Hexagon::isub_lo)378return false;379if (!PredGPRs.count(Reg))380return false;381}382383MachineBasicBlock &B = *MI->getParent();384DebugLoc DL = MI->getDebugLoc();385386unsigned NewOpc = getPredForm(Opc);387// Special case for comparisons against 0.388if (NewOpc == 0) {389switch (Opc) {390case Hexagon::C2_cmpeqi:391NewOpc = Hexagon::C2_not;392break;393case Hexagon::C4_cmpneqi:394NewOpc = TargetOpcode::COPY;395break;396default:397return false;398}399400// If it's a scalar predicate register, then all bits in it are401// the same. Otherwise, to determine whether all bits are 0 or not402// we would need to use any8.403RegisterSubReg PR = getPredRegFor(MI->getOperand(1));404if (!isScalarPred(PR))405return false;406// This will skip the immediate argument when creating the predicate407// version instruction.408NumOps = 2;409}410411// Check that def is in operand #0.412MachineOperand &Op0 = MI->getOperand(0);413assert(Op0.isDef());414RegisterSubReg OutR(Op0);415416// Don't use getPredRegFor, since it will create an association between417// the argument and a created predicate register (i.e. it will insert a418// copy if a new predicate register is created).419const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;420RegisterSubReg NewPR = MRI->createVirtualRegister(PredRC);421MachineInstrBuilder MIB = BuildMI(B, MI, DL, TII->get(NewOpc), NewPR.R);422423// Add predicate counterparts of the GPRs.424for (unsigned i = 1; i < NumOps; ++i) {425RegisterSubReg GPR = MI->getOperand(i);426RegisterSubReg Pred = getPredRegFor(GPR);427MIB.addReg(Pred.R, 0, Pred.S);428}429LLVM_DEBUG(dbgs() << "generated: " << *MIB);430431// Generate a copy-out: NewGPR = NewPR, and replace all uses of OutR432// with NewGPR.433const TargetRegisterClass *RC = MRI->getRegClass(OutR.R);434Register NewOutR = MRI->createVirtualRegister(RC);435BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), NewOutR)436.addReg(NewPR.R, 0, NewPR.S);437MRI->replaceRegWith(OutR.R, NewOutR);438MI->eraseFromParent();439440// If the processed instruction was C2_tfrrp (i.e. Rn = Pm; Pk = Rn),441// then the output will be a predicate register. Do not visit the442// users of it.443if (!isPredReg(NewOutR)) {444RegisterSubReg R(NewOutR);445PredGPRs.insert(R);446processPredicateGPR(R);447}448return true;449}450451bool HexagonGenPredicate::eliminatePredCopies(MachineFunction &MF) {452LLVM_DEBUG(dbgs() << __func__ << "\n");453const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;454bool Changed = false;455VectOfInst Erase;456457// First, replace copies458// IntR = PredR1459// PredR2 = IntR460// with461// PredR2 = PredR1462// Such sequences can be generated when a copy-into-pred is generated from463// a gpr register holding a result of a convertible instruction. After464// the convertible instruction is converted, its predicate result will be465// copied back into the original gpr.466467for (MachineBasicBlock &MBB : MF) {468for (MachineInstr &MI : MBB) {469if (MI.getOpcode() != TargetOpcode::COPY)470continue;471RegisterSubReg DR = MI.getOperand(0);472RegisterSubReg SR = MI.getOperand(1);473if (!DR.R.isVirtual())474continue;475if (!SR.R.isVirtual())476continue;477if (MRI->getRegClass(DR.R) != PredRC)478continue;479if (MRI->getRegClass(SR.R) != PredRC)480continue;481assert(!DR.S && !SR.S && "Unexpected subregister");482MRI->replaceRegWith(DR.R, SR.R);483Erase.insert(&MI);484Changed = true;485}486}487488for (MachineInstr *MI : Erase)489MI->eraseFromParent();490491return Changed;492}493494bool HexagonGenPredicate::runOnMachineFunction(MachineFunction &MF) {495if (skipFunction(MF.getFunction()))496return false;497498TII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo();499TRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();500MRI = &MF.getRegInfo();501PredGPRs.clear();502PUsers.clear();503G2P.clear();504505bool Changed = false;506collectPredicateGPR(MF);507for (const RegisterSubReg &R : PredGPRs)508processPredicateGPR(R);509510bool Again;511do {512Again = false;513VectOfInst Processed, Copy;514515Copy = PUsers;516for (MachineInstr *MI : Copy) {517bool Done = convertToPredForm(MI);518if (Done) {519Processed.insert(MI);520Again = true;521}522}523Changed |= Again;524525auto Done = [Processed] (MachineInstr *MI) -> bool {526return Processed.count(MI);527};528PUsers.remove_if(Done);529} while (Again);530531Changed |= eliminatePredCopies(MF);532return Changed;533}534535FunctionPass *llvm::createHexagonGenPredicate() {536return new HexagonGenPredicate();537}538539540