36 #define DEBUG_TYPE "systemz-elim-compare"
38 STATISTIC(BranchOnCounts,
"Number of branch-on-count instructions");
39 STATISTIC(LoadAndTraps,
"Number of load-and-trap instructions");
40 STATISTIC(EliminatedComparisons,
"Number of eliminated comparisons");
41 STATISTIC(FusedComparisons,
"Number of fused compare-and-branch instructions");
48 Reference() =
default;
50 Reference &
operator|=(
const Reference &Other) {
56 explicit operator bool()
const {
return Def ||
Use; }
92 unsigned ConvOpc = 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())
167 return (
MI.getOpcode() == SystemZ::LTEBR ||
168 MI.getOpcode() == SystemZ::LTDBR ||
169 MI.getOpcode() == SystemZ::LTXBR) &&
170 MI.getOperand(0).isDead();
178 reg =
Compare.getOperand(0).getReg();
180 reg =
Compare.getOperand(1).getReg();
189 bool 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();
243 bool 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();
283 bool 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);
311 bool 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;
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);
359 bool 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)
454 AlterMasks.push_back(&CCUserMI->
getOperand(FirstOpNum));
455 AlterMasks.push_back(&CCUserMI->
getOperand(FirstOpNum + 1));
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;
493 MBBI->clearRegisterKills(SystemZ::CC,
TRI);
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;
519 bool 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))
594 bool 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)
729 CCUsers.push_back(&
MI);
735 if (skipFunction(
F.getFunction()))
739 TRI = &
TII->getRegisterInfo();
741 bool Changed =
false;
743 Changed |= processBlock(
MBB);
749 return new SystemZElimCompare();