40#define DEBUG_TYPE "systemz-elim-compare"
42STATISTIC(BranchOnCounts,
"Number of branch-on-count instructions");
43STATISTIC(LoadAndTraps,
"Number of load-and-trap instructions");
44STATISTIC(EliminatedComparisons,
"Number of eliminated comparisons");
45STATISTIC(FusedComparisons,
"Number of fused compare-and-branch instructions");
52 Reference() =
default;
60 explicit operator bool()
const {
return Def || Use; }
72 SystemZElimCompareLegacy() : MachineFunctionPass(ID) {}
76 MachineFunctionProperties getRequiredProperties()
const override {
77 return MachineFunctionProperties().setNoVRegs();
80 void getAnalysisUsage(AnalysisUsage &AU)
const override {
86char SystemZElimCompareLegacy::ID = 0;
91 "SystemZ Comparison Elimination",
false,
false)
95 switch (
MI.getOpcode()) {
102 if (MI.getOperand(1).getReg() == Reg)
112 if (
MI.getNumOperands() > 0 &&
MI.getOperand(0).isReg() &&
113 MI.getOperand(0).isDef() &&
MI.getOperand(0).getReg() ==
Reg)
116 return (preservesValueOf(
MI,
Reg));
123 if (
MI.isDebugInstr())
129 if (
TRI->regsOverlap(MOReg,
Reg)) {
149 unsigned Opcode =
MI.getOpcode();
151 if (Opcode == SystemZ::AHI)
152 BRCT = SystemZ::BRCT;
153 else if (Opcode == SystemZ::AGHI)
154 BRCT = SystemZ::BRCTG;
155 else if (Opcode == SystemZ::AIH)
156 BRCT = SystemZ::BRCTH;
159 if (
MI.getOperand(2).getImm() != -1)
163 if (CCUsers.
size() != 1)
166 if (Branch->getOpcode() != SystemZ::BRC ||
174 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
182 while (Branch->getNumOperands())
183 Branch->removeOperand(0);
184 Branch->setDesc(
TII->get(BRCT));
190 if (BRCT != SystemZ::BRCTH)
194 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
195 MI.eraseFromParent();
206 unsigned LATOpcode =
TII->getLoadAndTrap(
MI.getOpcode());
211 if (CCUsers.
size() != 1)
214 if (Branch->getOpcode() != SystemZ::CondTrap ||
222 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
229 while (Branch->getNumOperands())
230 Branch->removeOperand(0);
231 Branch->setDesc(
TII->get(LATOpcode));
233 .
add(
MI.getOperand(0))
234 .
add(
MI.getOperand(1))
235 .
add(
MI.getOperand(2))
236 .
add(
MI.getOperand(3));
239 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *Branch);
240 MI.eraseFromParent();
273 int Opcode = (ConvOpc ? ConvOpc :
MI.getOpcode());
275 unsigned MIFlags =
Desc.TSFlags;
279 if (Compare.mayRaiseFPException()) {
282 if (ConvOpc && !
Desc.mayRaiseFPException())
285 if (!ConvOpc && !
MI.mayRaiseFPException())
291 unsigned ReusableCCMask = CCValues;
295 unsigned OFImplies = 0;
296 bool LogicalMI =
false;
297 bool MIEquivalentToCmp =
false;
304 MI.getOperand(2).isImm()) {
312 assert(!
MI.mayLoadOrStore() &&
"Expected an immediate term.");
313 int64_t
RHS =
MI.getOperand(2).getImm();
314 if (SystemZ::GRX32BitRegClass.
contains(
MI.getOperand(0).getReg()) &&
327 assert((ReusableCCMask & ~CCValues) == 0 &&
"Invalid CCValues");
329 ReusableCCMask == CCValues && CCValues == CompareCCValues;
331 if (ReusableCCMask == 0)
334 if (!MIEquivalentToCmp) {
339 unsigned Flags = CCUserMI->getDesc().TSFlags;
344 FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
351 unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
352 unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
353 assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
354 "Corrupt CC operands of CCUser.");
355 unsigned OutValid = ~ReusableCCMask & CCValid;
356 unsigned OutMask = ~ReusableCCMask & CCMask;
357 if (OutMask != 0 && OutMask != OutValid)
360 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum));
361 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum + 1));
365 for (
unsigned I = 0,
E = AlterMasks.
size();
I !=
E;
I += 2) {
366 AlterMasks[
I]->setImm(CCValues);
367 unsigned CCMask = AlterMasks[
I + 1]->getImm();
374 if (CCMask & ~ReusableCCMask)
375 CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
378 AlterMasks[
I + 1]->setImm(CCMask);
384 MI.clearRegisterDeads(SystemZ::CC);
387 bool BeforeCmp =
false;
390 if (
MBBI == Compare) {
399 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
413 unsigned Opcode =
TII->getLoadAndTest(
MI.getOpcode());
418 auto MIB =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
TII->get(Opcode));
419 for (
const auto &MO :
MI.operands())
421 MIB.setMemRefs(
MI.memoperands());
424 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
425 MI.eraseFromParent();
429 if (!Compare.mayRaiseFPException())
444 unsigned ConvOpc = 0;
445 switch (
MI.getOpcode()) {
447 ConvOpc = SystemZ::ALR;
450 ConvOpc = SystemZ::ALRK;
453 ConvOpc = SystemZ::ALGR;
456 ConvOpc = SystemZ::ALGRK;
459 ConvOpc = SystemZ::AL;
462 ConvOpc = SystemZ::ALY;
465 ConvOpc = SystemZ::ALG;
476 MI.setDesc(
TII->get(ConvOpc));
477 MI.clearRegisterDeads(SystemZ::CC);
489 if (!
TII->isCompareZero(Compare))
493 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
499 MBBE =
MBB.rend();
MBBI != MBBE;) {
505 if (!CCRefs.Use && !SrcRefs) {
520 EliminatedComparisons += 1;
528 if (CCRefs.Use && CCRefs.Def)
533 if (Compare.mayRaiseFPException() &&
534 (
MI.isCall() ||
MI.hasUnmodeledSideEffects()))
544 if (preservesValueOf(
MI, SrcReg)) {
547 EliminatedComparisons += 1;
567 if (CCUsers.
size() != 1)
571 switch (Branch->getOpcode()) {
575 case SystemZ::CondReturn:
578 case SystemZ::CallBCR:
581 case SystemZ::CondTrap:
589 unsigned FusedOpcode =
590 TII->getFusedCompare(Compare.getOpcode(),
Type, &Compare);
598 Register SrcReg = Compare.getOperand(0).getReg();
600 Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() :
Register();
603 if (
MBBI->modifiesRegister(SrcReg,
TRI) ||
604 (SrcReg2 &&
MBBI->modifiesRegister(SrcReg2,
TRI)))
610 "Invalid condition-code mask for integer comparison");
617 RegMask =
MBBI->getOperand(3).getRegMask();
620 int CCUse =
MBBI->findRegisterUseOperandIdx(SystemZ::CC,
TRI,
false);
621 assert(CCUse >= 0 &&
"BRC/BCR must use CC");
622 Branch->removeOperand(CCUse);
625 Branch->removeOperand(3);
629 Branch->removeOperand(2);
630 Branch->removeOperand(1);
631 Branch->removeOperand(0);
636 unsigned SrcNOps = 2;
637 if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
639 Branch->setDesc(
TII->get(FusedOpcode));
641 for (
unsigned I = 0;
I < SrcNOps;
I++)
642 MIB.
add(Compare.getOperand(
I));
661 MBBI->clearRegisterKills(SrcReg,
TRI);
663 MBBI->clearRegisterKills(SrcReg2,
TRI);
665 FusedComparisons += 1;
680 bool CompleteCCUsers =
LiveRegs.available(SystemZ::CC);
685 if (CompleteCCUsers && (
MI.isCompare() ||
TII->isLoadAndTestAsCmp(
MI)) &&
689 MI.eraseFromParent();
695 if (
MI.definesRegister(SystemZ::CC,
nullptr)) {
697 CompleteCCUsers =
true;
699 if (
MI.readsRegister(SystemZ::CC,
nullptr) && CompleteCCUsers)
719 return new SystemZElimCompareLegacy();
722bool SystemZElimCompareLegacy::runOnMachineFunction(
MachineFunction &MF) {
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
CompareFlags
CompareIO flag bitmask values.
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 optimizeCompareZero(MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool resultTests(MachineInstr &MI, unsigned Reg)
static bool runElimCompareOnMF(MachineFunction &F)
static bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool convertToLogical(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static Reference getRegReferences(MachineInstr &MI, unsigned Reg, const TargetRegisterInfo *TRI)
static bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, unsigned ConvOpc, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool fuseCompareOperations(MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl< MachineInstr * > &CCUsers, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool processBlock(MachineBasicBlock &MBB, const SystemZInstrInfo *TII, const TargetRegisterInfo *TRI)
static bool isAddWithImmediate(unsigned Opcode)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
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.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
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.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
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.
Pass manager infrastructure for declaring and invalidating analyses.
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...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
@ Ref
The access may reference the value stored in memory.
bool operator|=(SparseBitVector< ElementSize > &LHS, const SparseBitVector< ElementSize > *RHS)
FunctionPass * createSystemZElimCompareLegacyPass(SystemZTargetMachine &TM)