Path: blob/main/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
35294 views
//===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===//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//===----------------------------------------------------------------------===//7//8// This pass:9// (1) tries to remove compares if CC already contains the required information10// (2) fuses compares and branches into COMPARE AND BRANCH instructions11//12//===----------------------------------------------------------------------===//1314#include "SystemZ.h"15#include "SystemZInstrInfo.h"16#include "SystemZTargetMachine.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/ADT/Statistic.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/CodeGen/LiveRegUnits.h"21#include "llvm/CodeGen/MachineBasicBlock.h"22#include "llvm/CodeGen/MachineFunction.h"23#include "llvm/CodeGen/MachineFunctionPass.h"24#include "llvm/CodeGen/MachineInstr.h"25#include "llvm/CodeGen/MachineInstrBuilder.h"26#include "llvm/CodeGen/MachineOperand.h"27#include "llvm/CodeGen/TargetRegisterInfo.h"28#include "llvm/CodeGen/TargetSubtargetInfo.h"29#include "llvm/MC/MCInstrDesc.h"30#include <cassert>31#include <cstdint>3233using namespace llvm;3435#define DEBUG_TYPE "systemz-elim-compare"3637STATISTIC(BranchOnCounts, "Number of branch-on-count instructions");38STATISTIC(LoadAndTraps, "Number of load-and-trap instructions");39STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");40STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");4142namespace {4344// Represents the references to a particular register in one or more45// instructions.46struct Reference {47Reference() = default;4849Reference &operator|=(const Reference &Other) {50Def |= Other.Def;51Use |= Other.Use;52return *this;53}5455explicit operator bool() const { return Def || Use; }5657// True if the register is defined or used in some form, either directly or58// via a sub- or super-register.59bool Def = false;60bool Use = false;61};6263class SystemZElimCompare : public MachineFunctionPass {64public:65static char ID;6667SystemZElimCompare() : MachineFunctionPass(ID) {68initializeSystemZElimComparePass(*PassRegistry::getPassRegistry());69}7071bool processBlock(MachineBasicBlock &MBB);72bool runOnMachineFunction(MachineFunction &F) override;7374MachineFunctionProperties getRequiredProperties() const override {75return MachineFunctionProperties().set(76MachineFunctionProperties::Property::NoVRegs);77}7879private:80Reference getRegReferences(MachineInstr &MI, unsigned Reg);81bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare,82SmallVectorImpl<MachineInstr *> &CCUsers);83bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare,84SmallVectorImpl<MachineInstr *> &CCUsers);85bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare,86SmallVectorImpl<MachineInstr *> &CCUsers);87bool convertToLogical(MachineInstr &MI, MachineInstr &Compare,88SmallVectorImpl<MachineInstr *> &CCUsers);89bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,90SmallVectorImpl<MachineInstr *> &CCUsers,91unsigned ConvOpc = 0);92bool optimizeCompareZero(MachineInstr &Compare,93SmallVectorImpl<MachineInstr *> &CCUsers);94bool fuseCompareOperations(MachineInstr &Compare,95SmallVectorImpl<MachineInstr *> &CCUsers);9697const SystemZInstrInfo *TII = nullptr;98const TargetRegisterInfo *TRI = nullptr;99};100101char SystemZElimCompare::ID = 0;102103} // end anonymous namespace104105INITIALIZE_PASS(SystemZElimCompare, DEBUG_TYPE,106"SystemZ Comparison Elimination", false, false)107108// Returns true if MI is an instruction whose output equals the value in Reg.109static bool preservesValueOf(MachineInstr &MI, unsigned Reg) {110switch (MI.getOpcode()) {111case SystemZ::LR:112case SystemZ::LGR:113case SystemZ::LGFR:114case SystemZ::LTR:115case SystemZ::LTGR:116case SystemZ::LTGFR:117if (MI.getOperand(1).getReg() == Reg)118return true;119}120121return false;122}123124// Return true if any CC result of MI would (perhaps after conversion)125// reflect the value of Reg.126static bool resultTests(MachineInstr &MI, unsigned Reg) {127if (MI.getNumOperands() > 0 && MI.getOperand(0).isReg() &&128MI.getOperand(0).isDef() && MI.getOperand(0).getReg() == Reg)129return true;130131return (preservesValueOf(MI, Reg));132}133134// Describe the references to Reg or any of its aliases in MI.135Reference SystemZElimCompare::getRegReferences(MachineInstr &MI, unsigned Reg) {136Reference Ref;137if (MI.isDebugInstr())138return Ref;139140for (const MachineOperand &MO : MI.operands()) {141if (MO.isReg()) {142if (Register MOReg = MO.getReg()) {143if (TRI->regsOverlap(MOReg, Reg)) {144if (MO.isUse())145Ref.Use = true;146else if (MO.isDef())147Ref.Def = true;148}149}150}151}152return Ref;153}154155// Return true if this is a load and test which can be optimized the156// same way as compare instruction.157static bool isLoadAndTestAsCmp(MachineInstr &MI) {158// If we during isel used a load-and-test as a compare with 0, the159// def operand is dead.160return (MI.getOpcode() == SystemZ::LTEBR ||161MI.getOpcode() == SystemZ::LTDBR ||162MI.getOpcode() == SystemZ::LTXBR) &&163MI.getOperand(0).isDead();164}165166// Return the source register of Compare, which is the unknown value167// being tested.168static unsigned getCompareSourceReg(MachineInstr &Compare) {169unsigned reg = 0;170if (Compare.isCompare())171reg = Compare.getOperand(0).getReg();172else if (isLoadAndTestAsCmp(Compare))173reg = Compare.getOperand(1).getReg();174assert(reg);175176return reg;177}178179// Compare compares the result of MI against zero. If MI is an addition180// of -1 and if CCUsers is a single branch on nonzero, eliminate the addition181// and convert the branch to a BRCT(G) or BRCTH. Return true on success.182bool SystemZElimCompare::convertToBRCT(183MachineInstr &MI, MachineInstr &Compare,184SmallVectorImpl<MachineInstr *> &CCUsers) {185// Check whether we have an addition of -1.186unsigned Opcode = MI.getOpcode();187unsigned BRCT;188if (Opcode == SystemZ::AHI)189BRCT = SystemZ::BRCT;190else if (Opcode == SystemZ::AGHI)191BRCT = SystemZ::BRCTG;192else if (Opcode == SystemZ::AIH)193BRCT = SystemZ::BRCTH;194else195return false;196if (MI.getOperand(2).getImm() != -1)197return false;198199// Check whether we have a single JLH.200if (CCUsers.size() != 1)201return false;202MachineInstr *Branch = CCUsers[0];203if (Branch->getOpcode() != SystemZ::BRC ||204Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||205Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_NE)206return false;207208// We already know that there are no references to the register between209// MI and Compare. Make sure that there are also no references between210// Compare and Branch.211unsigned SrcReg = getCompareSourceReg(Compare);212MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;213for (++MBBI; MBBI != MBBE; ++MBBI)214if (getRegReferences(*MBBI, SrcReg))215return false;216217// The transformation is OK. Rebuild Branch as a BRCT(G) or BRCTH.218MachineOperand Target(Branch->getOperand(2));219while (Branch->getNumOperands())220Branch->removeOperand(0);221Branch->setDesc(TII->get(BRCT));222MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);223MIB.add(MI.getOperand(0)).add(MI.getOperand(1)).add(Target);224// Add a CC def to BRCT(G), since we may have to split them again if the225// branch displacement overflows. BRCTH has a 32-bit displacement, so226// this is not necessary there.227if (BRCT != SystemZ::BRCTH)228MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);229MI.eraseFromParent();230return true;231}232233// Compare compares the result of MI against zero. If MI is a suitable load234// instruction and if CCUsers is a single conditional trap on zero, eliminate235// the load and convert the branch to a load-and-trap. Return true on success.236bool SystemZElimCompare::convertToLoadAndTrap(237MachineInstr &MI, MachineInstr &Compare,238SmallVectorImpl<MachineInstr *> &CCUsers) {239unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode());240if (!LATOpcode)241return false;242243// Check whether we have a single CondTrap that traps on zero.244if (CCUsers.size() != 1)245return false;246MachineInstr *Branch = CCUsers[0];247if (Branch->getOpcode() != SystemZ::CondTrap ||248Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||249Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ)250return false;251252// We already know that there are no references to the register between253// MI and Compare. Make sure that there are also no references between254// Compare and Branch.255unsigned SrcReg = getCompareSourceReg(Compare);256MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;257for (++MBBI; MBBI != MBBE; ++MBBI)258if (getRegReferences(*MBBI, SrcReg))259return false;260261// The transformation is OK. Rebuild Branch as a load-and-trap.262while (Branch->getNumOperands())263Branch->removeOperand(0);264Branch->setDesc(TII->get(LATOpcode));265MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)266.add(MI.getOperand(0))267.add(MI.getOperand(1))268.add(MI.getOperand(2))269.add(MI.getOperand(3));270MI.eraseFromParent();271return true;272}273274// If MI is a load instruction, try to convert it into a LOAD AND TEST.275// Return true on success.276bool SystemZElimCompare::convertToLoadAndTest(277MachineInstr &MI, MachineInstr &Compare,278SmallVectorImpl<MachineInstr *> &CCUsers) {279280// Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI.281unsigned Opcode = TII->getLoadAndTest(MI.getOpcode());282if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode))283return false;284285// Rebuild to get the CC operand in the right place.286auto MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode));287for (const auto &MO : MI.operands())288MIB.add(MO);289MIB.setMemRefs(MI.memoperands());290MI.eraseFromParent();291292// Mark instruction as not raising an FP exception if applicable. We already293// verified earlier that this move is valid.294if (!Compare.mayRaiseFPException())295MIB.setMIFlag(MachineInstr::MIFlag::NoFPExcept);296297return true;298}299300// See if MI is an instruction with an equivalent "logical" opcode that can301// be used and replace MI. This is useful for EQ/NE comparisons where the302// "nsw" flag is missing since the "logical" opcode always sets CC to reflect303// the result being zero or non-zero.304bool SystemZElimCompare::convertToLogical(305MachineInstr &MI, MachineInstr &Compare,306SmallVectorImpl<MachineInstr *> &CCUsers) {307308unsigned ConvOpc = 0;309switch (MI.getOpcode()) {310case SystemZ::AR: ConvOpc = SystemZ::ALR; break;311case SystemZ::ARK: ConvOpc = SystemZ::ALRK; break;312case SystemZ::AGR: ConvOpc = SystemZ::ALGR; break;313case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK; break;314case SystemZ::A: ConvOpc = SystemZ::AL; break;315case SystemZ::AY: ConvOpc = SystemZ::ALY; break;316case SystemZ::AG: ConvOpc = SystemZ::ALG; break;317default: break;318}319if (!ConvOpc || !adjustCCMasksForInstr(MI, Compare, CCUsers, ConvOpc))320return false;321322// Operands should be identical, so just change the opcode and remove the323// dead flag on CC.324MI.setDesc(TII->get(ConvOpc));325MI.clearRegisterDeads(SystemZ::CC);326return true;327}328329#ifndef NDEBUG330static bool isAddWithImmediate(unsigned Opcode) {331switch(Opcode) {332case SystemZ::AHI:333case SystemZ::AHIK:334case SystemZ::AGHI:335case SystemZ::AGHIK:336case SystemZ::AFI:337case SystemZ::AIH:338case SystemZ::AGFI:339return true;340default: break;341}342return false;343}344#endif345346// The CC users in CCUsers are testing the result of a comparison of some347// value X against zero and we know that any CC value produced by MI would348// also reflect the value of X. ConvOpc may be used to pass the transfomed349// opcode MI will have if this succeeds. Try to adjust CCUsers so that they350// test the result of MI directly, returning true on success. Leave351// everything unchanged on failure.352bool SystemZElimCompare::adjustCCMasksForInstr(353MachineInstr &MI, MachineInstr &Compare,354SmallVectorImpl<MachineInstr *> &CCUsers,355unsigned ConvOpc) {356unsigned CompareFlags = Compare.getDesc().TSFlags;357unsigned CompareCCValues = SystemZII::getCCValues(CompareFlags);358int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode());359const MCInstrDesc &Desc = TII->get(Opcode);360unsigned MIFlags = Desc.TSFlags;361362// If Compare may raise an FP exception, we can only eliminate it363// if MI itself would have already raised the exception.364if (Compare.mayRaiseFPException()) {365// If the caller will change MI to use ConvOpc, only test whether366// ConvOpc is suitable; it is on the caller to set the MI flag.367if (ConvOpc && !Desc.mayRaiseFPException())368return false;369// If the caller will not change MI, we test the MI flag here.370if (!ConvOpc && !MI.mayRaiseFPException())371return false;372}373374// See which compare-style condition codes are available.375unsigned CCValues = SystemZII::getCCValues(MIFlags);376unsigned ReusableCCMask = CCValues;377// For unsigned comparisons with zero, only equality makes sense.378if (CompareFlags & SystemZII::IsLogical)379ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;380unsigned OFImplies = 0;381bool LogicalMI = false;382bool MIEquivalentToCmp = false;383if (MI.getFlag(MachineInstr::NoSWrap) &&384(MIFlags & SystemZII::CCIfNoSignedWrap)) {385// If MI has the NSW flag set in combination with the386// SystemZII::CCIfNoSignedWrap flag, all CCValues are valid.387}388else if ((MIFlags & SystemZII::CCIfNoSignedWrap) &&389MI.getOperand(2).isImm()) {390// Signed addition of immediate. If adding a positive immediate391// overflows, the result must be less than zero. If adding a negative392// immediate overflows, the result must be larger than zero (except in393// the special case of adding the minimum value of the result range, in394// which case we cannot predict whether the result is larger than or395// equal to zero).396assert(isAddWithImmediate(Opcode) && "Expected an add with immediate.");397assert(!MI.mayLoadOrStore() && "Expected an immediate term.");398int64_t RHS = MI.getOperand(2).getImm();399if (SystemZ::GRX32BitRegClass.contains(MI.getOperand(0).getReg()) &&400RHS == INT32_MIN)401return false;402OFImplies = (RHS > 0 ? SystemZ::CCMASK_CMP_LT : SystemZ::CCMASK_CMP_GT);403}404else if ((MIFlags & SystemZII::IsLogical) && CCValues) {405// Use CCMASK_CMP_EQ to match with CCUsers. On success CCMask:s will be406// converted to CCMASK_LOGICAL_ZERO or CCMASK_LOGICAL_NONZERO.407LogicalMI = true;408ReusableCCMask = SystemZ::CCMASK_CMP_EQ;409}410else {411ReusableCCMask &= SystemZII::getCompareZeroCCMask(MIFlags);412assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");413MIEquivalentToCmp =414ReusableCCMask == CCValues && CCValues == CompareCCValues;415}416if (ReusableCCMask == 0)417return false;418419if (!MIEquivalentToCmp) {420// Now check whether these flags are enough for all users.421SmallVector<MachineOperand *, 4> AlterMasks;422for (MachineInstr *CCUserMI : CCUsers) {423// Fail if this isn't a use of CC that we understand.424unsigned Flags = CCUserMI->getDesc().TSFlags;425unsigned FirstOpNum;426if (Flags & SystemZII::CCMaskFirst)427FirstOpNum = 0;428else if (Flags & SystemZII::CCMaskLast)429FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;430else431return false;432433// Check whether the instruction predicate treats all CC values434// outside of ReusableCCMask in the same way. In that case it435// doesn't matter what those CC values mean.436unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();437unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();438assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&439"Corrupt CC operands of CCUser.");440unsigned OutValid = ~ReusableCCMask & CCValid;441unsigned OutMask = ~ReusableCCMask & CCMask;442if (OutMask != 0 && OutMask != OutValid)443return false;444445AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum));446AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum + 1));447}448449// All users are OK. Adjust the masks for MI.450for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) {451AlterMasks[I]->setImm(CCValues);452unsigned CCMask = AlterMasks[I + 1]->getImm();453if (LogicalMI) {454// Translate the CCMask into its "logical" value.455CCMask = (CCMask == SystemZ::CCMASK_CMP_EQ ?456SystemZ::CCMASK_LOGICAL_ZERO : SystemZ::CCMASK_LOGICAL_NONZERO);457CCMask &= CCValues; // Logical subtracts never set CC=0.458} else {459if (CCMask & ~ReusableCCMask)460CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);461CCMask |= (CCMask & OFImplies) ? SystemZ::CCMASK_ARITH_OVERFLOW : 0;462}463AlterMasks[I + 1]->setImm(CCMask);464}465}466467// CC is now live after MI.468if (!ConvOpc)469MI.clearRegisterDeads(SystemZ::CC);470471// Check if MI lies before Compare.472bool BeforeCmp = false;473MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end();474for (++MBBI; MBBI != MBBE; ++MBBI)475if (MBBI == Compare) {476BeforeCmp = true;477break;478}479480// Clear any intervening kills of CC.481if (BeforeCmp) {482MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;483for (++MBBI; MBBI != MBBE; ++MBBI)484MBBI->clearRegisterKills(SystemZ::CC, TRI);485}486487return true;488}489490// Return true if Compare is a comparison against zero.491static bool isCompareZero(MachineInstr &Compare) {492if (isLoadAndTestAsCmp(Compare))493return true;494return Compare.getNumExplicitOperands() == 2 &&495Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;496}497498// Try to optimize cases where comparison instruction Compare is testing499// a value against zero. Return true on success and if Compare should be500// deleted as dead. CCUsers is the list of instructions that use the CC501// value produced by Compare.502bool SystemZElimCompare::optimizeCompareZero(503MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {504if (!isCompareZero(Compare))505return false;506507// Search back for CC results that are based on the first operand.508unsigned SrcReg = getCompareSourceReg(Compare);509MachineBasicBlock &MBB = *Compare.getParent();510Reference CCRefs;511Reference SrcRefs;512for (MachineBasicBlock::reverse_iterator MBBI =513std::next(MachineBasicBlock::reverse_iterator(&Compare)),514MBBE = MBB.rend(); MBBI != MBBE;) {515MachineInstr &MI = *MBBI++;516if (resultTests(MI, SrcReg)) {517// Try to remove both MI and Compare by converting a branch to BRCT(G).518// or a load-and-trap instruction. We don't care in this case whether519// CC is modified between MI and Compare.520if (!CCRefs.Use && !SrcRefs) {521if (convertToBRCT(MI, Compare, CCUsers)) {522BranchOnCounts += 1;523return true;524}525if (convertToLoadAndTrap(MI, Compare, CCUsers)) {526LoadAndTraps += 1;527return true;528}529}530// Try to eliminate Compare by reusing a CC result from MI.531if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) ||532(!CCRefs.Def &&533(adjustCCMasksForInstr(MI, Compare, CCUsers) ||534convertToLogical(MI, Compare, CCUsers)))) {535EliminatedComparisons += 1;536return true;537}538}539SrcRefs |= getRegReferences(MI, SrcReg);540if (SrcRefs.Def)541break;542CCRefs |= getRegReferences(MI, SystemZ::CC);543if (CCRefs.Use && CCRefs.Def)544break;545// Eliminating a Compare that may raise an FP exception will move546// raising the exception to some earlier MI. We cannot do this if547// there is anything in between that might change exception flags.548if (Compare.mayRaiseFPException() &&549(MI.isCall() || MI.hasUnmodeledSideEffects()))550break;551}552553// Also do a forward search to handle cases where an instruction after the554// compare can be converted, like555// CGHI %r0d, 0; %r1d = LGR %r0d => LTGR %r1d, %r0d556auto MIRange = llvm::make_range(557std::next(MachineBasicBlock::iterator(&Compare)), MBB.end());558for (MachineInstr &MI : llvm::make_early_inc_range(MIRange)) {559if (preservesValueOf(MI, SrcReg)) {560// Try to eliminate Compare by reusing a CC result from MI.561if (convertToLoadAndTest(MI, Compare, CCUsers)) {562EliminatedComparisons += 1;563return true;564}565}566if (getRegReferences(MI, SrcReg).Def)567return false;568if (getRegReferences(MI, SystemZ::CC))569return false;570}571572return false;573}574575// Try to fuse comparison instruction Compare into a later branch.576// Return true on success and if Compare is therefore redundant.577bool SystemZElimCompare::fuseCompareOperations(578MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {579// See whether we have a single branch with which to fuse.580if (CCUsers.size() != 1)581return false;582MachineInstr *Branch = CCUsers[0];583SystemZII::FusedCompareType Type;584switch (Branch->getOpcode()) {585case SystemZ::BRC:586Type = SystemZII::CompareAndBranch;587break;588case SystemZ::CondReturn:589Type = SystemZII::CompareAndReturn;590break;591case SystemZ::CallBCR:592Type = SystemZII::CompareAndSibcall;593break;594case SystemZ::CondTrap:595Type = SystemZII::CompareAndTrap;596break;597default:598return false;599}600601// See whether we have a comparison that can be fused.602unsigned FusedOpcode =603TII->getFusedCompare(Compare.getOpcode(), Type, &Compare);604if (!FusedOpcode)605return false;606607// Make sure that the operands are available at the branch.608// SrcReg2 is the register if the source operand is a register,609// 0 if the source operand is immediate, and the base register610// if the source operand is memory (index is not supported).611Register SrcReg = Compare.getOperand(0).getReg();612Register SrcReg2 =613Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : Register();614MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;615for (++MBBI; MBBI != MBBE; ++MBBI)616if (MBBI->modifiesRegister(SrcReg, TRI) ||617(SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))618return false;619620// Read the branch mask, target (if applicable), regmask (if applicable).621MachineOperand CCMask(MBBI->getOperand(1));622assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&623"Invalid condition-code mask for integer comparison");624// This is only valid for CompareAndBranch and CompareAndSibcall.625MachineOperand Target(MBBI->getOperand(626(Type == SystemZII::CompareAndBranch ||627Type == SystemZII::CompareAndSibcall) ? 2 : 0));628const uint32_t *RegMask;629if (Type == SystemZII::CompareAndSibcall)630RegMask = MBBI->getOperand(3).getRegMask();631632// Clear out all current operands.633int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, TRI, false);634assert(CCUse >= 0 && "BRC/BCR must use CC");635Branch->removeOperand(CCUse);636// Remove regmask (sibcall).637if (Type == SystemZII::CompareAndSibcall)638Branch->removeOperand(3);639// Remove target (branch or sibcall).640if (Type == SystemZII::CompareAndBranch ||641Type == SystemZII::CompareAndSibcall)642Branch->removeOperand(2);643Branch->removeOperand(1);644Branch->removeOperand(0);645646// Rebuild Branch as a fused compare and branch.647// SrcNOps is the number of MI operands of the compare instruction648// that we need to copy over.649unsigned SrcNOps = 2;650if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)651SrcNOps = 3;652Branch->setDesc(TII->get(FusedOpcode));653MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);654for (unsigned I = 0; I < SrcNOps; I++)655MIB.add(Compare.getOperand(I));656MIB.add(CCMask);657658if (Type == SystemZII::CompareAndBranch) {659// Only conditional branches define CC, as they may be converted back660// to a non-fused branch because of a long displacement. Conditional661// returns don't have that problem.662MIB.add(Target).addReg(SystemZ::CC,663RegState::ImplicitDefine | RegState::Dead);664}665666if (Type == SystemZII::CompareAndSibcall) {667MIB.add(Target);668MIB.addRegMask(RegMask);669}670671// Clear any intervening kills of SrcReg and SrcReg2.672MBBI = Compare;673for (++MBBI; MBBI != MBBE; ++MBBI) {674MBBI->clearRegisterKills(SrcReg, TRI);675if (SrcReg2)676MBBI->clearRegisterKills(SrcReg2, TRI);677}678FusedComparisons += 1;679return true;680}681682// Process all comparison instructions in MBB. Return true if something683// changed.684bool SystemZElimCompare::processBlock(MachineBasicBlock &MBB) {685bool Changed = false;686687// Walk backwards through the block looking for comparisons, recording688// all CC users as we go. The subroutines can delete Compare and689// instructions before it.690LiveRegUnits LiveRegs(*TRI);691LiveRegs.addLiveOuts(MBB);692bool CompleteCCUsers = LiveRegs.available(SystemZ::CC);693SmallVector<MachineInstr *, 4> CCUsers;694MachineBasicBlock::iterator MBBI = MBB.end();695while (MBBI != MBB.begin()) {696MachineInstr &MI = *--MBBI;697if (CompleteCCUsers && (MI.isCompare() || isLoadAndTestAsCmp(MI)) &&698(optimizeCompareZero(MI, CCUsers) ||699fuseCompareOperations(MI, CCUsers))) {700++MBBI;701MI.eraseFromParent();702Changed = true;703CCUsers.clear();704continue;705}706707if (MI.definesRegister(SystemZ::CC, /*TRI=*/nullptr)) {708CCUsers.clear();709CompleteCCUsers = true;710}711if (MI.readsRegister(SystemZ::CC, /*TRI=*/nullptr) && CompleteCCUsers)712CCUsers.push_back(&MI);713}714return Changed;715}716717bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) {718if (skipFunction(F.getFunction()))719return false;720721TII = F.getSubtarget<SystemZSubtarget>().getInstrInfo();722TRI = &TII->getRegisterInfo();723724bool Changed = false;725for (auto &MBB : F)726Changed |= processBlock(MBB);727728return Changed;729}730731FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) {732return new SystemZElimCompare();733}734735736