From 66fbb4781841a8411a772b6909a7e0de182b896f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 5 Aug 2013 10:58:53 +0000 Subject: [PATCH] [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 --- lib/Target/SystemZ/CMakeLists.txt | 1 + lib/Target/SystemZ/SystemZ.h | 1 + lib/Target/SystemZ/SystemZElimCompare.cpp | 311 ++++++++++++++++++++ lib/Target/SystemZ/SystemZLongBranch.cpp | 281 +----------------- lib/Target/SystemZ/SystemZTargetMachine.cpp | 22 ++ 5 files changed, 346 insertions(+), 270 deletions(-) create mode 100644 lib/Target/SystemZ/SystemZElimCompare.cpp diff --git a/lib/Target/SystemZ/CMakeLists.txt b/lib/Target/SystemZ/CMakeLists.txt index 04bbec5127e..cd01f1a5618 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 4c1e81a082c..eccc2aa4d52 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 00000000000..9b0bdd8505e --- /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 &CCUsers); + bool optimizeCompareZero(MachineInstr *Compare, + SmallVectorImpl &CCUsers); + bool fuseCompareAndBranch(MachineInstr *Compare, + SmallVectorImpl &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 &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 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 &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 &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 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(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 f0ea3e20be6..c5c4cab6afd 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 &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 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 437ea615582..2bacc2bc24f 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; }