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; }
89 unsigned ConvOpc = 0);
99char SystemZElimCompare::ID = 0;
104 "SystemZ Comparison Elimination",
false,
false)
108 switch (
MI.getOpcode()) {
115 if (
MI.getOperand(1).getReg() ==
Reg)
125 if (
MI.getNumOperands() > 0 &&
MI.getOperand(0).isReg() &&
126 MI.getOperand(0).isDef() &&
MI.getOperand(0).getReg() ==
Reg)
129 return (preservesValueOf(
MI,
Reg));
135 if (
MI.isDebugInstr())
141 if (
TRI->regsOverlap(MOReg,
Reg)) {
158 return (
MI.getOpcode() == SystemZ::LTEBR ||
159 MI.getOpcode() == SystemZ::LTDBR ||
160 MI.getOpcode() == SystemZ::LTXBR) &&
161 MI.getOperand(0).isDead();
168 if (Compare.isCompare())
169 reg = Compare.getOperand(0).getReg();
171 reg = Compare.getOperand(1).getReg();
180bool SystemZElimCompare::convertToBRCT(
184 unsigned Opcode =
MI.getOpcode();
186 if (Opcode == SystemZ::AHI)
187 BRCT = SystemZ::BRCT;
188 else if (Opcode == SystemZ::AGHI)
189 BRCT = SystemZ::BRCTG;
190 else if (Opcode == SystemZ::AIH)
191 BRCT = SystemZ::BRCTH;
194 if (
MI.getOperand(2).getImm() != -1)
198 if (CCUsers.
size() != 1)
201 if (
Branch->getOpcode() != SystemZ::BRC ||
212 if (getRegReferences(*
MBBI, SrcReg))
217 while (
Branch->getNumOperands())
221 MIB.add(
MI.getOperand(0)).add(
MI.getOperand(1)).add(
Target);
225 if (BRCT != SystemZ::BRCTH)
229 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
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));
273 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *Branch);
274 MI.eraseFromParent();
280bool SystemZElimCompare::convertToLoadAndTest(
285 unsigned Opcode =
TII->getLoadAndTest(
MI.getOpcode());
286 if (!Opcode || !adjustCCMasksForInstr(
MI, Compare, CCUsers, Opcode))
290 auto MIB =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
TII->get(Opcode));
291 for (
const auto &MO :
MI.operands())
293 MIB.setMemRefs(
MI.memoperands());
296 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
297 MI.eraseFromParent();
301 if (!
Compare.mayRaiseFPException())
302 MIB.setMIFlag(MachineInstr::MIFlag::NoFPExcept);
311bool SystemZElimCompare::convertToLogical(
315 unsigned ConvOpc = 0;
316 switch (
MI.getOpcode()) {
317 case SystemZ::AR: ConvOpc = SystemZ::ALR;
break;
318 case SystemZ::ARK: ConvOpc = SystemZ::ALRK;
break;
319 case SystemZ::AGR: ConvOpc = SystemZ::ALGR;
break;
320 case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK;
break;
321 case SystemZ::A: ConvOpc = SystemZ::AL;
break;
322 case SystemZ::AY: ConvOpc = SystemZ::ALY;
break;
323 case SystemZ::AG: ConvOpc = SystemZ::ALG;
break;
326 if (!ConvOpc || !adjustCCMasksForInstr(
MI, Compare, CCUsers, ConvOpc))
331 MI.setDesc(
TII->get(ConvOpc));
332 MI.clearRegisterDeads(SystemZ::CC);
359bool SystemZElimCompare::adjustCCMasksForInstr(
363 unsigned CompareFlags =
Compare.getDesc().TSFlags;
365 int Opcode = (ConvOpc ? ConvOpc :
MI.getOpcode());
367 unsigned MIFlags =
Desc.TSFlags;
371 if (
Compare.mayRaiseFPException()) {
374 if (ConvOpc && !
Desc.mayRaiseFPException())
377 if (!ConvOpc && !
MI.mayRaiseFPException())
383 unsigned ReusableCCMask = CCValues;
387 unsigned OFImplies = 0;
388 bool LogicalMI =
false;
389 bool MIEquivalentToCmp =
false;
396 MI.getOperand(2).isImm()) {
404 assert(!
MI.mayLoadOrStore() &&
"Expected an immediate term.");
405 int64_t
RHS =
MI.getOperand(2).getImm();
406 if (SystemZ::GRX32BitRegClass.
contains(
MI.getOperand(0).getReg()) &&
419 assert((ReusableCCMask & ~CCValues) == 0 &&
"Invalid CCValues");
421 ReusableCCMask == CCValues && CCValues == CompareCCValues;
423 if (ReusableCCMask == 0)
426 if (!MIEquivalentToCmp) {
431 unsigned Flags = CCUserMI->getDesc().TSFlags;
436 FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
443 unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
444 unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
445 assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
446 "Corrupt CC operands of CCUser.");
447 unsigned OutValid = ~ReusableCCMask & CCValid;
448 unsigned OutMask = ~ReusableCCMask & CCMask;
449 if (OutMask != 0 && OutMask != OutValid)
452 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum));
453 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum + 1));
457 for (
unsigned I = 0, E = AlterMasks.
size();
I != E;
I += 2) {
458 AlterMasks[
I]->setImm(CCValues);
459 unsigned CCMask = AlterMasks[
I + 1]->getImm();
466 if (CCMask & ~ReusableCCMask)
467 CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
470 AlterMasks[
I + 1]->setImm(CCMask);
476 MI.clearRegisterDeads(SystemZ::CC);
479 bool BeforeCmp =
false;
482 if (
MBBI == Compare) {
491 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
501 return Compare.getNumExplicitOperands() == 2 &&
502 Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;
509bool SystemZElimCompare::optimizeCompareZero(
527 if (!CCRefs.Use && !SrcRefs) {
528 if (convertToBRCT(
MI, Compare, CCUsers)) {
532 if (convertToLoadAndTrap(
MI, Compare, CCUsers)) {
538 if ((!CCRefs && convertToLoadAndTest(
MI, Compare, CCUsers)) ||
540 (adjustCCMasksForInstr(
MI, Compare, CCUsers) ||
541 convertToLogical(
MI, Compare, CCUsers)))) {
542 EliminatedComparisons += 1;
546 SrcRefs |= getRegReferences(
MI, SrcReg);
549 CCRefs |= getRegReferences(
MI, SystemZ::CC);
550 if (CCRefs.Use && CCRefs.Def)
555 if (
Compare.mayRaiseFPException() &&
556 (
MI.isCall() ||
MI.hasUnmodeledSideEffects()))
566 if (preservesValueOf(
MI, SrcReg)) {
568 if (convertToLoadAndTest(
MI, Compare, CCUsers)) {
569 EliminatedComparisons += 1;
573 if (getRegReferences(
MI, SrcReg).Def)
575 if (getRegReferences(
MI, SystemZ::CC))
584bool SystemZElimCompare::fuseCompareOperations(
587 if (CCUsers.
size() != 1)
591 switch (
Branch->getOpcode()) {
595 case SystemZ::CondReturn:
598 case SystemZ::CallBCR:
601 case SystemZ::CondTrap:
609 unsigned FusedOpcode =
623 if (
MBBI->modifiesRegister(SrcReg,
TRI) ||
624 (SrcReg2 &&
MBBI->modifiesRegister(SrcReg2,
TRI)))
630 "Invalid condition-code mask for integer comparison");
637 RegMask =
MBBI->getOperand(3).getRegMask();
640 int CCUse =
MBBI->findRegisterUseOperandIdx(SystemZ::CC,
TRI,
false);
641 assert(CCUse >= 0 &&
"BRC/BCR must use CC");
642 Branch->removeOperand(CCUse);
656 unsigned SrcNOps = 2;
657 if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
661 for (
unsigned I = 0;
I < SrcNOps;
I++)
669 MIB.add(
Target).addReg(SystemZ::CC,
675 MIB.addRegMask(RegMask);
681 MBBI->clearRegisterKills(SrcReg,
TRI);
683 MBBI->clearRegisterKills(SrcReg2,
TRI);
685 FusedComparisons += 1;
692 bool Changed =
false;
698 LiveRegs.addLiveOuts(
MBB);
699 bool CompleteCCUsers = LiveRegs.available(SystemZ::CC);
705 (optimizeCompareZero(
MI, CCUsers) ||
706 fuseCompareOperations(
MI, CCUsers))) {
708 MI.eraseFromParent();
714 if (
MI.definesRegister(SystemZ::CC,
nullptr)) {
716 CompleteCCUsers =
true;
718 if (
MI.readsRegister(SystemZ::CC,
nullptr) && CompleteCCUsers)
725 if (skipFunction(
F.getFunction()))
729 TRI = &
TII->getRegisterInfo();
731 bool Changed =
false;
733 Changed |= processBlock(
MBB);
739 return new SystemZElimCompare();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator MBBI
std::optional< std::vector< StOtherPiece > > Other
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
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.
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.