mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-24 22:24:54 +00:00
[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:
@@ -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) {
|
||||
|
Reference in New Issue
Block a user