diff options
author | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-08-12 10:28:10 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@linux.vnet.ibm.com> | 2013-08-12 10:28:10 +0000 |
commit | ac168b8bc8773a083a10902f64e4ae57a925aee4 (patch) | |
tree | f01bc6788d39669344e52a5304fbe7859ebc8702 /lib/Target/SystemZ/SystemZInstrInfo.cpp | |
parent | e03a56d62fc623e2f72d623b816f91b293d5904b (diff) | |
download | llvm-ac168b8bc8773a083a10902f64e4ae57a925aee4.tar.gz llvm-ac168b8bc8773a083a10902f64e4ae57a925aee4.tar.bz2 llvm-ac168b8bc8773a083a10902f64e4ae57a925aee4.tar.xz |
[SystemZ] Use CLC and IPM to implement memcmp
For now this is restricted to fixed-length comparisons with a length
in the range [1, 256], as for memcpy() and MVC.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188163 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/SystemZ/SystemZInstrInfo.cpp')
-rw-r--r-- | lib/Target/SystemZ/SystemZInstrInfo.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp index 9ee60aa80c..54a8669359 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -293,6 +293,99 @@ SystemZInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, return Count; } +bool SystemZInstrInfo::analyzeCompare(const MachineInstr *MI, + unsigned &SrcReg, unsigned &SrcReg2, + int &Mask, int &Value) const { + assert(MI->isCompare() && "Caller should have checked for a comparison"); + + if (MI->getNumExplicitOperands() == 2 && + MI->getOperand(0).isReg() && + MI->getOperand(1).isImm()) { + SrcReg = MI->getOperand(0).getReg(); + SrcReg2 = 0; + Value = MI->getOperand(1).getImm(); + Mask = ~0; + return true; + } + + return false; +} + +// If Reg is a virtual register that is used by only a single non-debug +// instruction, return the defining instruction, otherwise return null. +static MachineInstr *getDefSingleUse(const MachineRegisterInfo *MRI, + unsigned Reg) { + if (TargetRegisterInfo::isPhysicalRegister(Reg)) + return 0; + + MachineRegisterInfo::use_nodbg_iterator I = MRI->use_nodbg_begin(Reg); + MachineRegisterInfo::use_nodbg_iterator E = MRI->use_nodbg_end(); + if (I == E || llvm::next(I) != E) + return 0; + + return MRI->getUniqueVRegDef(Reg); +} + +// Return true if MI is a shift of type Opcode by Imm bits. +static bool isShift(MachineInstr *MI, int Opcode, int64_t Imm) { + return (MI->getOpcode() == Opcode && + !MI->getOperand(2).getReg() && + MI->getOperand(3).getImm() == Imm); +} + +// Compare compares SrcReg against zero. Check whether SrcReg contains +// the result of an IPM sequence that is only used by Compare. Try to +// delete both of them if so and return true if a change was made. +static bool removeIPM(MachineInstr *Compare, unsigned SrcReg, + const MachineRegisterInfo *MRI, + const TargetRegisterInfo *TRI) { + MachineInstr *SRA = getDefSingleUse(MRI, SrcReg); + if (!SRA || !isShift(SRA, SystemZ::SRA, 30)) + return false; + + MachineInstr *SLL = getDefSingleUse(MRI, SRA->getOperand(1).getReg()); + if (!SLL || !isShift(SLL, SystemZ::SLL, 2)) + return false; + + MachineInstr *IPM = getDefSingleUse(MRI, SLL->getOperand(1).getReg()); + if (!IPM || IPM->getOpcode() != SystemZ::IPM) + return false; + + // Check that there are no assignments to CC between the IPM and Compare, + // except for the SRA that we'd like to delete. We can ignore SLL because + // it does not assign to CC. We can also ignore uses of the SRA CC result, + // since it is effectively restoring CC to the value it had before IPM + // (for all current use cases). + if (IPM->getParent() != Compare->getParent()) + return false; + MachineBasicBlock::iterator MBBI = IPM, MBBE = Compare; + for (++MBBI; MBBI != MBBE; ++MBBI) { + MachineInstr *MI = MBBI; + if (MI != SRA && MI->modifiesRegister(SystemZ::CC, TRI)) + return false; + } + + IPM->eraseFromParent(); + SLL->eraseFromParent(); + SRA->eraseFromParent(); + Compare->eraseFromParent(); + return true; +} + +bool +SystemZInstrInfo::optimizeCompareInstr(MachineInstr *Compare, + unsigned SrcReg, unsigned SrcReg2, + int Mask, int Value, + const MachineRegisterInfo *MRI) const { + assert(!SrcReg2 && "Only optimizing constant comparisons so far"); + bool IsLogical = (Compare->getDesc().TSFlags & SystemZII::IsLogical) != 0; + if (Value == 0 && + !IsLogical && + removeIPM(Compare, SrcReg, MRI, TM.getRegisterInfo())) + return true; + return false; +} + // If Opcode is a move that has a conditional variant, return that variant, // otherwise return 0. static unsigned getConditionalMove(unsigned Opcode) { |