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()) {
124 if (
MI.getOperand(1).getReg() ==
Reg)
134 if (
MI.getNumOperands() > 0 &&
MI.getOperand(0).isReg() &&
135 MI.getOperand(0).isDef() &&
MI.getOperand(0).getReg() ==
Reg)
138 return (preservesValueOf(
MI,
Reg));
144 if (
MI.isDebugInstr())
150 if (
TRI->regsOverlap(MOReg,
Reg)) {
167 return (
MI.getOpcode() == SystemZ::LTEBR ||
168 MI.getOpcode() == SystemZ::LTDBR ||
169 MI.getOpcode() == SystemZ::LTXBR) &&
170 MI.getOperand(0).isDead();
177 if (Compare.isCompare())
178 reg = Compare.getOperand(0).getReg();
180 reg = Compare.getOperand(1).getReg();
189bool SystemZElimCompare::convertToBRCT(
193 unsigned Opcode =
MI.getOpcode();
195 if (Opcode == SystemZ::AHI)
196 BRCT = SystemZ::BRCT;
197 else if (Opcode == SystemZ::AGHI)
198 BRCT = SystemZ::BRCTG;
199 else if (Opcode == SystemZ::AIH)
200 BRCT = SystemZ::BRCTH;
203 if (
MI.getOperand(2).getImm() != -1)
207 if (CCUsers.
size() != 1)
210 if (
Branch->getOpcode() != SystemZ::BRC ||
221 if (getRegReferences(*
MBBI, SrcReg))
226 while (
Branch->getNumOperands())
230 MIB.add(
MI.getOperand(0)).add(
MI.getOperand(1)).add(
Target);
234 if (BRCT != SystemZ::BRCTH)
236 MI.eraseFromParent();
243bool SystemZElimCompare::convertToLoadAndTrap(
246 unsigned LATOpcode =
TII->getLoadAndTrap(
MI.getOpcode());
251 if (CCUsers.
size() != 1)
254 if (
Branch->getOpcode() != SystemZ::CondTrap ||
265 if (getRegReferences(*
MBBI, SrcReg))
269 while (
Branch->getNumOperands())
273 .
add(
MI.getOperand(0))
274 .
add(
MI.getOperand(1))
275 .
add(
MI.getOperand(2))
276 .
add(
MI.getOperand(3));
277 MI.eraseFromParent();
283bool SystemZElimCompare::convertToLoadAndTest(
288 unsigned Opcode =
TII->getLoadAndTest(
MI.getOpcode());
289 if (!Opcode || !adjustCCMasksForInstr(
MI, Compare, CCUsers, Opcode))
293 auto MIB =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
TII->get(Opcode));
294 for (
const auto &MO :
MI.operands())
296 MIB.setMemRefs(
MI.memoperands());
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()) {
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 (
unsigned int I = 0,
E = CCUsers.
size();
I !=
E; ++
I) {
447 assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
448 "Corrupt CC operands of CCUser.");
449 unsigned OutValid = ~ReusableCCMask & CCValid;
450 unsigned OutMask = ~ReusableCCMask & CCMask;
451 if (OutMask != 0 && OutMask != OutValid)
459 for (
unsigned I = 0,
E = AlterMasks.
size();
I !=
E;
I += 2) {
460 AlterMasks[
I]->setImm(CCValues);
461 unsigned CCMask = AlterMasks[
I + 1]->getImm();
468 if (CCMask & ~ReusableCCMask)
469 CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
472 AlterMasks[
I + 1]->setImm(CCMask);
478 MI.clearRegisterDeads(SystemZ::CC);
481 bool BeforeCmp =
false;
484 if (
MBBI == Compare) {
493 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
501 switch (Compare.getOpcode()) {
502 case SystemZ::LTEBRCompare:
503 case SystemZ::LTDBRCompare:
504 case SystemZ::LTXBRCompare:
510 return Compare.getNumExplicitOperands() == 2 &&
511 Compare.getOperand(1).isImm() && Compare.getOperand(1).getImm() == 0;
519bool SystemZElimCompare::optimizeCompareZero(
537 if (!CCRefs.Use && !SrcRefs) {
538 if (convertToBRCT(
MI, Compare, CCUsers)) {
542 if (convertToLoadAndTrap(
MI, Compare, CCUsers)) {
548 if ((!CCRefs && convertToLoadAndTest(
MI, Compare, CCUsers)) ||
550 (adjustCCMasksForInstr(
MI, Compare, CCUsers) ||
551 convertToLogical(
MI, Compare, CCUsers)))) {
552 EliminatedComparisons += 1;
556 SrcRefs |= getRegReferences(
MI, SrcReg);
559 CCRefs |= getRegReferences(
MI, SystemZ::CC);
560 if (CCRefs.Use && CCRefs.Def)
565 if (
Compare.mayRaiseFPException() &&
566 (
MI.isCall() ||
MI.hasUnmodeledSideEffects()))
576 if (preservesValueOf(
MI, SrcReg)) {
578 if (convertToLoadAndTest(
MI, Compare, CCUsers)) {
579 EliminatedComparisons += 1;
583 if (getRegReferences(
MI, SrcReg).Def)
585 if (getRegReferences(
MI, SystemZ::CC))
594bool SystemZElimCompare::fuseCompareOperations(
597 if (CCUsers.
size() != 1)
601 switch (
Branch->getOpcode()) {
605 case SystemZ::CondReturn:
608 case SystemZ::CallBCR:
611 case SystemZ::CondTrap:
619 unsigned FusedOpcode =
633 if (
MBBI->modifiesRegister(SrcReg,
TRI) ||
634 (SrcReg2 &&
MBBI->modifiesRegister(SrcReg2,
TRI)))
640 "Invalid condition-code mask for integer comparison");
647 RegMask =
MBBI->getOperand(3).getRegMask();
650 int CCUse =
MBBI->findRegisterUseOperandIdx(SystemZ::CC,
false,
TRI);
651 assert(CCUse >= 0 &&
"BRC/BCR must use CC");
652 Branch->removeOperand(CCUse);
666 unsigned SrcNOps = 2;
667 if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
671 for (
unsigned I = 0;
I < SrcNOps;
I++)
679 MIB.add(
Target).addReg(SystemZ::CC,
685 MIB.addRegMask(RegMask);
691 MBBI->clearRegisterKills(SrcReg,
TRI);
693 MBBI->clearRegisterKills(SrcReg2,
TRI);
695 FusedComparisons += 1;
702 bool Changed =
false;
708 LiveRegs.addLiveOuts(
MBB);
709 bool CompleteCCUsers = !LiveRegs.contains(SystemZ::CC);
715 (optimizeCompareZero(
MI, CCUsers) ||
716 fuseCompareOperations(
MI, CCUsers))) {
718 MI.eraseFromParent();
724 if (
MI.definesRegister(SystemZ::CC)) {
726 CompleteCCUsers =
true;
728 if (
MI.readsRegister(SystemZ::CC) && CompleteCCUsers)
735 if (skipFunction(
F.getFunction()))
739 TRI = &
TII->getRegisterInfo();
741 bool Changed =
false;
743 Changed |= processBlock(
MBB);
749 return new SystemZElimCompare();
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::optional< std::vector< StOtherPiece > > Other
const HexagonInstrInfo * TII
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
unsigned const TargetRegisterInfo * TRI
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
FunctionPass class - This class is used to implement most global optimizations.
A set of physical registers with utility functions to track liveness when walking backward/forward th...
Describe properties that are true of each instruction in the target description file.
bool mayRaiseFPException() const
Return true if this instruction may raise a floating-point exception.
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.
unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
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
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)