summaryrefslogtreecommitdiff
path: root/lib/Target/SystemZ/SystemZInstrInfo.cpp
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-08-12 10:28:10 +0000
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>2013-08-12 10:28:10 +0000
commitac168b8bc8773a083a10902f64e4ae57a925aee4 (patch)
treef01bc6788d39669344e52a5304fbe7859ebc8702 /lib/Target/SystemZ/SystemZInstrInfo.cpp
parente03a56d62fc623e2f72d623b816f91b293d5904b (diff)
downloadllvm-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.cpp93
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) {