//===----------------------------------------------------------------------===//
#include "SystemZInstrInfo.h"
+#include "SystemZTargetMachine.h"
#include "SystemZInstrBuilder.h"
-#include "llvm/Target/TargetMachine.h"
+#include "llvm/CodeGen/LiveVariables.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#define GET_INSTRINFO_CTOR
#define GET_INSTRMAP_INFO
SystemZInstrInfo::SystemZInstrInfo(SystemZTargetMachine &tm)
: SystemZGenInstrInfo(SystemZ::ADJCALLSTACKDOWN, SystemZ::ADJCALLSTACKUP),
- RI(tm, *this) {
+ RI(tm), TM(tm) {
}
// MI is a 128-bit load or store. Split it into two 64-bit loads or stores,
// Return 0 otherwise.
//
// Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
-static int isSimpleMove(const MachineInstr *MI, int &FrameIndex, int Flag) {
+static int isSimpleMove(const MachineInstr *MI, int &FrameIndex,
+ unsigned Flag) {
const MCInstrDesc &MCID = MI->getDesc();
if ((MCID.TSFlags & Flag) &&
MI->getOperand(1).isFI() &&
return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXStore);
}
+bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr *MI,
+ int &DestFrameIndex,
+ int &SrcFrameIndex) const {
+ // Check for MVC 0(Length,FI1),0(FI2)
+ const MachineFrameInfo *MFI = MI->getParent()->getParent()->getFrameInfo();
+ if (MI->getOpcode() != SystemZ::MVC ||
+ !MI->getOperand(0).isFI() ||
+ MI->getOperand(1).getImm() != 0 ||
+ !MI->getOperand(3).isFI() ||
+ MI->getOperand(4).getImm() != 0)
+ return false;
+
+ // Check that Length covers the full slots.
+ int64_t Length = MI->getOperand(2).getImm();
+ unsigned FI1 = MI->getOperand(0).getIndex();
+ unsigned FI2 = MI->getOperand(3).getIndex();
+ if (MFI->getObjectSize(FI1) != Length ||
+ MFI->getObjectSize(FI2) != Length)
+ return false;
+
+ DestFrameIndex = FI1;
+ SrcFrameIndex = FI2;
+ return true;
+}
+
bool SystemZInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
// A terminator that isn't a branch can't easily be handled by this
// analysis.
- unsigned ThisCond;
- const MachineOperand *ThisTarget;
- if (!isBranch(I, ThisCond, ThisTarget))
+ if (!I->isBranch())
return true;
// Can't handle indirect branches.
- if (!ThisTarget->isMBB())
+ SystemZII::Branch Branch(getBranchInfo(I));
+ if (!Branch.Target->isMBB())
+ return true;
+
+ // Punt on compound branches.
+ if (Branch.Type != SystemZII::BranchNormal)
return true;
- if (ThisCond == SystemZ::CCMASK_ANY) {
+ if (Branch.CCMask == SystemZ::CCMASK_ANY) {
// Handle unconditional branches.
if (!AllowModify) {
- TBB = ThisTarget->getMBB();
+ TBB = Branch.Target->getMBB();
continue;
}
FBB = 0;
// Delete the JMP if it's equivalent to a fall-through.
- if (MBB.isLayoutSuccessor(ThisTarget->getMBB())) {
+ if (MBB.isLayoutSuccessor(Branch.Target->getMBB())) {
TBB = 0;
I->eraseFromParent();
I = MBB.end();
}
// TBB is used to indicate the unconditinal destination.
- TBB = ThisTarget->getMBB();
+ TBB = Branch.Target->getMBB();
continue;
}
if (Cond.empty()) {
// FIXME: add X86-style branch swap
FBB = TBB;
- TBB = ThisTarget->getMBB();
- Cond.push_back(MachineOperand::CreateImm(ThisCond));
+ TBB = Branch.Target->getMBB();
+ Cond.push_back(MachineOperand::CreateImm(Branch.CCMask));
continue;
}
// Only handle the case where all conditional branches branch to the same
// destination.
- if (TBB != ThisTarget->getMBB())
+ if (TBB != Branch.Target->getMBB())
return true;
// If the conditions are the same, we can leave them alone.
unsigned OldCond = Cond[0].getImm();
- if (OldCond == ThisCond)
+ if (OldCond == Branch.CCMask)
continue;
// FIXME: Try combining conditions like X86 does. Should be easy on Z!
--I;
if (I->isDebugValue())
continue;
- unsigned Cond;
- const MachineOperand *Target;
- if (!isBranch(I, Cond, Target))
+ if (!I->isBranch())
break;
- if (!Target->isMBB())
+ if (!getBranchInfo(I).Target->isMBB())
break;
// Remove the branch.
I->eraseFromParent();
return Count;
}
+// If Opcode is a move that has a conditional variant, return that variant,
+// otherwise return 0.
+static unsigned getConditionalMove(unsigned Opcode) {
+ switch (Opcode) {
+ case SystemZ::LR: return SystemZ::LOCR;
+ case SystemZ::LGR: return SystemZ::LOCGR;
+ default: return 0;
+ }
+}
+
+bool SystemZInstrInfo::isPredicable(MachineInstr *MI) const {
+ unsigned Opcode = MI->getOpcode();
+ if (TM.getSubtargetImpl()->hasLoadStoreOnCond() &&
+ getConditionalMove(Opcode))
+ return true;
+ return false;
+}
+
+bool SystemZInstrInfo::
+isProfitableToIfCvt(MachineBasicBlock &MBB,
+ unsigned NumCycles, unsigned ExtraPredCycles,
+ const BranchProbability &Probability) const {
+ // For now only convert single instructions.
+ return NumCycles == 1;
+}
+
+bool SystemZInstrInfo::
+isProfitableToIfCvt(MachineBasicBlock &TMBB,
+ unsigned NumCyclesT, unsigned ExtraPredCyclesT,
+ MachineBasicBlock &FMBB,
+ unsigned NumCyclesF, unsigned ExtraPredCyclesF,
+ const BranchProbability &Probability) const {
+ // For now avoid converting mutually-exclusive cases.
+ return false;
+}
+
+bool SystemZInstrInfo::
+PredicateInstruction(MachineInstr *MI,
+ const SmallVectorImpl<MachineOperand> &Pred) const {
+ unsigned CCMask = Pred[0].getImm();
+ assert(CCMask > 0 && CCMask < 15 && "Invalid predicate");
+ unsigned Opcode = MI->getOpcode();
+ if (TM.getSubtargetImpl()->hasLoadStoreOnCond()) {
+ if (unsigned CondOpcode = getConditionalMove(Opcode)) {
+ MI->setDesc(get(CondOpcode));
+ MachineInstrBuilder(*MI->getParent()->getParent(), MI).addImm(CCMask);
+ return true;
+ }
+ }
+ return false;
+}
+
void
SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, DebugLoc DL,
FrameIdx);
}
+// Return true if MI is a simple load or store with a 12-bit displacement
+// and no index. Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
+static bool isSimpleBD12Move(const MachineInstr *MI, unsigned Flag) {
+ const MCInstrDesc &MCID = MI->getDesc();
+ return ((MCID.TSFlags & Flag) &&
+ isUInt<12>(MI->getOperand(2).getImm()) &&
+ MI->getOperand(3).getReg() == 0);
+}
+
+MachineInstr *
+SystemZInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
+ MachineBasicBlock::iterator &MBBI,
+ LiveVariables *LV) const {
+ MachineInstr *MI = MBBI;
+ MachineBasicBlock *MBB = MI->getParent();
+
+ unsigned Opcode = MI->getOpcode();
+ unsigned NumOps = MI->getNumOperands();
+
+ // Try to convert something like SLL into SLLK, if supported.
+ // We prefer to keep the two-operand form where possible both
+ // because it tends to be shorter and because some instructions
+ // have memory forms that can be used during spilling.
+ if (TM.getSubtargetImpl()->hasDistinctOps()) {
+ int ThreeOperandOpcode = SystemZ::getThreeOperandOpcode(Opcode);
+ if (ThreeOperandOpcode >= 0) {
+ unsigned DestReg = MI->getOperand(0).getReg();
+ MachineOperand &Src = MI->getOperand(1);
+ MachineInstrBuilder MIB = BuildMI(*MBB, MBBI, MI->getDebugLoc(),
+ get(ThreeOperandOpcode), DestReg);
+ // Keep the kill state, but drop the tied flag.
+ MIB.addReg(Src.getReg(), getKillRegState(Src.isKill()));
+ // Keep the remaining operands as-is.
+ for (unsigned I = 2; I < NumOps; ++I)
+ MIB.addOperand(MI->getOperand(I));
+ MachineInstr *NewMI = MIB;
+
+ // Transfer killing information to the new instruction.
+ if (LV) {
+ for (unsigned I = 1; I < NumOps; ++I) {
+ MachineOperand &Op = MI->getOperand(I);
+ if (Op.isReg() && Op.isKill())
+ LV->replaceKillInstruction(Op.getReg(), MI, NewMI);
+ }
+ }
+ return MIB;
+ }
+ }
+ return 0;
+}
+
+MachineInstr *
+SystemZInstrInfo::foldMemoryOperandImpl(MachineFunction &MF,
+ MachineInstr *MI,
+ const SmallVectorImpl<unsigned> &Ops,
+ int FrameIndex) const {
+ const MachineFrameInfo *MFI = MF.getFrameInfo();
+ unsigned Size = MFI->getObjectSize(FrameIndex);
+
+ // Eary exit for cases we don't care about
+ if (Ops.size() != 1)
+ return 0;
+
+ unsigned OpNum = Ops[0];
+ assert(Size == MF.getRegInfo()
+ .getRegClass(MI->getOperand(OpNum).getReg())->getSize() &&
+ "Invalid size combination");
+
+ unsigned Opcode = MI->getOpcode();
+ if (Opcode == SystemZ::LGDR || Opcode == SystemZ::LDGR) {
+ bool Op0IsGPR = (Opcode == SystemZ::LGDR);
+ bool Op1IsGPR = (Opcode == SystemZ::LDGR);
+ // If we're spilling the destination of an LDGR or LGDR, store the
+ // source register instead.
+ if (OpNum == 0) {
+ unsigned StoreOpcode = Op1IsGPR ? SystemZ::STG : SystemZ::STD;
+ return BuildMI(MF, MI->getDebugLoc(), get(StoreOpcode))
+ .addOperand(MI->getOperand(1)).addFrameIndex(FrameIndex)
+ .addImm(0).addReg(0);
+ }
+ // If we're spilling the source of an LDGR or LGDR, load the
+ // destination register instead.
+ if (OpNum == 1) {
+ unsigned LoadOpcode = Op0IsGPR ? SystemZ::LG : SystemZ::LD;
+ unsigned Dest = MI->getOperand(0).getReg();
+ return BuildMI(MF, MI->getDebugLoc(), get(LoadOpcode), Dest)
+ .addFrameIndex(FrameIndex).addImm(0).addReg(0);
+ }
+ }
+
+ // Look for cases where the source of a simple store or the destination
+ // of a simple load is being spilled. Try to use MVC instead.
+ //
+ // Although MVC is in practice a fast choice in these cases, it is still
+ // logically a bytewise copy. This means that we cannot use it if the
+ // load or store is volatile. It also means that the transformation is
+ // not valid in cases where the two memories partially overlap; however,
+ // that is not a problem here, because we know that one of the memories
+ // is a full frame index.
+ if (OpNum == 0 && MI->hasOneMemOperand()) {
+ MachineMemOperand *MMO = *MI->memoperands_begin();
+ if (MMO->getSize() == Size && !MMO->isVolatile()) {
+ // Handle conversion of loads.
+ if (isSimpleBD12Move(MI, SystemZII::SimpleBDXLoad)) {
+ return BuildMI(MF, MI->getDebugLoc(), get(SystemZ::MVC))
+ .addFrameIndex(FrameIndex).addImm(0).addImm(Size)
+ .addOperand(MI->getOperand(1)).addImm(MI->getOperand(2).getImm())
+ .addMemOperand(MMO);
+ }
+ // Handle conversion of stores.
+ if (isSimpleBD12Move(MI, SystemZII::SimpleBDXStore)) {
+ return BuildMI(MF, MI->getDebugLoc(), get(SystemZ::MVC))
+ .addOperand(MI->getOperand(1)).addImm(MI->getOperand(2).getImm())
+ .addImm(Size).addFrameIndex(FrameIndex).addImm(0)
+ .addMemOperand(MMO);
+ }
+ }
+ }
+
+ // If the spilled operand is the final one, try to change <INSN>R
+ // into <INSN>.
+ int MemOpcode = SystemZ::getMemOpcode(Opcode);
+ if (MemOpcode >= 0) {
+ unsigned NumOps = MI->getNumExplicitOperands();
+ if (OpNum == NumOps - 1) {
+ const MCInstrDesc &MemDesc = get(MemOpcode);
+ uint64_t AccessBytes = SystemZII::getAccessSize(MemDesc.TSFlags);
+ assert(AccessBytes != 0 && "Size of access should be known");
+ assert(AccessBytes <= Size && "Access outside the frame index");
+ uint64_t Offset = Size - AccessBytes;
+ MachineInstrBuilder MIB = BuildMI(MF, MI->getDebugLoc(), get(MemOpcode));
+ for (unsigned I = 0; I < OpNum; ++I)
+ MIB.addOperand(MI->getOperand(I));
+ MIB.addFrameIndex(FrameIndex).addImm(Offset);
+ if (MemDesc.TSFlags & SystemZII::HasIndex)
+ MIB.addReg(0);
+ return MIB;
+ }
+ }
+
+ return 0;
+}
+
+MachineInstr *
+SystemZInstrInfo::foldMemoryOperandImpl(MachineFunction &MF, MachineInstr* MI,
+ const SmallVectorImpl<unsigned> &Ops,
+ MachineInstr* LoadMI) const {
+ return 0;
+}
+
bool
SystemZInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
switch (MI->getOpcode()) {
return MI->getDesc().getSize();
}
-bool SystemZInstrInfo::isBranch(const MachineInstr *MI, unsigned &Cond,
- const MachineOperand *&Target) const {
+SystemZII::Branch
+SystemZInstrInfo::getBranchInfo(const MachineInstr *MI) const {
switch (MI->getOpcode()) {
case SystemZ::BR:
case SystemZ::J:
case SystemZ::JG:
- Cond = SystemZ::CCMASK_ANY;
- Target = &MI->getOperand(0);
- return true;
+ return SystemZII::Branch(SystemZII::BranchNormal, SystemZ::CCMASK_ANY,
+ &MI->getOperand(0));
case SystemZ::BRC:
case SystemZ::BRCL:
- Cond = MI->getOperand(0).getImm();
- Target = &MI->getOperand(1);
- return true;
+ return SystemZII::Branch(SystemZII::BranchNormal,
+ MI->getOperand(0).getImm(), &MI->getOperand(1));
+
+ case SystemZ::CIJ:
+ case SystemZ::CRJ:
+ return SystemZII::Branch(SystemZII::BranchC, MI->getOperand(2).getImm(),
+ &MI->getOperand(3));
+
+ case SystemZ::CGIJ:
+ case SystemZ::CGRJ:
+ return SystemZII::Branch(SystemZII::BranchCG, MI->getOperand(2).getImm(),
+ &MI->getOperand(3));
default:
- assert(!MI->getDesc().isBranch() && "Unknown branch opcode");
- return false;
+ llvm_unreachable("Unrecognized branch opcode");
}
}
return 0;
}
+unsigned SystemZInstrInfo::getCompareAndBranch(unsigned Opcode,
+ const MachineInstr *MI) const {
+ switch (Opcode) {
+ case SystemZ::CR:
+ return SystemZ::CRJ;
+ case SystemZ::CGR:
+ return SystemZ::CGRJ;
+ case SystemZ::CHI:
+ return MI && isInt<8>(MI->getOperand(1).getImm()) ? SystemZ::CIJ : 0;
+ case SystemZ::CGHI:
+ return MI && isInt<8>(MI->getOperand(1).getImm()) ? SystemZ::CGIJ : 0;
+ default:
+ return 0;
+ }
+}
+
void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned Reg, uint64_t Value) const {