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; }
68 SystemZElimCompare() : MachineFunctionPass(ID) {}
70 bool processBlock(MachineBasicBlock &
MBB);
71 bool runOnMachineFunction(MachineFunction &
F)
override;
73 MachineFunctionProperties getRequiredProperties()
const override {
74 return MachineFunctionProperties().setNoVRegs();
79 bool convertToBRCT(MachineInstr &
MI, MachineInstr &Compare,
80 SmallVectorImpl<MachineInstr *> &CCUsers);
81 bool convertToLoadAndTrap(MachineInstr &
MI, MachineInstr &Compare,
82 SmallVectorImpl<MachineInstr *> &CCUsers);
83 bool convertToLoadAndTest(MachineInstr &
MI, MachineInstr &Compare,
84 SmallVectorImpl<MachineInstr *> &CCUsers);
85 bool convertToLogical(MachineInstr &
MI, MachineInstr &Compare,
86 SmallVectorImpl<MachineInstr *> &CCUsers);
87 bool adjustCCMasksForInstr(MachineInstr &
MI, MachineInstr &Compare,
88 SmallVectorImpl<MachineInstr *> &CCUsers,
89 unsigned ConvOpc = 0);
90 bool optimizeCompareZero(MachineInstr &Compare,
91 SmallVectorImpl<MachineInstr *> &CCUsers);
92 bool fuseCompareOperations(MachineInstr &Compare,
93 SmallVectorImpl<MachineInstr *> &CCUsers);
95 const SystemZInstrInfo *TII =
nullptr;
96 const TargetRegisterInfo *TRI =
nullptr;
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())
138 for (
const MachineOperand &MO :
MI.operands()) {
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(
181 MachineInstr &
MI, MachineInstr &Compare,
182 SmallVectorImpl<MachineInstr *> &CCUsers) {
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)
200 MachineInstr *
Branch = CCUsers[0];
201 if (
Branch->getOpcode() != SystemZ::BRC ||
212 if (getRegReferences(*
MBBI, SrcReg))
217 while (
Branch->getNumOperands())
220 MachineInstrBuilder MIB(*
Branch->getParent()->getParent(), Branch);
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(
238 MachineInstr &
MI, MachineInstr &Compare,
239 SmallVectorImpl<MachineInstr *> &CCUsers) {
240 unsigned LATOpcode =
TII->getLoadAndTrap(
MI.getOpcode());
245 if (CCUsers.
size() != 1)
247 MachineInstr *
Branch = CCUsers[0];
248 if (
Branch->getOpcode() != SystemZ::CondTrap ||
259 if (getRegReferences(*
MBBI, SrcReg))
263 while (
Branch->getNumOperands())
266 MachineInstrBuilder(*
Branch->getParent()->getParent(), Branch)
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(
281 MachineInstr &
MI, MachineInstr &Compare,
282 SmallVectorImpl<MachineInstr *> &CCUsers) {
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(
312 MachineInstr &
MI, MachineInstr &Compare,
313 SmallVectorImpl<MachineInstr *> &CCUsers) {
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(
360 MachineInstr &
MI, MachineInstr &Compare,
361 SmallVectorImpl<MachineInstr *> &CCUsers,
363 unsigned CompareFlags =
Compare.getDesc().TSFlags;
365 int Opcode = (ConvOpc ? ConvOpc :
MI.getOpcode());
366 const MCInstrDesc &
Desc =
TII->get(Opcode);
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) {
429 for (MachineInstr *CCUserMI : CCUsers) {
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(
510 MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
516 MachineBasicBlock &
MBB = *
Compare.getParent();
522 MachineInstr &
MI = *
MBBI++;
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(
585 MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
587 if (CCUsers.
size() != 1)
589 MachineInstr *
Branch = CCUsers[0];
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)))
628 MachineOperand CCMask(
MBBI->getOperand(1));
630 "Invalid condition-code mask for integer comparison");
635 const uint32_t *RegMask;
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)
660 MachineInstrBuilder MIB(*
Branch->getParent()->getParent(), Branch);
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;
691bool SystemZElimCompare::processBlock(MachineBasicBlock &
MBB) {
697 LiveRegUnits LiveRegs(*
TRI);
698 LiveRegs.addLiveOuts(
MBB);
699 bool CompleteCCUsers = LiveRegs.available(SystemZ::CC);
700 SmallVector<MachineInstr *, 4> CCUsers;
703 MachineInstr &
MI = *--
MBBI;
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)
724bool SystemZElimCompare::runOnMachineFunction(MachineFunction &
F) {
725 if (skipFunction(
F.getFunction()))
728 TII =
F.getSubtarget<SystemZSubtarget>().getInstrInfo();
729 TRI = &
TII->getRegisterInfo();
739 return new SystemZElimCompare();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#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.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Representation of each machine instruction.
void push_back(const T &Elt)
A Use represents the edge between a Value definition and its users.
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
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)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Ref
The access may reference the value stored in memory.
bool operator|=(SparseBitVector< ElementSize > &LHS, const SparseBitVector< ElementSize > *RHS)