diff options
Diffstat (limited to 'lib/Target/SystemZ/SystemZElimCompare.cpp')
-rw-r--r-- | lib/Target/SystemZ/SystemZElimCompare.cpp | 164 |
1 files changed, 97 insertions, 67 deletions
diff --git a/lib/Target/SystemZ/SystemZElimCompare.cpp b/lib/Target/SystemZ/SystemZElimCompare.cpp index 55f7a7b8d0d1..9edd1fc36406 100644 --- a/lib/Target/SystemZ/SystemZElimCompare.cpp +++ b/lib/Target/SystemZ/SystemZElimCompare.cpp @@ -86,9 +86,11 @@ private: SmallVectorImpl<MachineInstr *> &CCUsers); bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers); - bool convertToLoadAndTest(MachineInstr &MI); + bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare, + SmallVectorImpl<MachineInstr *> &CCUsers); bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare, - SmallVectorImpl<MachineInstr *> &CCUsers); + SmallVectorImpl<MachineInstr *> &CCUsers, + unsigned ConvOpc = 0); bool optimizeCompareZero(MachineInstr &Compare, SmallVectorImpl<MachineInstr *> &CCUsers); bool fuseCompareOperations(MachineInstr &Compare, @@ -282,26 +284,37 @@ bool SystemZElimCompare::convertToLoadAndTrap( // If MI is a load instruction, try to convert it into a LOAD AND TEST. // Return true on success. -bool SystemZElimCompare::convertToLoadAndTest(MachineInstr &MI) { +bool SystemZElimCompare::convertToLoadAndTest( + MachineInstr &MI, MachineInstr &Compare, + SmallVectorImpl<MachineInstr *> &CCUsers) { + + // Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI. unsigned Opcode = TII->getLoadAndTest(MI.getOpcode()); - if (!Opcode) + if (!Opcode || !adjustCCMasksForInstr(MI, Compare, CCUsers, Opcode)) return false; - MI.setDesc(TII->get(Opcode)); - MachineInstrBuilder(*MI.getParent()->getParent(), MI) - .addReg(SystemZ::CC, RegState::ImplicitDefine); + // Rebuild to get the CC operand in the right place. + MachineInstr *BuiltMI = + BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opcode)); + for (const auto &MO : MI.operands()) + BuiltMI->addOperand(MO); + BuiltMI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + MI.eraseFromParent(); + return true; } // The CC users in CCUsers are testing the result of a comparison of some -// value X against zero and we know that any CC value produced by MI -// would also reflect the value of X. Try to adjust CCUsers so that -// they test the result of MI directly, returning true on success. -// Leave everything unchanged on failure. +// value X against zero and we know that any CC value produced by MI would +// also reflect the value of X. ConvOpc may be used to pass the transfomed +// opcode MI will have if this succeeds. Try to adjust CCUsers so that they +// test the result of MI directly, returning true on success. Leave +// everything unchanged on failure. bool SystemZElimCompare::adjustCCMasksForInstr( MachineInstr &MI, MachineInstr &Compare, - SmallVectorImpl<MachineInstr *> &CCUsers) { - int Opcode = MI.getOpcode(); + SmallVectorImpl<MachineInstr *> &CCUsers, + unsigned ConvOpc) { + int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode()); const MCInstrDesc &Desc = TII->get(Opcode); unsigned MIFlags = Desc.TSFlags; @@ -319,53 +332,72 @@ bool SystemZElimCompare::adjustCCMasksForInstr( unsigned CCValues = SystemZII::getCCValues(MIFlags); assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues"); - // Now check whether these flags are enough for all users. - SmallVector<MachineOperand *, 4> AlterMasks; - for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) { - MachineInstr *MI = CCUsers[I]; - - // Fail if this isn't a use of CC that we understand. - unsigned Flags = MI->getDesc().TSFlags; - unsigned FirstOpNum; - if (Flags & SystemZII::CCMaskFirst) - FirstOpNum = 0; - else if (Flags & SystemZII::CCMaskLast) - FirstOpNum = MI->getNumExplicitOperands() - 2; - else - return false; - - // Check whether the instruction predicate treats all CC values - // outside of ReusableCCMask in the same way. In that case it - // doesn't matter what those CC values mean. - unsigned CCValid = MI->getOperand(FirstOpNum).getImm(); - unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm(); - unsigned OutValid = ~ReusableCCMask & CCValid; - unsigned OutMask = ~ReusableCCMask & CCMask; - if (OutMask != 0 && OutMask != OutValid) - return false; + bool MIEquivalentToCmp = + (ReusableCCMask == CCValues && + CCValues == SystemZII::getCCValues(CompareFlags)); + + if (!MIEquivalentToCmp) { + // Now check whether these flags are enough for all users. + SmallVector<MachineOperand *, 4> AlterMasks; + for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) { + MachineInstr *MI = CCUsers[I]; + + // Fail if this isn't a use of CC that we understand. + unsigned Flags = MI->getDesc().TSFlags; + unsigned FirstOpNum; + if (Flags & SystemZII::CCMaskFirst) + FirstOpNum = 0; + else if (Flags & SystemZII::CCMaskLast) + FirstOpNum = MI->getNumExplicitOperands() - 2; + else + return false; + + // Check whether the instruction predicate treats all CC values + // outside of ReusableCCMask in the same way. In that case it + // doesn't matter what those CC values mean. + unsigned CCValid = MI->getOperand(FirstOpNum).getImm(); + unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm(); + unsigned OutValid = ~ReusableCCMask & CCValid; + unsigned OutMask = ~ReusableCCMask & CCMask; + if (OutMask != 0 && OutMask != OutValid) + return false; + + AlterMasks.push_back(&MI->getOperand(FirstOpNum)); + AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1)); + } - AlterMasks.push_back(&MI->getOperand(FirstOpNum)); - AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1)); + // All users are OK. Adjust the masks for MI. + for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) { + AlterMasks[I]->setImm(CCValues); + unsigned CCMask = AlterMasks[I + 1]->getImm(); + if (CCMask & ~ReusableCCMask) + AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) | + (CCValues & ~ReusableCCMask)); + } } - // All users are OK. Adjust the masks for MI. - for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) { - AlterMasks[I]->setImm(CCValues); - unsigned CCMask = AlterMasks[I + 1]->getImm(); - if (CCMask & ~ReusableCCMask) - AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) | - (CCValues & ~ReusableCCMask)); + // CC is now live after MI. + if (!ConvOpc) { + int CCDef = MI.findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI); + assert(CCDef >= 0 && "Couldn't find CC set"); + MI.getOperand(CCDef).setIsDead(false); } - // CC is now live after MI. - int CCDef = MI.findRegisterDefOperandIdx(SystemZ::CC, false, true, TRI); - assert(CCDef >= 0 && "Couldn't find CC set"); - MI.getOperand(CCDef).setIsDead(false); + // Check if MI lies before Compare. + bool BeforeCmp = false; + MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent()->end(); + for (++MBBI; MBBI != MBBE; ++MBBI) + if (MBBI == Compare) { + BeforeCmp = true; + break; + } // Clear any intervening kills of CC. - MachineBasicBlock::iterator MBBI = MI, MBBE = Compare; - for (++MBBI; MBBI != MBBE; ++MBBI) - MBBI->clearRegisterKills(SystemZ::CC, TRI); + if (BeforeCmp) { + MachineBasicBlock::iterator MBBI = MI, MBBE = Compare; + for (++MBBI; MBBI != MBBE; ++MBBI) + MBBI->clearRegisterKills(SystemZ::CC, TRI); + } return true; } @@ -398,12 +430,12 @@ bool SystemZElimCompare::optimizeCompareZero( // Search back for CC results that are based on the first operand. unsigned SrcReg = getCompareSourceReg(Compare); MachineBasicBlock &MBB = *Compare.getParent(); - MachineBasicBlock::iterator MBBI = Compare, MBBE = MBB.begin(); Reference CCRefs; Reference SrcRefs; - while (MBBI != MBBE) { - --MBBI; - MachineInstr &MI = *MBBI; + for (MachineBasicBlock::reverse_iterator MBBI = + std::next(MachineBasicBlock::reverse_iterator(&Compare)), + MBBE = MBB.rend(); MBBI != MBBE;) { + MachineInstr &MI = *MBBI++; if (resultTests(MI, SrcReg)) { // Try to remove both MI and Compare by converting a branch to BRCT(G). // or a load-and-trap instruction. We don't care in this case whether @@ -419,7 +451,7 @@ bool SystemZElimCompare::optimizeCompareZero( } } // Try to eliminate Compare by reusing a CC result from MI. - if ((!CCRefs && convertToLoadAndTest(MI)) || + if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) || (!CCRefs.Def && adjustCCMasksForInstr(MI, Compare, CCUsers))) { EliminatedComparisons += 1; return true; @@ -434,17 +466,15 @@ bool SystemZElimCompare::optimizeCompareZero( } // Also do a forward search to handle cases where an instruction after the - // compare can be converted like - // - // LTEBRCompare %f0s, %f0s, implicit-def %cc LTEBRCompare %f0s, %f0s, - // implicit-def %cc %f2s = LER %f0s - // - MBBI = Compare, MBBE = MBB.end(); - while (++MBBI != MBBE) { - MachineInstr &MI = *MBBI; + // compare can be converted, like + // LTEBRCompare %f0s, %f0s; %f2s = LER %f0s => LTEBRCompare %f2s, %f0s + for (MachineBasicBlock::iterator MBBI = + std::next(MachineBasicBlock::iterator(&Compare)), MBBE = MBB.end(); + MBBI != MBBE;) { + MachineInstr &MI = *MBBI++; if (preservesValueOf(MI, SrcReg)) { // Try to eliminate Compare by reusing a CC result from MI. - if (convertToLoadAndTest(MI)) { + if (convertToLoadAndTest(MI, Compare, CCUsers)) { EliminatedComparisons += 1; return true; } |