aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-08-05 10:58:53 +0000
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-08-05 10:58:53 +0000
commit66fbb4781841a8411a772b6909a7e0de182b896f (patch)
tree282862d1fa64afb72878b1e7dec031fb42ad3d3f
parent13e6e9171f79a481d7f814aad958460dfd867c71 (diff)
downloadexternal_llvm-66fbb4781841a8411a772b6909a7e0de182b896f.zip
external_llvm-66fbb4781841a8411a772b6909a7e0de182b896f.tar.gz
external_llvm-66fbb4781841a8411a772b6909a7e0de182b896f.tar.bz2
[SystemZ] Split out comparison elimination into a separate pass
Perhaps predictably, doing comparison elimination on the fly during SystemZLongBranch turned out to be a bad idea. The next patches make use of LOAD AND TEST and BRANCH ON COUNT, both of which require changes to earlier instructions. No functionality change intended. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187718 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/SystemZ/CMakeLists.txt1
-rw-r--r--lib/Target/SystemZ/SystemZ.h1
-rw-r--r--lib/Target/SystemZ/SystemZElimCompare.cpp311
-rw-r--r--lib/Target/SystemZ/SystemZLongBranch.cpp281
-rw-r--r--lib/Target/SystemZ/SystemZTargetMachine.cpp22
5 files changed, 346 insertions, 270 deletions
diff --git a/lib/Target/SystemZ/CMakeLists.txt b/lib/Target/SystemZ/CMakeLists.txt
index 04bbec5..cd01f1a 100644
--- a/lib/Target/SystemZ/CMakeLists.txt
+++ b/lib/Target/SystemZ/CMakeLists.txt
@@ -15,6 +15,7 @@ add_llvm_target(SystemZCodeGen
SystemZAsmPrinter.cpp
SystemZCallingConv.cpp
SystemZConstantPoolValue.cpp
+ SystemZElimCompare.cpp
SystemZFrameLowering.cpp
SystemZISelDAGToDAG.cpp
SystemZISelLowering.cpp
diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h
index 4c1e81a..eccc2aa 100644
--- a/lib/Target/SystemZ/SystemZ.h
+++ b/lib/Target/SystemZ/SystemZ.h
@@ -85,6 +85,7 @@ namespace llvm {
FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM,
CodeGenOpt::Level OptLevel);
+ FunctionPass *createSystemZElimComparePass(SystemZTargetMachine &TM);
FunctionPass *createSystemZLongBranchPass(SystemZTargetMachine &TM);
} // end namespace llvm;
#endif
diff --git a/lib/Target/SystemZ/SystemZElimCompare.cpp b/lib/Target/SystemZ/SystemZElimCompare.cpp
new file mode 100644
index 0000000..9b0bdd8
--- /dev/null
+++ b/lib/Target/SystemZ/SystemZElimCompare.cpp
@@ -0,0 +1,311 @@
+//===-- SystemZElimCompare.cpp - Eliminate comparison instructions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass:
+// (1) tries to remove compares if CC already contains the required information
+// (2) fuses compares and branches into COMPARE AND BRANCH instructions
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "systemz-elim-compare"
+
+#include "SystemZTargetMachine.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
+STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
+
+namespace {
+ class SystemZElimCompare : public MachineFunctionPass {
+ public:
+ static char ID;
+ SystemZElimCompare(const SystemZTargetMachine &tm)
+ : MachineFunctionPass(ID), TII(0), TRI(0) {}
+
+ virtual const char *getPassName() const {
+ return "SystemZ Comparison Elimination";
+ }
+
+ bool processBlock(MachineBasicBlock *MBB);
+ bool runOnMachineFunction(MachineFunction &F);
+
+ private:
+ bool adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers);
+ bool optimizeCompareZero(MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers);
+ bool fuseCompareAndBranch(MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers);
+
+ const SystemZInstrInfo *TII;
+ const TargetRegisterInfo *TRI;
+ };
+
+ char SystemZElimCompare::ID = 0;
+} // end of anonymous namespace
+
+FunctionPass *llvm::createSystemZElimComparePass(SystemZTargetMachine &TM) {
+ return new SystemZElimCompare(TM);
+}
+
+// Return true if CC is live out of MBB.
+static bool isCCLiveOut(MachineBasicBlock *MBB) {
+ for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
+ SE = MBB->succ_end(); SI != SE; ++SI)
+ if ((*SI)->isLiveIn(SystemZ::CC))
+ return true;
+ return false;
+}
+
+// Return true if any CC result of MI would reflect the value of subreg
+// SubReg of Reg.
+static bool resultTests(MachineInstr *MI, unsigned Reg, unsigned SubReg) {
+ if (MI->getNumOperands() > 0 &&
+ MI->getOperand(0).isReg() &&
+ MI->getOperand(0).isDef() &&
+ MI->getOperand(0).getReg() == Reg &&
+ MI->getOperand(0).getSubReg() == SubReg)
+ return true;
+
+ return false;
+}
+
+// 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.
+bool SystemZElimCompare::
+adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers) {
+ int Opcode = MI->getOpcode();
+ const MCInstrDesc &Desc = TII->get(Opcode);
+ unsigned MIFlags = Desc.TSFlags;
+
+ // See which compare-style condition codes are available.
+ unsigned ReusableCCMask = 0;
+ if (MIFlags & SystemZII::CCHasZero)
+ ReusableCCMask |= SystemZ::CCMASK_CMP_EQ;
+
+ // For unsigned comparisons with zero, only equality makes sense.
+ unsigned CompareFlags = Compare->getDesc().TSFlags;
+ if (!(CompareFlags & SystemZII::IsLogical) &&
+ (MIFlags & SystemZII::CCHasOrder))
+ ReusableCCMask |= SystemZ::CCMASK_CMP_LT | SystemZ::CCMASK_CMP_GT;
+
+ if (ReusableCCMask == 0)
+ return false;
+
+ 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;
+
+ 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));
+ }
+
+ // 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);
+
+ // Clear any intervening kills of CC.
+ MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;
+ for (++MBBI; MBBI != MBBE; ++MBBI)
+ MBBI->clearRegisterKills(SystemZ::CC, TRI);
+
+ return true;
+}
+
+// Try to optimize cases where comparison instruction Compare is testing
+// a value against zero. Return true on success and if Compare should be
+// deleted as dead. CCUsers is the list of instructions that use the CC
+// value produced by Compare.
+bool SystemZElimCompare::
+optimizeCompareZero(MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers) {
+ // Check whether this is a comparison against zero.
+ if (Compare->getNumExplicitOperands() != 2 ||
+ !Compare->getOperand(1).isImm() ||
+ Compare->getOperand(1).getImm() != 0)
+ return false;
+
+ // Search back for CC results that are based on the first operand.
+ unsigned SrcReg = Compare->getOperand(0).getReg();
+ unsigned SrcSubReg = Compare->getOperand(0).getSubReg();
+ MachineBasicBlock *MBB = Compare->getParent();
+ MachineBasicBlock::iterator MBBI = Compare, MBBE = MBB->begin();
+ while (MBBI != MBBE) {
+ --MBBI;
+ MachineInstr *MI = MBBI;
+ if (resultTests(MI, SrcReg, SrcSubReg) &&
+ adjustCCMasksForInstr(MI, Compare, CCUsers)) {
+ EliminatedComparisons += 1;
+ return true;
+ }
+ if (MI->modifiesRegister(SrcReg, TRI) ||
+ MI->modifiesRegister(SystemZ::CC, TRI))
+ return false;
+ }
+ return false;
+}
+
+// Try to fuse comparison instruction Compare into a later branch.
+// Return true on success and if Compare is therefore redundant.
+bool SystemZElimCompare::
+fuseCompareAndBranch(MachineInstr *Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers) {
+ // See whether we have a comparison that can be fused.
+ unsigned FusedOpcode = TII->getCompareAndBranch(Compare->getOpcode(),
+ Compare);
+ if (!FusedOpcode)
+ return false;
+
+ // See whether we have a single branch with which to fuse.
+ if (CCUsers.size() != 1)
+ return false;
+ MachineInstr *Branch = CCUsers[0];
+ if (Branch->getOpcode() != SystemZ::BRC)
+ return false;
+
+ // Make sure that the operands are available at the branch.
+ unsigned SrcReg = Compare->getOperand(0).getReg();
+ unsigned SrcReg2 = (Compare->getOperand(1).isReg() ?
+ Compare->getOperand(1).getReg() : 0);
+ MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
+ for (++MBBI; MBBI != MBBE; ++MBBI)
+ if (MBBI->modifiesRegister(SrcReg, TRI) ||
+ (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
+ return false;
+
+ // Read the branch mask and target.
+ MachineOperand CCMask(MBBI->getOperand(1));
+ MachineOperand Target(MBBI->getOperand(2));
+ assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&
+ "Invalid condition-code mask for integer comparison");
+
+ // Clear out all current operands.
+ int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
+ assert(CCUse >= 0 && "BRC must use CC");
+ Branch->RemoveOperand(CCUse);
+ Branch->RemoveOperand(2);
+ Branch->RemoveOperand(1);
+ Branch->RemoveOperand(0);
+
+ // Rebuild Branch as a fused compare and branch.
+ Branch->setDesc(TII->get(FusedOpcode));
+ MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
+ .addOperand(Compare->getOperand(0))
+ .addOperand(Compare->getOperand(1))
+ .addOperand(CCMask)
+ .addOperand(Target)
+ .addReg(SystemZ::CC, RegState::ImplicitDefine);
+
+ // Clear any intervening kills of SrcReg and SrcReg2.
+ MBBI = Compare;
+ for (++MBBI; MBBI != MBBE; ++MBBI) {
+ MBBI->clearRegisterKills(SrcReg, TRI);
+ if (SrcReg2)
+ MBBI->clearRegisterKills(SrcReg2, TRI);
+ }
+ FusedComparisons += 1;
+ return true;
+}
+
+// Process all comparison instructions in MBB. Return true if something
+// changed.
+bool SystemZElimCompare::processBlock(MachineBasicBlock *MBB) {
+ bool Changed = false;
+
+ // Walk backwards through the block looking for comparisons, recording
+ // all CC users as we go. The subroutines can delete Compare and
+ // instructions before it.
+ bool CompleteCCUsers = !isCCLiveOut(MBB);
+ SmallVector<MachineInstr *, 4> CCUsers;
+ MachineBasicBlock::iterator MBBI = MBB->end();
+ while (MBBI != MBB->begin()) {
+ MachineInstr *MI = --MBBI;
+ if (CompleteCCUsers &&
+ MI->isCompare() &&
+ (optimizeCompareZero(MI, CCUsers) ||
+ fuseCompareAndBranch(MI, CCUsers))) {
+ ++MBBI;
+ MI->removeFromParent();
+ Changed = true;
+ CCUsers.clear();
+ CompleteCCUsers = true;
+ continue;
+ }
+
+ if (MI->definesRegister(SystemZ::CC, TRI)) {
+ CCUsers.clear();
+ CompleteCCUsers = true;
+ } else if (MI->modifiesRegister(SystemZ::CC, TRI))
+ CompleteCCUsers = false;
+
+ if (CompleteCCUsers && MI->readsRegister(SystemZ::CC, TRI))
+ CCUsers.push_back(MI);
+ }
+ return Changed;
+}
+
+bool SystemZElimCompare::runOnMachineFunction(MachineFunction &F) {
+ TII = static_cast<const SystemZInstrInfo *>(F.getTarget().getInstrInfo());
+ TRI = &TII->getRegisterInfo();
+
+ bool Changed = false;
+ for (MachineFunction::iterator MFI = F.begin(), MFE = F.end();
+ MFI != MFE; ++MFI)
+ Changed |= processBlock(MFI);
+
+ return Changed;
+}
diff --git a/lib/Target/SystemZ/SystemZLongBranch.cpp b/lib/Target/SystemZ/SystemZLongBranch.cpp
index f0ea3e2..c5c4cab 100644
--- a/lib/Target/SystemZ/SystemZLongBranch.cpp
+++ b/lib/Target/SystemZ/SystemZLongBranch.cpp
@@ -7,44 +7,16 @@
//
//===----------------------------------------------------------------------===//
//
-// This pass does three things:
-// (1) try to remove compares if CC already contains the required information
-// (2) fuse compares and branches into COMPARE AND BRANCH instructions
-// (3) make sure that all branches are in range.
-//
-// We do (1) here rather than earlier because some transformations can
-// change the set of available CC values and we generally want those
-// transformations to have priority over (1). This is especially true in
-// the commonest case where the CC value is used by a single in-range branch
-// instruction, since (2) will then be able to fuse the compare and the
-// branch instead.
-//
-// For example, two-address NILF can sometimes be converted into
-// three-address RISBLG. NILF produces a CC value that indicates whether
-// the low word is zero, but RISBLG does not modify CC at all. On the
-// other hand, 64-bit ANDs like NILL can sometimes be converted to RISBG.
-// The CC value produced by NILL isn't useful for our purposes, but the
-// value produced by RISBG can be used for any comparison with zero
-// (not just equality). So there are some transformations that lose
-// CC values (while still being worthwhile) and others that happen to make
-// the CC result more useful than it was originally.
-//
-// We do (2) here rather than earlier because the fused form prevents
-// predication. It also has to happen after (1).
-//
-// Doing (2) so late makes it more likely that a register will be reused
-// between the compare and the branch, but it isn't clear whether preventing
-// that would be a win or not.
-//
-// There are several ways in which (3) could be done. One aggressive
-// approach is to assume that all branches are in range and successively
-// replace those that turn out not to be in range with a longer form
-// (branch relaxation). A simple implementation is to continually walk
-// through the function relaxing branches until no more changes are
-// needed and a fixed point is reached. However, in the pathological
-// worst case, this implementation is quadratic in the number of blocks;
-// relaxing branch N can make branch N-1 go out of range, which in turn
-// can make branch N-2 go out of range, and so on.
+// This pass makes sure that all branches are in range. There are several ways
+// in which this could be done. One aggressive approach is to assume that all
+// branches are in range and successively replace those that turn out not
+// to be in range with a longer form (branch relaxation). A simple
+// implementation is to continually walk through the function relaxing
+// branches until no more changes are needed and a fixed point is reached.
+// However, in the pathological worst case, this implementation is
+// quadratic in the number of blocks; relaxing branch N can make branch N-1
+// go out of range, which in turn can make branch N-2 go out of range,
+// and so on.
//
// An alternative approach is to assume that all branches must be
// converted to their long forms, then reinstate the short forms of
@@ -99,8 +71,6 @@ using namespace llvm;
STATISTIC(LongBranches, "Number of long branches.");
namespace {
- typedef MachineBasicBlock::iterator Iter;
-
// Represents positional information about a basic block.
struct MBBInfo {
// The address that we currently assume the block has.
@@ -174,8 +144,6 @@ namespace {
void skipTerminator(BlockPosition &Position, TerminatorInfo &Terminator,
bool AssumeRelaxed);
TerminatorInfo describeTerminator(MachineInstr *MI);
- bool optimizeCompareZero(MachineInstr *PrevCCSetter, MachineInstr *Compare);
- bool fuseCompareAndBranch(MachineInstr *Compare);
uint64_t initMBBInfo();
bool mustRelaxBranch(const TerminatorInfo &Terminator, uint64_t Address);
bool mustRelaxABranch();
@@ -273,226 +241,10 @@ TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr *MI) {
return Terminator;
}
-// Return true if CC is live out of MBB.
-static bool isCCLiveOut(MachineBasicBlock *MBB) {
- for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
- SE = MBB->succ_end(); SI != SE; ++SI)
- if ((*SI)->isLiveIn(SystemZ::CC))
- return true;
- return false;
-}
-
-// Return true if CC is live after MBBI.
-static bool isCCLiveAfter(MachineBasicBlock::iterator MBBI,
- const TargetRegisterInfo *TRI) {
- if (MBBI->killsRegister(SystemZ::CC, TRI))
- return false;
-
- MachineBasicBlock *MBB = MBBI->getParent();
- MachineBasicBlock::iterator MBBE = MBB->end();
- for (++MBBI; MBBI != MBBE; ++MBBI) {
- if (MBBI->readsRegister(SystemZ::CC, TRI))
- return true;
- if (MBBI->definesRegister(SystemZ::CC, TRI))
- return false;
- }
-
- return isCCLiveOut(MBB);
-}
-
-// Return true if all uses of the CC value produced by MBBI could make do
-// with the CC values in ReusableCCMask. When returning true, point AlterMasks
-// to the "CC valid" and "CC mask" operands for each condition.
-static bool canRestrictCCMask(MachineBasicBlock::iterator MBBI,
- unsigned ReusableCCMask,
- SmallVectorImpl<MachineOperand *> &AlterMasks,
- const TargetRegisterInfo *TRI) {
- MachineBasicBlock *MBB = MBBI->getParent();
- MachineBasicBlock::iterator MBBE = MBB->end();
- for (++MBBI; MBBI != MBBE; ++MBBI) {
- if (MBBI->readsRegister(SystemZ::CC, TRI)) {
- // Fail if this isn't a use of CC that we understand.
- unsigned MBBIFlags = MBBI->getDesc().TSFlags;
- unsigned FirstOpNum;
- if (MBBIFlags & SystemZII::CCMaskFirst)
- FirstOpNum = 0;
- else if (MBBIFlags & SystemZII::CCMaskLast)
- FirstOpNum = MBBI->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 = MBBI->getOperand(FirstOpNum).getImm();
- unsigned CCMask = MBBI->getOperand(FirstOpNum + 1).getImm();
- unsigned OutValid = ~ReusableCCMask & CCValid;
- unsigned OutMask = ~ReusableCCMask & CCMask;
- if (OutMask != 0 && OutMask != OutValid)
- return false;
-
- AlterMasks.push_back(&MBBI->getOperand(FirstOpNum));
- AlterMasks.push_back(&MBBI->getOperand(FirstOpNum + 1));
-
- // Succeed if this was the final use of the CC value.
- if (MBBI->killsRegister(SystemZ::CC, TRI))
- return true;
- }
- // Succeed if the instruction redefines CC.
- if (MBBI->definesRegister(SystemZ::CC, TRI))
- return true;
- }
- // Fail if there are other uses of CC that we didn't see.
- return !isCCLiveOut(MBB);
-}
-
-// Try to make Compare redundant with PrevCCSetter, the previous setter of CC,
-// by looking for cases where Compare compares the result of PrevCCSetter
-// against zero. Return true on success and if Compare can therefore
-// be deleted.
-bool SystemZLongBranch::optimizeCompareZero(MachineInstr *PrevCCSetter,
- MachineInstr *Compare) {
- if (MF->getTarget().getOptLevel() == CodeGenOpt::None)
- return false;
-
- // Check whether this is a comparison against zero.
- if (Compare->getNumExplicitOperands() != 2 ||
- !Compare->getOperand(1).isImm() ||
- Compare->getOperand(1).getImm() != 0)
- return false;
-
- // See which compare-style condition codes are available after PrevCCSetter.
- unsigned PrevFlags = PrevCCSetter->getDesc().TSFlags;
- unsigned ReusableCCMask = 0;
- if (PrevFlags & SystemZII::CCHasZero)
- ReusableCCMask |= SystemZ::CCMASK_CMP_EQ;
-
- // For unsigned comparisons with zero, only equality makes sense.
- unsigned CompareFlags = Compare->getDesc().TSFlags;
- if (!(CompareFlags & SystemZII::IsLogical) &&
- (PrevFlags & SystemZII::CCHasOrder))
- ReusableCCMask |= SystemZ::CCMASK_CMP_LT | SystemZ::CCMASK_CMP_GT;
-
- if (ReusableCCMask == 0)
- return false;
-
- // Make sure that PrevCCSetter sets the value being compared.
- unsigned SrcReg = Compare->getOperand(0).getReg();
- unsigned SrcSubReg = Compare->getOperand(0).getSubReg();
- if (!PrevCCSetter->getOperand(0).isReg() ||
- !PrevCCSetter->getOperand(0).isDef() ||
- PrevCCSetter->getOperand(0).getReg() != SrcReg ||
- PrevCCSetter->getOperand(0).getSubReg() != SrcSubReg)
- return false;
-
- // Make sure that SrcReg survives until Compare.
- MachineBasicBlock::iterator MBBI = PrevCCSetter, MBBE = Compare;
- const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
- for (++MBBI; MBBI != MBBE; ++MBBI)
- if (MBBI->modifiesRegister(SrcReg, TRI))
- return false;
-
- // See whether all uses of Compare's CC value could make do with
- // the values produced by PrevCCSetter.
- SmallVector<MachineOperand *, 4> AlterMasks;
- if (!canRestrictCCMask(Compare, ReusableCCMask, AlterMasks, TRI))
- return false;
-
- // Alter the CC masks that canRestrictCCMask says need to be altered.
- unsigned CCValues = SystemZII::getCCValues(PrevFlags);
- assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
- 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 PrevCCSetter.
- int CCDef = PrevCCSetter->findRegisterDefOperandIdx(SystemZ::CC, false,
- true, TRI);
- assert(CCDef >= 0 && "Couldn't find CC set");
- PrevCCSetter->getOperand(CCDef).setIsDead(false);
-
- // Clear any intervening kills of CC.
- MBBI = PrevCCSetter;
- for (++MBBI; MBBI != MBBE; ++MBBI)
- MBBI->clearRegisterKills(SystemZ::CC, TRI);
-
- return true;
-}
-
-// Try to fuse compare instruction Compare into a later branch. Return
-// true on success and if Compare is therefore redundant.
-bool SystemZLongBranch::fuseCompareAndBranch(MachineInstr *Compare) {
- if (MF->getTarget().getOptLevel() == CodeGenOpt::None)
- return false;
-
- unsigned FusedOpcode = TII->getCompareAndBranch(Compare->getOpcode(),
- Compare);
- if (!FusedOpcode)
- return false;
-
- unsigned SrcReg = Compare->getOperand(0).getReg();
- unsigned SrcReg2 = (Compare->getOperand(1).isReg() ?
- Compare->getOperand(1).getReg() : 0);
- const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
- MachineBasicBlock *MBB = Compare->getParent();
- MachineBasicBlock::iterator MBBI = Compare, MBBE = MBB->end();
- for (++MBBI; MBBI != MBBE; ++MBBI) {
- if (MBBI->getOpcode() == SystemZ::BRC && !isCCLiveAfter(MBBI, TRI)) {
- // Read the branch mask and target.
- MachineOperand CCMask(MBBI->getOperand(1));
- MachineOperand Target(MBBI->getOperand(2));
- assert((CCMask.getImm() & ~SystemZ::CCMASK_ICMP) == 0 &&
- "Invalid condition-code mask for integer comparison");
-
- // Clear out all current operands.
- int CCUse = MBBI->findRegisterUseOperandIdx(SystemZ::CC, false, TRI);
- assert(CCUse >= 0 && "BRC must use CC");
- MBBI->RemoveOperand(CCUse);
- MBBI->RemoveOperand(2);
- MBBI->RemoveOperand(1);
- MBBI->RemoveOperand(0);
-
- // Rebuild MBBI as a fused compare and branch.
- MBBI->setDesc(TII->get(FusedOpcode));
- MachineInstrBuilder(*MBB->getParent(), MBBI)
- .addOperand(Compare->getOperand(0))
- .addOperand(Compare->getOperand(1))
- .addOperand(CCMask)
- .addOperand(Target);
-
- // Clear any intervening kills of SrcReg and SrcReg2.
- MBBI = Compare;
- for (++MBBI; MBBI != MBBE; ++MBBI) {
- MBBI->clearRegisterKills(SrcReg, TRI);
- if (SrcReg2)
- MBBI->clearRegisterKills(SrcReg2, TRI);
- }
- return true;
- }
-
- // Stop if we find another reference to CC before a branch.
- if (MBBI->readsRegister(SystemZ::CC, TRI) ||
- MBBI->modifiesRegister(SystemZ::CC, TRI))
- return false;
-
- // Stop if we find another assignment to the registers before the branch.
- if (MBBI->modifiesRegister(SrcReg, TRI) ||
- (SrcReg2 && MBBI->modifiesRegister(SrcReg2, TRI)))
- return false;
- }
- return false;
-}
-
// Fill MBBs and Terminators, setting the addresses on the assumption
// that no branches need relaxation. Return the size of the function under
// this assumption.
uint64_t SystemZLongBranch::initMBBInfo() {
- const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
-
MF->RenumberBlocks();
unsigned NumBlocks = MF->size();
@@ -513,20 +265,9 @@ uint64_t SystemZLongBranch::initMBBInfo() {
// Calculate the size of the fixed part of the block.
MachineBasicBlock::iterator MI = MBB->begin();
MachineBasicBlock::iterator End = MBB->end();
- MachineInstr *PrevCCSetter = 0;
while (MI != End && !MI->isTerminator()) {
- MachineInstr *Current = MI;
+ Block.Size += TII->getInstSizeInBytes(MI);
++MI;
- if (Current->isCompare()) {
- if ((PrevCCSetter && optimizeCompareZero(PrevCCSetter, Current)) ||
- fuseCompareAndBranch(Current)) {
- Current->removeFromParent();
- continue;
- }
- }
- if (Current->modifiesRegister(SystemZ::CC, TRI))
- PrevCCSetter = Current;
- Block.Size += TII->getInstSizeInBytes(Current);
}
skipNonTerminators(Position, Block);
diff --git a/lib/Target/SystemZ/SystemZTargetMachine.cpp b/lib/Target/SystemZ/SystemZTargetMachine.cpp
index 437ea61..2bacc2b 100644
--- a/lib/Target/SystemZ/SystemZTargetMachine.cpp
+++ b/lib/Target/SystemZ/SystemZTargetMachine.cpp
@@ -65,6 +65,28 @@ bool SystemZPassConfig::addPreSched2() {
}
bool SystemZPassConfig::addPreEmitPass() {
+ // We eliminate comparisons here rather than earlier because some
+ // transformations can change the set of available CC values and we
+ // generally want those transformations to have priority. This is
+ // especially true in the commonest case where the result of the comparison
+ // is used by a single in-range branch instruction, since we will then
+ // be able to fuse the compare and the branch instead.
+ //
+ // For example, two-address NILF can sometimes be converted into
+ // three-address RISBLG. NILF produces a CC value that indicates whether
+ // the low word is zero, but RISBLG does not modify CC at all. On the
+ // other hand, 64-bit ANDs like NILL can sometimes be converted to RISBG.
+ // The CC value produced by NILL isn't useful for our purposes, but the
+ // value produced by RISBG can be used for any comparison with zero
+ // (not just equality). So there are some transformations that lose
+ // CC values (while still being worthwhile) and others that happen to make
+ // the CC result more useful than it was originally.
+ //
+ // Doing it so late makes it more likely that a register will be reused
+ // between the comparison and the branch, but it isn't clear whether
+ // preventing that would be a win or not.
+ if (getOptLevel() != CodeGenOpt::None)
+ addPass(createSystemZElimComparePass(getSystemZTargetMachine()));
addPass(createSystemZLongBranchPass(getSystemZTargetMachine()));
return true;
}