36#define DEBUG_TYPE "systemz-elim-compare"
38STATISTIC(BranchOnCounts,
"Number of branch-on-count instructions");
39STATISTIC(LoadAndTraps,
"Number of load-and-trap instructions");
40STATISTIC(EliminatedComparisons,
"Number of eliminated comparisons");
41STATISTIC(FusedComparisons,
"Number of fused compare-and-branch instructions");
48 Reference() =
default;
56 explicit operator bool()
const {
return Def ||
Use; }
77 MachineFunctionProperties::Property::NoVRegs);
92 unsigned ConvOpc = 0);
102char SystemZElimCompare::ID = 0;
107 "SystemZ Comparison Elimination",
false,
false)
111 switch (
MI.getOpcode()) {
118 if (
MI.getOperand(1).getReg() ==
Reg)
128 if (
MI.getNumOperands() > 0 &&
MI.getOperand(0).isReg() &&
129 MI.getOperand(0).isDef() &&
MI.getOperand(0).getReg() ==
Reg)
132 return (preservesValueOf(
MI,
Reg));
138 if (
MI.isDebugInstr())
144 if (
TRI->regsOverlap(MOReg,
Reg)) {
161 return (
MI.getOpcode() == SystemZ::LTEBR ||
162 MI.getOpcode() == SystemZ::LTDBR ||
163 MI.getOpcode() == SystemZ::LTXBR) &&
164 MI.getOperand(0).isDead();
171 if (Compare.isCompare())
172 reg = Compare.getOperand(0).getReg();
174 reg = Compare.getOperand(1).getReg();
183bool SystemZElimCompare::convertToBRCT(
187 unsigned Opcode =
MI.getOpcode();
189 if (Opcode == SystemZ::AHI)
190 BRCT = SystemZ::BRCT;
191 else if (Opcode == SystemZ::AGHI)
192 BRCT = SystemZ::BRCTG;
193 else if (Opcode == SystemZ::AIH)
194 BRCT = SystemZ::BRCTH;
197 if (
MI.getOperand(2).getImm() != -1)
201 if (CCUsers.
size() != 1)
204 if (
Branch->getOpcode() != SystemZ::BRC ||
215 if (getRegReferences(*
MBBI, SrcReg))
220 while (
Branch->getNumOperands())
224 MIB.add(
MI.getOperand(0)).add(
MI.getOperand(1)).add(
Target);
228 if (BRCT != SystemZ::BRCTH)
230 MI.eraseFromParent();
237bool SystemZElimCompare::convertToLoadAndTrap(
240 unsigned LATOpcode =
TII->getLoadAndTrap(
MI.getOpcode());
245 if (CCUsers.
size() != 1)
248 if (
Branch->getOpcode() != SystemZ::CondTrap ||
259 if (getRegReferences(*
MBBI, SrcReg))
263 while (
Branch->getNumOperands())
267 .
add(
MI.getOperand(0))
268 .
add(
MI.getOperand(1))
269 .
add(
MI.getOperand(2))
270 .
add(
MI.getOperand(3));
271 MI.eraseFromParent();
277bool SystemZElimCompare::convertToLoadAndTest(
282 unsigned Opcode =
TII->getLoadAndTest(
MI.getOpcode());
283 if (!Opcode || !adjustCCMasksForInstr(
MI, Compare, CCUsers, Opcode))
287 auto MIB =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
TII->get(Opcode));
288 for (
const auto &MO :
MI.operands())
290 MIB.setMemRefs(
MI.memoperands());
291 MI.eraseFromParent();
295 if (!
Compare.mayRaiseFPException())
296 MIB.setMIFlag(MachineInstr::MIFlag::NoFPExcept);
305bool SystemZElimCompare::convertToLogical(
309 unsigned ConvOpc = 0;
310 switch (
MI.getOpcode()) {
311 case SystemZ::AR: ConvOpc = SystemZ::ALR;
break;
312 case SystemZ::ARK: ConvOpc = SystemZ::ALRK;
break;
313 case SystemZ::AGR: ConvOpc = SystemZ::ALGR;
break;
314 case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK;
break;
315 case SystemZ::A: ConvOpc = SystemZ::AL;
break;
316 case SystemZ::AY: ConvOpc = SystemZ::ALY;
break;
317 case SystemZ::AG: ConvOpc = SystemZ::ALG;
break;
320 if (!ConvOpc || !adjustCCMasksForInstr(
MI, Compare, CCUsers, ConvOpc))
325 MI.setDesc(
TII->get(ConvOpc));
326 MI.clearRegisterDeads(SystemZ::CC);
353bool SystemZElimCompare::adjustCCMasksForInstr(
357 unsigned CompareFlags =
Compare.getDesc().TSFlags;
359 int Opcode = (ConvOpc ? ConvOpc :
MI.getOpcode());
361 unsigned MIFlags =
Desc.TSFlags;
365 if (
Compare.mayRaiseFPException()) {
368 if (ConvOpc && !
Desc.mayRaiseFPException())
371 if (!ConvOpc && !
MI.mayRaiseFPException())
377 unsigned ReusableCCMask = CCValues;
381 unsigned OFImplies = 0;
382 bool LogicalMI =
false;
383 bool MIEquivalentToCmp =
false;
390 MI.getOperand(2).isImm()) {
398 assert(!
MI.mayLoadOrStore() &&
"Expected an immediate term.");
399 int64_t
RHS =
MI.getOperand(2).getImm();
400 if (SystemZ::GRX32BitRegClass.
contains(
MI.getOperand(0).getReg()) &&
413 assert((ReusableCCMask & ~CCValues) == 0 &&
"Invalid CCValues");
415 ReusableCCMask == CCValues && CCValues == CompareCCValues;
417 if (ReusableCCMask == 0)
420 if (!MIEquivalentToCmp) {
425 unsigned Flags = CCUserMI->getDesc().TSFlags;
430 FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
437 unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
438 unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
439 assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
440 "Corrupt CC operands of CCUser.");
441 unsigned OutValid = ~ReusableCCMask & CCValid;
442 unsigned OutMask = ~ReusableCCMask & CCMask;
443 if (OutMask != 0 && OutMask != OutValid)
446 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum));
447 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum + 1));
451 for (
unsigned I = 0, E = AlterMasks.
size();
I != E;
I += 2) {
452 AlterMasks[
I]->setImm(CCValues);
453 unsigned CCMask = AlterMasks[
I + 1]->getImm();
460 if (CCMask & ~ReusableCCMask)
461 CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
464 AlterMasks[
I + 1]->setImm(CCMask);
470 MI.clearRegisterDeads(SystemZ::CC);
473 bool BeforeCmp =
false;
476 if (
MBBI == Compare) {
485 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
495 return Compare.getNumExplicitOperands() == 2 &&
496 Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;
503bool SystemZElimCompare::optimizeCompareZero(
521 if (!CCRefs.Use && !SrcRefs) {
522 if (convertToBRCT(
MI, Compare, CCUsers)) {
526 if (convertToLoadAndTrap(
MI, Compare, CCUsers)) {
532 if ((!CCRefs && convertToLoadAndTest(
MI, Compare, CCUsers)) ||
534 (adjustCCMasksForInstr(
MI, Compare, CCUsers) ||
535 convertToLogical(
MI, Compare, CCUsers)))) {
536 EliminatedComparisons += 1;
540 SrcRefs |= getRegReferences(
MI, SrcReg);
543 CCRefs |= getRegReferences(
MI, SystemZ::CC);
544 if (CCRefs.Use && CCRefs.Def)
549 if (
Compare.mayRaiseFPException() &&
550 (
MI.isCall() ||
MI.hasUnmodeledSideEffects()))
560 if (preservesValueOf(
MI, SrcReg)) {
562 if (convertToLoadAndTest(
MI, Compare, CCUsers)) {
563 EliminatedComparisons += 1;
567 if (getRegReferences(
MI, SrcReg).Def)
569 if (getRegReferences(
MI, SystemZ::CC))
578bool SystemZElimCompare::fuseCompareOperations(
581 if (CCUsers.
size() != 1)
585 switch (
Branch->getOpcode()) {
589 case SystemZ::CondReturn:
592 case SystemZ::CallBCR:
595 case SystemZ::CondTrap:
603 unsigned FusedOpcode =
617 if (
MBBI->modifiesRegister(SrcReg,
TRI) ||
618 (SrcReg2 &&
MBBI->modifiesRegister(SrcReg2,
TRI)))
624 "Invalid condition-code mask for integer comparison");
631 RegMask =
MBBI->getOperand(3).getRegMask();
634 int CCUse =
MBBI->findRegisterUseOperandIdx(SystemZ::CC,
TRI,
false);
635 assert(CCUse >= 0 &&
"BRC/BCR must use CC");
636 Branch->removeOperand(CCUse);
650 unsigned SrcNOps = 2;
651 if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
655 for (
unsigned I = 0;
I < SrcNOps;
I++)
663 MIB.add(
Target).addReg(SystemZ::CC,
669 MIB.addRegMask(RegMask);
675 MBBI->clearRegisterKills(SrcReg,
TRI);
677 MBBI->clearRegisterKills(SrcReg2,
TRI);
679 FusedComparisons += 1;
686 bool Changed =
false;
692 LiveRegs.addLiveOuts(
MBB);
693 bool CompleteCCUsers = LiveRegs.available(SystemZ::CC);
699 (optimizeCompareZero(
MI, CCUsers) ||
700 fuseCompareOperations(
MI, CCUsers))) {
702 MI.eraseFromParent();
708 if (
MI.definesRegister(SystemZ::CC,
nullptr)) {
710 CompleteCCUsers =
true;
712 if (
MI.readsRegister(SystemZ::CC,
nullptr) && CompleteCCUsers)
719 if (skipFunction(
F.getFunction()))
723 TRI = &
TII->getRegisterInfo();
725 bool Changed =
false;
727 Changed |= processBlock(
MBB);
733 return new SystemZElimCompare();
MachineBasicBlock MachineBasicBlock::iterator MBBI
std::optional< std::vector< StOtherPiece > > Other
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static bool resultTests(MachineInstr &MI, unsigned Reg)
static unsigned getCompareSourceReg(MachineInstr &Compare)
static bool isLoadAndTestAsCmp(MachineInstr &MI)
static bool isCompareZero(MachineInstr &Compare)
static bool isAddWithImmediate(unsigned Opcode)
FunctionPass class - This class is used to implement most global optimizations.
A set of register units used to track register liveness.
Describe properties that are true of each instruction in the target description file.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual MachineFunctionProperties getRequiredProperties() const
Properties which a MachineFunction may have at a given point in time.
MachineFunctionProperties & set(Property P)
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Wrapper class representing virtual and physical registers.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Target - Wrapper for Target specific information.
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
static unsigned getCCValues(unsigned int Flags)
static unsigned getCompareZeroCCMask(unsigned int Flags)
const unsigned CCMASK_LOGICAL_ZERO
const unsigned CCMASK_CMP_GT
const unsigned CCMASK_CMP_EQ
const unsigned CCMASK_ICMP
const unsigned CCMASK_ARITH_OVERFLOW
const unsigned CCMASK_CMP_LT
const unsigned CCMASK_CMP_NE
const unsigned CCMASK_LOGICAL_NONZERO
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
void initializeSystemZElimComparePass(PassRegistry &)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
FunctionPass * createSystemZElimComparePass(SystemZTargetMachine &TM)
@ Ref
The access may reference the value stored in memory.
bool operator|=(SparseBitVector< ElementSize > &LHS, const SparseBitVector< ElementSize > *RHS)
Description of the encoding of one expression Op.