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)) {
156bool SystemZElimCompare::convertToBRCT(
157 MachineInstr &
MI, MachineInstr &Compare,
158 SmallVectorImpl<MachineInstr *> &CCUsers) {
160 unsigned Opcode =
MI.getOpcode();
162 if (Opcode == SystemZ::AHI)
163 BRCT = SystemZ::BRCT;
164 else if (Opcode == SystemZ::AGHI)
165 BRCT = SystemZ::BRCTG;
166 else if (Opcode == SystemZ::AIH)
167 BRCT = SystemZ::BRCTH;
170 if (
MI.getOperand(2).getImm() != -1)
174 if (CCUsers.
size() != 1)
176 MachineInstr *
Branch = CCUsers[0];
177 if (
Branch->getOpcode() != SystemZ::BRC ||
185 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
188 if (getRegReferences(*
MBBI, SrcReg))
193 while (
Branch->getNumOperands())
196 MachineInstrBuilder MIB(*
Branch->getParent()->getParent(), Branch);
197 MIB.add(
MI.getOperand(0)).add(
MI.getOperand(1)).add(Target);
201 if (BRCT != SystemZ::BRCTH)
202 MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
205 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
206 MI.eraseFromParent();
213bool SystemZElimCompare::convertToLoadAndTrap(
214 MachineInstr &
MI, MachineInstr &Compare,
215 SmallVectorImpl<MachineInstr *> &CCUsers) {
216 unsigned LATOpcode =
TII->getLoadAndTrap(
MI.getOpcode());
221 if (CCUsers.
size() != 1)
223 MachineInstr *
Branch = CCUsers[0];
224 if (
Branch->getOpcode() != SystemZ::CondTrap ||
232 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
235 if (getRegReferences(*
MBBI, SrcReg))
239 while (
Branch->getNumOperands())
242 MachineInstrBuilder(*
Branch->getParent()->getParent(), Branch)
243 .add(
MI.getOperand(0))
244 .add(
MI.getOperand(1))
245 .add(
MI.getOperand(2))
246 .add(
MI.getOperand(3));
249 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *Branch);
250 MI.eraseFromParent();
256bool SystemZElimCompare::convertToLoadAndTest(
257 MachineInstr &
MI, MachineInstr &Compare,
258 SmallVectorImpl<MachineInstr *> &CCUsers) {
261 unsigned Opcode =
TII->getLoadAndTest(
MI.getOpcode());
262 if (!Opcode || !adjustCCMasksForInstr(
MI, Compare, CCUsers, Opcode))
266 auto MIB =
BuildMI(*
MI.getParent(),
MI,
MI.getDebugLoc(),
TII->get(Opcode));
267 for (
const auto &MO :
MI.operands())
269 MIB.setMemRefs(
MI.memoperands());
272 MI.getParent()->getParent()->substituteDebugValuesForInst(
MI, *MIB);
273 MI.eraseFromParent();
277 if (!
Compare.mayRaiseFPException())
278 MIB.setMIFlag(MachineInstr::MIFlag::NoFPExcept);
287bool SystemZElimCompare::convertToLogical(
288 MachineInstr &
MI, MachineInstr &Compare,
289 SmallVectorImpl<MachineInstr *> &CCUsers) {
291 unsigned ConvOpc = 0;
292 switch (
MI.getOpcode()) {
293 case SystemZ::AR: ConvOpc = SystemZ::ALR;
break;
294 case SystemZ::ARK: ConvOpc = SystemZ::ALRK;
break;
295 case SystemZ::AGR: ConvOpc = SystemZ::ALGR;
break;
296 case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK;
break;
297 case SystemZ::A: ConvOpc = SystemZ::AL;
break;
298 case SystemZ::AY: ConvOpc = SystemZ::ALY;
break;
299 case SystemZ::AG: ConvOpc = SystemZ::ALG;
break;
302 if (!ConvOpc || !adjustCCMasksForInstr(
MI, Compare, CCUsers, ConvOpc))
307 MI.setDesc(
TII->get(ConvOpc));
308 MI.clearRegisterDeads(SystemZ::CC);
335bool SystemZElimCompare::adjustCCMasksForInstr(
336 MachineInstr &
MI, MachineInstr &Compare,
337 SmallVectorImpl<MachineInstr *> &CCUsers,
339 unsigned CompareFlags =
Compare.getDesc().TSFlags;
341 int Opcode = (ConvOpc ? ConvOpc :
MI.getOpcode());
342 const MCInstrDesc &
Desc =
TII->get(Opcode);
343 unsigned MIFlags =
Desc.TSFlags;
347 if (
Compare.mayRaiseFPException()) {
350 if (ConvOpc && !
Desc.mayRaiseFPException())
353 if (!ConvOpc && !
MI.mayRaiseFPException())
359 unsigned ReusableCCMask = CCValues;
363 unsigned OFImplies = 0;
364 bool LogicalMI =
false;
365 bool MIEquivalentToCmp =
false;
372 MI.getOperand(2).isImm()) {
380 assert(!
MI.mayLoadOrStore() &&
"Expected an immediate term.");
381 int64_t
RHS =
MI.getOperand(2).getImm();
382 if (SystemZ::GRX32BitRegClass.
contains(
MI.getOperand(0).getReg()) &&
395 assert((ReusableCCMask & ~CCValues) == 0 &&
"Invalid CCValues");
397 ReusableCCMask == CCValues && CCValues == CompareCCValues;
399 if (ReusableCCMask == 0)
402 if (!MIEquivalentToCmp) {
405 for (MachineInstr *CCUserMI : CCUsers) {
407 unsigned Flags = CCUserMI->getDesc().TSFlags;
412 FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
419 unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
420 unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
421 assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
422 "Corrupt CC operands of CCUser.");
423 unsigned OutValid = ~ReusableCCMask & CCValid;
424 unsigned OutMask = ~ReusableCCMask & CCMask;
425 if (OutMask != 0 && OutMask != OutValid)
428 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum));
429 AlterMasks.
push_back(&CCUserMI->getOperand(FirstOpNum + 1));
433 for (
unsigned I = 0,
E = AlterMasks.
size();
I !=
E;
I += 2) {
434 AlterMasks[
I]->setImm(CCValues);
435 unsigned CCMask = AlterMasks[
I + 1]->getImm();
442 if (CCMask & ~ReusableCCMask)
443 CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
446 AlterMasks[
I + 1]->setImm(CCMask);
452 MI.clearRegisterDeads(SystemZ::CC);
455 bool BeforeCmp =
false;
458 if (
MBBI == Compare) {
467 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
477bool SystemZElimCompare::optimizeCompareZero(
478 MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
479 if (!
TII->isCompareZero(Compare))
483 unsigned SrcReg =
TII->getCompareSourceReg(Compare);
484 MachineBasicBlock &
MBB = *
Compare.getParent();
490 MachineInstr &
MI = *
MBBI++;
495 if (!CCRefs.Use && !SrcRefs) {
496 if (convertToBRCT(
MI, Compare, CCUsers)) {
500 if (convertToLoadAndTrap(
MI, Compare, CCUsers)) {
506 if ((!CCRefs && convertToLoadAndTest(
MI, Compare, CCUsers)) ||
508 (adjustCCMasksForInstr(
MI, Compare, CCUsers) ||
509 convertToLogical(
MI, Compare, CCUsers)))) {
510 EliminatedComparisons += 1;
514 SrcRefs |= getRegReferences(
MI, SrcReg);
517 CCRefs |= getRegReferences(
MI, SystemZ::CC);
518 if (CCRefs.Use && CCRefs.Def)
523 if (
Compare.mayRaiseFPException() &&
524 (
MI.isCall() ||
MI.hasUnmodeledSideEffects()))
534 if (preservesValueOf(
MI, SrcReg)) {
536 if (convertToLoadAndTest(
MI, Compare, CCUsers)) {
537 EliminatedComparisons += 1;
541 if (getRegReferences(
MI, SrcReg).Def)
543 if (getRegReferences(
MI, SystemZ::CC))
552bool SystemZElimCompare::fuseCompareOperations(
553 MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers) {
555 if (CCUsers.
size() != 1)
557 MachineInstr *
Branch = CCUsers[0];
559 switch (
Branch->getOpcode()) {
563 case SystemZ::CondReturn:
566 case SystemZ::CallBCR:
569 case SystemZ::CondTrap:
577 unsigned FusedOpcode =
591 if (
MBBI->modifiesRegister(SrcReg,
TRI) ||
592 (SrcReg2 &&
MBBI->modifiesRegister(SrcReg2,
TRI)))
596 MachineOperand CCMask(
MBBI->getOperand(1));
598 "Invalid condition-code mask for integer comparison");
603 const uint32_t *RegMask;
605 RegMask =
MBBI->getOperand(3).getRegMask();
608 int CCUse =
MBBI->findRegisterUseOperandIdx(SystemZ::CC,
TRI,
false);
609 assert(CCUse >= 0 &&
"BRC/BCR must use CC");
610 Branch->removeOperand(CCUse);
624 unsigned SrcNOps = 2;
625 if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
628 MachineInstrBuilder MIB(*
Branch->getParent()->getParent(), Branch);
629 for (
unsigned I = 0;
I < SrcNOps;
I++)
637 MIB.add(Target).addReg(SystemZ::CC,
638 RegState::ImplicitDefine | RegState::Dead);
643 MIB.addRegMask(RegMask);
649 MBBI->clearRegisterKills(SrcReg,
TRI);
651 MBBI->clearRegisterKills(SrcReg2,
TRI);
653 FusedComparisons += 1;
659bool SystemZElimCompare::processBlock(MachineBasicBlock &
MBB) {
665 LiveRegUnits LiveRegs(*
TRI);
666 LiveRegs.addLiveOuts(
MBB);
667 bool CompleteCCUsers = LiveRegs.available(SystemZ::CC);
668 SmallVector<MachineInstr *, 4> CCUsers;
671 MachineInstr &
MI = *--
MBBI;
672 if (CompleteCCUsers && (
MI.isCompare() ||
TII->isLoadAndTestAsCmp(
MI)) &&
673 (optimizeCompareZero(
MI, CCUsers) ||
674 fuseCompareOperations(
MI, CCUsers))) {
676 MI.eraseFromParent();
682 if (
MI.definesRegister(SystemZ::CC,
nullptr)) {
684 CompleteCCUsers =
true;
686 if (
MI.readsRegister(SystemZ::CC,
nullptr) && CompleteCCUsers)
692bool SystemZElimCompare::runOnMachineFunction(MachineFunction &
F) {
693 if (skipFunction(
F.getFunction()))
696 TII =
F.getSubtarget<SystemZSubtarget>().getInstrInfo();
707 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 bool isAddWithImmediate(unsigned Opcode)
FunctionPass class - This class is used to implement most global optimizations.
const HexagonRegisterInfo & getRegisterInfo() const
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)