summaryrefslogtreecommitdiff
path: root/lib/Target/SystemZ/SystemZElimCompare.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Target/SystemZ/SystemZElimCompare.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/Target/SystemZ/SystemZElimCompare.cpp')
-rw-r--r--lib/Target/SystemZ/SystemZElimCompare.cpp164
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;
}