[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
This commit is contained in:
Richard Sandiford
2013-08-12 10:28:10 +00:00
parent e03a56d62f
commit ac168b8bc8
12 changed files with 324 additions and 12 deletions

View File

@@ -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) {