#include "SystemZInstrInfo.h"
#include "MCTargetDesc/SystemZMCTargetDesc.h"
#include "SystemZ.h"
#include "SystemZInstrBuilder.h"
#include "SystemZSubtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include <cassert>
#include <cstdint>
#include <iterator>
using namespace llvm;
#define GET_INSTRINFO_CTOR_DTOR
#define GET_INSTRMAP_INFO
#include "SystemZGenInstrInfo.inc"
#define DEBUG_TYPE "systemz-II"
static uint64_t allOnes(unsigned int Count) {
return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1;
}
void SystemZInstrInfo::anchor() {}
SystemZInstrInfo::SystemZInstrInfo(SystemZSubtarget &sti)
: SystemZGenInstrInfo(SystemZ::ADJCALLSTACKDOWN, SystemZ::ADJCALLSTACKUP),
RI(sti.getSpecialRegisters()->getReturnFunctionAddressRegister()),
STI(sti) {}
void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI,
unsigned NewOpcode) const {
MachineBasicBlock *MBB = MI->getParent();
MachineFunction &MF = *MBB->getParent();
MachineInstr *EarlierMI = MF.CloneMachineInstr(&*MI);
MBB->insert(MI, EarlierMI);
MachineOperand &HighRegOp = EarlierMI->getOperand(0);
MachineOperand &LowRegOp = MI->getOperand(0);
Register Reg128 = LowRegOp.getReg();
unsigned Reg128Killed = getKillRegState(LowRegOp.isKill());
unsigned Reg128Undef = getUndefRegState(LowRegOp.isUndef());
HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_h64));
LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_l64));
if (MI->mayStore()) {
unsigned Reg128UndefImpl = (Reg128Undef | RegState::Implicit);
MachineInstrBuilder(MF, EarlierMI).addReg(Reg128, Reg128UndefImpl);
MachineInstrBuilder(MF, MI).addReg(Reg128, (Reg128UndefImpl | Reg128Killed));
}
MachineOperand &HighOffsetOp = EarlierMI->getOperand(2);
MachineOperand &LowOffsetOp = MI->getOperand(2);
LowOffsetOp.setImm(LowOffsetOp.getImm() + 8);
if (EarlierMI->getOperand(0).isReg() && EarlierMI->getOperand(0).isUse())
EarlierMI->getOperand(0).setIsKill(false);
EarlierMI->getOperand(1).setIsKill(false);
EarlierMI->getOperand(3).setIsKill(false);
unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm());
unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm());
assert(HighOpcode && LowOpcode && "Both offsets should be in range");
EarlierMI->setDesc(get(HighOpcode));
MI->setDesc(get(LowOpcode));
}
void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const {
MachineBasicBlock *MBB = MI->getParent();
MachineFunction &MF = *MBB->getParent();
MachineFrameInfo &MFFrame = MF.getFrameInfo();
MachineOperand &OffsetMO = MI->getOperand(2);
SystemZCallingConventionRegisters *Regs = STI.getSpecialRegisters();
uint64_t Offset = (MFFrame.getMaxCallFrameSize() +
Regs->getCallFrameSize() +
Regs->getStackPointerBias() +
OffsetMO.getImm());
unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset);
assert(NewOpcode && "No support for huge argument lists yet");
MI->setDesc(get(NewOpcode));
OffsetMO.setImm(Offset);
}
void SystemZInstrInfo::expandRIPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned HighOpcode,
bool ConvertHigh) const {
Register Reg = MI.getOperand(0).getReg();
bool IsHigh = SystemZ::isHighReg(Reg);
MI.setDesc(get(IsHigh ? HighOpcode : LowOpcode));
if (IsHigh && ConvertHigh)
MI.getOperand(1).setImm(uint32_t(MI.getOperand(1).getImm()));
}
void SystemZInstrInfo::expandRIEPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned LowOpcodeK,
unsigned HighOpcode) const {
Register DestReg = MI.getOperand(0).getReg();
Register SrcReg = MI.getOperand(1).getReg();
bool DestIsHigh = SystemZ::isHighReg(DestReg);
bool SrcIsHigh = SystemZ::isHighReg(SrcReg);
if (!DestIsHigh && !SrcIsHigh)
MI.setDesc(get(LowOpcodeK));
else {
if (DestReg != SrcReg) {
emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(), DestReg, SrcReg,
SystemZ::LR, 32, MI.getOperand(1).isKill(),
MI.getOperand(1).isUndef());
MI.getOperand(1).setReg(DestReg);
}
MI.setDesc(get(DestIsHigh ? HighOpcode : LowOpcode));
MI.tieOperands(0, 1);
}
}
void SystemZInstrInfo::expandRXYPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned HighOpcode) const {
Register Reg = MI.getOperand(0).getReg();
unsigned Opcode = getOpcodeForOffset(
SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode,
MI.getOperand(2).getImm());
MI.setDesc(get(Opcode));
}
void SystemZInstrInfo::expandLOCPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned HighOpcode) const {
Register Reg = MI.getOperand(0).getReg();
unsigned Opcode = SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode;
MI.setDesc(get(Opcode));
}
void SystemZInstrInfo::expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned Size) const {
MachineInstrBuilder MIB =
emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(),
MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), LowOpcode,
Size, MI.getOperand(1).isKill(), MI.getOperand(1).isUndef());
for (const MachineOperand &MO : llvm::drop_begin(MI.operands(), 2))
MIB.add(MO);
MI.eraseFromParent();
}
void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const {
MachineBasicBlock *MBB = MI->getParent();
MachineFunction &MF = *MBB->getParent();
const Register Reg64 = MI->getOperand(0).getReg();
const Register Reg32 = RI.getSubReg(Reg64, SystemZ::subreg_l32);
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
.addReg(SystemZ::A0)
.addReg(Reg64, RegState::ImplicitDefine);
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::SLLG), Reg64)
.addReg(Reg64)
.addReg(0)
.addImm(32);
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
.addReg(SystemZ::A1);
MI->setDesc(get(SystemZ::LG));
MachineInstrBuilder(MF, MI).addReg(Reg64).addImm(40).addReg(0);
}
MachineInstrBuilder
SystemZInstrInfo::emitGRX32Move(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, unsigned LowLowOpcode,
unsigned Size, bool KillSrc,
bool UndefSrc) const {
unsigned Opcode;
bool DestIsHigh = SystemZ::isHighReg(DestReg);
bool SrcIsHigh = SystemZ::isHighReg(SrcReg);
if (DestIsHigh && SrcIsHigh)
Opcode = SystemZ::RISBHH;
else if (DestIsHigh && !SrcIsHigh)
Opcode = SystemZ::RISBHL;
else if (!DestIsHigh && SrcIsHigh)
Opcode = SystemZ::RISBLH;
else {
return BuildMI(MBB, MBBI, DL, get(LowLowOpcode), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc));
}
unsigned Rotate = (DestIsHigh != SrcIsHigh ? 32 : 0);
return BuildMI(MBB, MBBI, DL, get(Opcode), DestReg)
.addReg(DestReg, RegState::Undef)
.addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc))
.addImm(32 - Size).addImm(128 + 31).addImm(Rotate);
}
MachineInstr *SystemZInstrInfo::commuteInstructionImpl(MachineInstr &MI,
bool NewMI,
unsigned OpIdx1,
unsigned OpIdx2) const {
auto cloneIfNew = [NewMI](MachineInstr &MI) -> MachineInstr & {
if (NewMI)
return *MI.getParent()->getParent()->CloneMachineInstr(&MI);
return MI;
};
switch (MI.getOpcode()) {
case SystemZ::SELRMux:
case SystemZ::SELFHR:
case SystemZ::SELR:
case SystemZ::SELGR:
case SystemZ::LOCRMux:
case SystemZ::LOCFHR:
case SystemZ::LOCR:
case SystemZ::LOCGR: {
auto &WorkingMI = cloneIfNew(MI);
unsigned CCValid = WorkingMI.getOperand(3).getImm();
unsigned CCMask = WorkingMI.getOperand(4).getImm();
WorkingMI.getOperand(4).setImm(CCMask ^ CCValid);
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, false,
OpIdx1, OpIdx2);
}
default:
return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
}
}
static int isSimpleMove(const MachineInstr &MI, int &FrameIndex,
unsigned Flag) {
const MCInstrDesc &MCID = MI.getDesc();
if ((MCID.TSFlags & Flag) && MI.getOperand(1).isFI() &&
MI.getOperand(2).getImm() == 0 && MI.getOperand(3).getReg() == 0) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
return 0;
}
unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXLoad);
}
unsigned SystemZInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXStore);
}
bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr &MI,
int &DestFrameIndex,
int &SrcFrameIndex) const {
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;
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,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const {
MachineBasicBlock::iterator I = MBB.end();
while (I != MBB.begin()) {
--I;
if (I->isDebugInstr())
continue;
if (!isUnpredicatedTerminator(*I))
break;
if (!I->isBranch())
return true;
SystemZII::Branch Branch(getBranchInfo(*I));
if (!Branch.hasMBBTarget())
return true;
if (Branch.Type != SystemZII::BranchNormal)
return true;
if (Branch.CCMask == SystemZ::CCMASK_ANY) {
if (!AllowModify) {
TBB = Branch.getMBBTarget();
continue;
}
MBB.erase(std::next(I), MBB.end());
Cond.clear();
FBB = nullptr;
if (MBB.isLayoutSuccessor(Branch.getMBBTarget())) {
TBB = nullptr;
I->eraseFromParent();
I = MBB.end();
continue;
}
TBB = Branch.getMBBTarget();
continue;
}
if (Cond.empty()) {
FBB = TBB;
TBB = Branch.getMBBTarget();
Cond.push_back(MachineOperand::CreateImm(Branch.CCValid));
Cond.push_back(MachineOperand::CreateImm(Branch.CCMask));
continue;
}
assert(Cond.size() == 2 && TBB && "Should have seen a conditional branch");
if (TBB != Branch.getMBBTarget())
return true;
unsigned OldCCValid = Cond[0].getImm();
unsigned OldCCMask = Cond[1].getImm();
if (OldCCValid == Branch.CCValid && OldCCMask == Branch.CCMask)
continue;
return false;
}
return false;
}
unsigned SystemZInstrInfo::removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved) const {
assert(!BytesRemoved && "code size not handled");
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
while (I != MBB.begin()) {
--I;
if (I->isDebugInstr())
continue;
if (!I->isBranch())
break;
if (!getBranchInfo(*I).hasMBBTarget())
break;
I->eraseFromParent();
I = MBB.end();
++Count;
}
return Count;
}
bool SystemZInstrInfo::
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 2 && "Invalid condition");
Cond[1].setImm(Cond[1].getImm() ^ Cond[0].getImm());
return false;
}
unsigned SystemZInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
const DebugLoc &DL,
int *BytesAdded) const {
assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"SystemZ branch conditions have one component!");
assert(!BytesAdded && "code size not handled");
if (Cond.empty()) {
assert(!FBB && "Unconditional branch with multiple successors!");
BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(TBB);
return 1;
}
unsigned Count = 0;
unsigned CCValid = Cond[0].getImm();
unsigned CCMask = Cond[1].getImm();
BuildMI(&MBB, DL, get(SystemZ::BRC))
.addImm(CCValid).addImm(CCMask).addMBB(TBB);
++Count;
if (FBB) {
BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(FBB);
++Count;
}
return Count;
}
bool SystemZInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
Register &SrcReg2, int64_t &Mask,
int64_t &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;
}
bool SystemZInstrInfo::canInsertSelect(const MachineBasicBlock &MBB,
ArrayRef<MachineOperand> Pred,
Register DstReg, Register TrueReg,
Register FalseReg, int &CondCycles,
int &TrueCycles,
int &FalseCycles) const {
if (!STI.hasLoadStoreOnCond())
return false;
if (Pred.size() != 2)
return false;
const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
const TargetRegisterClass *RC =
RI.getCommonSubClass(MRI.getRegClass(TrueReg), MRI.getRegClass(FalseReg));
if (!RC)
return false;
if ((STI.hasLoadStoreOnCond2() &&
SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) ||
SystemZ::GR32BitRegClass.hasSubClassEq(RC) ||
SystemZ::GR64BitRegClass.hasSubClassEq(RC)) {
CondCycles = 2;
TrueCycles = 2;
FalseCycles = 2;
return true;
}
return false;
}
void SystemZInstrInfo::insertSelect(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, Register DstReg,
ArrayRef<MachineOperand> Pred,
Register TrueReg,
Register FalseReg) const {
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
assert(Pred.size() == 2 && "Invalid condition");
unsigned CCValid = Pred[0].getImm();
unsigned CCMask = Pred[1].getImm();
unsigned Opc;
if (SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) {
if (STI.hasMiscellaneousExtensions3())
Opc = SystemZ::SELRMux;
else if (STI.hasLoadStoreOnCond2())
Opc = SystemZ::LOCRMux;
else {
Opc = SystemZ::LOCR;
MRI.constrainRegClass(DstReg, &SystemZ::GR32BitRegClass);
Register TReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass);
Register FReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass);
BuildMI(MBB, I, DL, get(TargetOpcode::COPY), TReg).addReg(TrueReg);
BuildMI(MBB, I, DL, get(TargetOpcode::COPY), FReg).addReg(FalseReg);
TrueReg = TReg;
FalseReg = FReg;
}
} else if (SystemZ::GR64BitRegClass.hasSubClassEq(RC)) {
if (STI.hasMiscellaneousExtensions3())
Opc = SystemZ::SELGR;
else
Opc = SystemZ::LOCGR;
} else
llvm_unreachable("Invalid register class");
BuildMI(MBB, I, DL, get(Opc), DstReg)
.addReg(FalseReg).addReg(TrueReg)
.addImm(CCValid).addImm(CCMask);
}
bool SystemZInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
Register Reg,
MachineRegisterInfo *MRI) const {
unsigned DefOpc = DefMI.getOpcode();
if (DefOpc != SystemZ::LHIMux && DefOpc != SystemZ::LHI &&
DefOpc != SystemZ::LGHI)
return false;
if (DefMI.getOperand(0).getReg() != Reg)
return false;
int32_t ImmVal = (int32_t)DefMI.getOperand(1).getImm();
unsigned UseOpc = UseMI.getOpcode();
unsigned NewUseOpc;
unsigned UseIdx;
int CommuteIdx = -1;
bool TieOps = false;
switch (UseOpc) {
case SystemZ::SELRMux:
TieOps = true;
LLVM_FALLTHROUGH;
case SystemZ::LOCRMux:
if (!STI.hasLoadStoreOnCond2())
return false;
NewUseOpc = SystemZ::LOCHIMux;
if (UseMI.getOperand(2).getReg() == Reg)
UseIdx = 2;
else if (UseMI.getOperand(1).getReg() == Reg)
UseIdx = 2, CommuteIdx = 1;
else
return false;
break;
case SystemZ::SELGR:
TieOps = true;
LLVM_FALLTHROUGH;
case SystemZ::LOCGR:
if (!STI.hasLoadStoreOnCond2())
return false;
NewUseOpc = SystemZ::LOCGHI;
if (UseMI.getOperand(2).getReg() == Reg)
UseIdx = 2;
else if (UseMI.getOperand(1).getReg() == Reg)
UseIdx = 2, CommuteIdx = 1;
else
return false;
break;
default:
return false;
}
if (CommuteIdx != -1)
if (!commuteInstruction(UseMI, false, CommuteIdx, UseIdx))
return false;
bool DeleteDef = MRI->hasOneNonDBGUse(Reg);
UseMI.setDesc(get(NewUseOpc));
if (TieOps)
UseMI.tieOperands(0, 1);
UseMI.getOperand(UseIdx).ChangeToImmediate(ImmVal);
if (DeleteDef)
DefMI.eraseFromParent();
return true;
}
bool SystemZInstrInfo::isPredicable(const MachineInstr &MI) const {
unsigned Opcode = MI.getOpcode();
if (Opcode == SystemZ::Return ||
Opcode == SystemZ::Return_XPLINK ||
Opcode == SystemZ::Trap ||
Opcode == SystemZ::CallJG ||
Opcode == SystemZ::CallBR)
return true;
return false;
}
bool SystemZInstrInfo::
isProfitableToIfCvt(MachineBasicBlock &MBB,
unsigned NumCycles, unsigned ExtraPredCycles,
BranchProbability Probability) const {
if (MBB.getLastNonDebugInstr()->getOpcode() != SystemZ::Trap &&
MBB.succ_empty() && Probability < BranchProbability(1, 8))
return false;
return NumCycles == 1;
}
bool SystemZInstrInfo::
isProfitableToIfCvt(MachineBasicBlock &TMBB,
unsigned NumCyclesT, unsigned ExtraPredCyclesT,
MachineBasicBlock &FMBB,
unsigned NumCyclesF, unsigned ExtraPredCyclesF,
BranchProbability Probability) const {
return false;
}
bool SystemZInstrInfo::
isProfitableToDupForIfCvt(MachineBasicBlock &MBB, unsigned NumCycles,
BranchProbability Probability) const {
return NumCycles == 1;
}
bool SystemZInstrInfo::PredicateInstruction(
MachineInstr &MI, ArrayRef<MachineOperand> Pred) const {
assert(Pred.size() == 2 && "Invalid condition");
unsigned CCValid = Pred[0].getImm();
unsigned CCMask = Pred[1].getImm();
assert(CCMask > 0 && CCMask < 15 && "Invalid predicate");
unsigned Opcode = MI.getOpcode();
if (Opcode == SystemZ::Trap) {
MI.setDesc(get(SystemZ::CondTrap));
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
.addImm(CCValid).addImm(CCMask)
.addReg(SystemZ::CC, RegState::Implicit);
return true;
}
if (Opcode == SystemZ::Return || Opcode == SystemZ::Return_XPLINK) {
MI.setDesc(get(Opcode == SystemZ::Return ? SystemZ::CondReturn
: SystemZ::CondReturn_XPLINK));
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
.addImm(CCValid)
.addImm(CCMask)
.addReg(SystemZ::CC, RegState::Implicit);
return true;
}
if (Opcode == SystemZ::CallJG) {
MachineOperand FirstOp = MI.getOperand(0);
const uint32_t *RegMask = MI.getOperand(1).getRegMask();
MI.removeOperand(1);
MI.removeOperand(0);
MI.setDesc(get(SystemZ::CallBRCL));
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
.addImm(CCValid)
.addImm(CCMask)
.add(FirstOp)
.addRegMask(RegMask)
.addReg(SystemZ::CC, RegState::Implicit);
return true;
}
if (Opcode == SystemZ::CallBR) {
MachineOperand Target = MI.getOperand(0);
const uint32_t *RegMask = MI.getOperand(1).getRegMask();
MI.removeOperand(1);
MI.removeOperand(0);
MI.setDesc(get(SystemZ::CallBCR));
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
.addImm(CCValid).addImm(CCMask)
.add(Target)
.addRegMask(RegMask)
.addReg(SystemZ::CC, RegState::Implicit);
return true;
}
return false;
}
void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, MCRegister DestReg,
MCRegister SrcReg, bool KillSrc) const {
if (SystemZ::GR128BitRegClass.contains(DestReg, SrcReg)) {
copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_h64),
RI.getSubReg(SrcReg, SystemZ::subreg_h64), KillSrc);
MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI))
.addReg(SrcReg, RegState::Implicit);
copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_l64),
RI.getSubReg(SrcReg, SystemZ::subreg_l64), KillSrc);
MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI))
.addReg(SrcReg, (getKillRegState(KillSrc) | RegState::Implicit));
return;
}
if (SystemZ::GRX32BitRegClass.contains(DestReg, SrcReg)) {
emitGRX32Move(MBB, MBBI, DL, DestReg, SrcReg, SystemZ::LR, 32, KillSrc,
false);
return;
}
if (SystemZ::VR128BitRegClass.contains(DestReg) &&
SystemZ::FP128BitRegClass.contains(SrcReg)) {
MCRegister SrcRegHi =
RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_h64),
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
MCRegister SrcRegLo =
RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_l64),
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
BuildMI(MBB, MBBI, DL, get(SystemZ::VMRHG), DestReg)
.addReg(SrcRegHi, getKillRegState(KillSrc))
.addReg(SrcRegLo, getKillRegState(KillSrc));
return;
}
if (SystemZ::FP128BitRegClass.contains(DestReg) &&
SystemZ::VR128BitRegClass.contains(SrcReg)) {
MCRegister DestRegHi =
RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_h64),
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
MCRegister DestRegLo =
RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_l64),
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
if (DestRegHi != SrcReg)
copyPhysReg(MBB, MBBI, DL, DestRegHi, SrcReg, false);
BuildMI(MBB, MBBI, DL, get(SystemZ::VREPG), DestRegLo)
.addReg(SrcReg, getKillRegState(KillSrc)).addImm(1);
return;
}
if (DestReg == SystemZ::CC) {
unsigned Opcode =
SystemZ::GR32BitRegClass.contains(SrcReg) ? SystemZ::TMLH : SystemZ::TMHH;
BuildMI(MBB, MBBI, DL, get(Opcode))
.addReg(SrcReg, getKillRegState(KillSrc))
.addImm(3 << (SystemZ::IPM_CC - 16));
return;
}
unsigned Opcode;
if (SystemZ::GR64BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::LGR;
else if (SystemZ::FP32BitRegClass.contains(DestReg, SrcReg))
Opcode = STI.hasVector() ? SystemZ::LDR32 : SystemZ::LER;
else if (SystemZ::FP64BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::LDR;
else if (SystemZ::FP128BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::LXR;
else if (SystemZ::VR32BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::VLR32;
else if (SystemZ::VR64BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::VLR64;
else if (SystemZ::VR128BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::VLR;
else if (SystemZ::AR32BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::CPYA;
else
llvm_unreachable("Impossible reg-to-reg copy");
BuildMI(MBB, MBBI, DL, get(Opcode), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
}
void SystemZInstrInfo::storeRegToStackSlot(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg,
bool isKill, int FrameIdx, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
unsigned LoadOpcode, StoreOpcode;
getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode);
addFrameReference(BuildMI(MBB, MBBI, DL, get(StoreOpcode))
.addReg(SrcReg, getKillRegState(isKill)),
FrameIdx);
}
void SystemZInstrInfo::loadRegFromStackSlot(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg,
int FrameIdx, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
unsigned LoadOpcode, StoreOpcode;
getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode);
addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg),
FrameIdx);
}
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);
}
namespace {
struct LogicOp {
LogicOp() = default;
LogicOp(unsigned regSize, unsigned immLSB, unsigned immSize)
: RegSize(regSize), ImmLSB(immLSB), ImmSize(immSize) {}
explicit operator bool() const { return RegSize; }
unsigned RegSize = 0;
unsigned ImmLSB = 0;
unsigned ImmSize = 0;
};
}
static LogicOp interpretAndImmediate(unsigned Opcode) {
switch (Opcode) {
case SystemZ::NILMux: return LogicOp(32, 0, 16);
case SystemZ::NIHMux: return LogicOp(32, 16, 16);
case SystemZ::NILL64: return LogicOp(64, 0, 16);
case SystemZ::NILH64: return LogicOp(64, 16, 16);
case SystemZ::NIHL64: return LogicOp(64, 32, 16);
case SystemZ::NIHH64: return LogicOp(64, 48, 16);
case SystemZ::NIFMux: return LogicOp(32, 0, 32);
case SystemZ::NILF64: return LogicOp(64, 0, 32);
case SystemZ::NIHF64: return LogicOp(64, 32, 32);
default: return LogicOp();
}
}
static void transferDeadCC(MachineInstr *OldMI, MachineInstr *NewMI) {
if (OldMI->registerDefIsDead(SystemZ::CC)) {
MachineOperand *CCDef = NewMI->findRegisterDefOperand(SystemZ::CC);
if (CCDef != nullptr)
CCDef->setIsDead(true);
}
}
static void transferMIFlag(MachineInstr *OldMI, MachineInstr *NewMI,
MachineInstr::MIFlag Flag) {
if (OldMI->getFlag(Flag))
NewMI->setFlag(Flag);
}
MachineInstr *
SystemZInstrInfo::convertToThreeAddress(MachineInstr &MI, LiveVariables *LV,
LiveIntervals *LIS) const {
MachineBasicBlock *MBB = MI.getParent();
if (LogicOp And = interpretAndImmediate(MI.getOpcode())) {
uint64_t Imm = MI.getOperand(2).getImm() << And.ImmLSB;
Imm |= allOnes(And.RegSize) & ~(allOnes(And.ImmSize) << And.ImmLSB);
unsigned Start, End;
if (isRxSBGMask(Imm, And.RegSize, Start, End)) {
unsigned NewOpcode;
if (And.RegSize == 64) {
NewOpcode = SystemZ::RISBG;
if (STI.hasMiscellaneousExtensions())
NewOpcode = SystemZ::RISBGN;
} else {
NewOpcode = SystemZ::RISBMux;
Start &= 31;
End &= 31;
}
MachineOperand &Dest = MI.getOperand(0);
MachineOperand &Src = MI.getOperand(1);
MachineInstrBuilder MIB =
BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpcode))
.add(Dest)
.addReg(0)
.addReg(Src.getReg(), getKillRegState(Src.isKill()),
Src.getSubReg())
.addImm(Start)
.addImm(End + 128)
.addImm(0);
if (LV) {
unsigned NumOps = MI.getNumOperands();
for (unsigned I = 1; I < NumOps; ++I) {
MachineOperand &Op = MI.getOperand(I);
if (Op.isReg() && Op.isKill())
LV->replaceKillInstruction(Op.getReg(), MI, *MIB);
}
}
if (LIS)
LIS->ReplaceMachineInstrInMaps(MI, *MIB);
transferDeadCC(&MI, MIB);
return MIB;
}
}
return nullptr;
}
MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops,
MachineBasicBlock::iterator InsertPt, int FrameIndex,
LiveIntervals *LIS, VirtRegMap *VRM) const {
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
const MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Size = MFI.getObjectSize(FrameIndex);
unsigned Opcode = MI.getOpcode();
MCRegUnitIterator CCUnit(MCRegister::from(SystemZ::CC), TRI);
SlotIndex MISlot = SlotIndex();
LiveRange *CCLiveRange = nullptr;
bool CCLiveAtMI = true;
if (LIS) {
MISlot = LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot();
CCLiveRange = &LIS->getRegUnit(*CCUnit);
CCLiveAtMI = CCLiveRange->liveAt(MISlot);
}
++CCUnit;
assert(!CCUnit.isValid() && "CC only has one reg unit.");
if (Ops.size() == 2 && Ops[0] == 0 && Ops[1] == 1) {
if (!CCLiveAtMI && (Opcode == SystemZ::LA || Opcode == SystemZ::LAY) &&
isInt<8>(MI.getOperand(2).getImm()) && !MI.getOperand(3).getReg()) {
MachineInstr *BuiltMI = BuildMI(*InsertPt->getParent(), InsertPt,
MI.getDebugLoc(), get(SystemZ::AGSI))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(MI.getOperand(2).getImm());
BuiltMI->findRegisterDefOperand(SystemZ::CC)->setIsDead(true);
CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator());
return BuiltMI;
}
return nullptr;
}
if (Ops.size() != 1)
return nullptr;
unsigned OpNum = Ops[0];
assert(Size * 8 ==
TRI->getRegSizeInBits(*MF.getRegInfo()
.getRegClass(MI.getOperand(OpNum).getReg())) &&
"Invalid size combination");
if ((Opcode == SystemZ::AHI || Opcode == SystemZ::AGHI) && OpNum == 0 &&
isInt<8>(MI.getOperand(2).getImm())) {
Opcode = (Opcode == SystemZ::AHI ? SystemZ::ASI : SystemZ::AGSI);
MachineInstr *BuiltMI =
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(MI.getOperand(2).getImm());
transferDeadCC(&MI, BuiltMI);
transferMIFlag(&MI, BuiltMI, MachineInstr::NoSWrap);
return BuiltMI;
}
if ((Opcode == SystemZ::ALFI && OpNum == 0 &&
isInt<8>((int32_t)MI.getOperand(2).getImm())) ||
(Opcode == SystemZ::ALGFI && OpNum == 0 &&
isInt<8>((int64_t)MI.getOperand(2).getImm()))) {
Opcode = (Opcode == SystemZ::ALFI ? SystemZ::ALSI : SystemZ::ALGSI);
MachineInstr *BuiltMI =
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm((int8_t)MI.getOperand(2).getImm());
transferDeadCC(&MI, BuiltMI);
return BuiltMI;
}
if ((Opcode == SystemZ::SLFI && OpNum == 0 &&
isInt<8>((int32_t)-MI.getOperand(2).getImm())) ||
(Opcode == SystemZ::SLGFI && OpNum == 0 &&
isInt<8>((int64_t)-MI.getOperand(2).getImm()))) {
Opcode = (Opcode == SystemZ::SLFI ? SystemZ::ALSI : SystemZ::ALGSI);
MachineInstr *BuiltMI =
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm((int8_t)-MI.getOperand(2).getImm());
transferDeadCC(&MI, BuiltMI);
return BuiltMI;
}
unsigned MemImmOpc = 0;
switch (Opcode) {
case SystemZ::LHIMux:
case SystemZ::LHI: MemImmOpc = SystemZ::MVHI; break;
case SystemZ::LGHI: MemImmOpc = SystemZ::MVGHI; break;
case SystemZ::CHIMux:
case SystemZ::CHI: MemImmOpc = SystemZ::CHSI; break;
case SystemZ::CGHI: MemImmOpc = SystemZ::CGHSI; break;
case SystemZ::CLFIMux:
case SystemZ::CLFI:
if (isUInt<16>(MI.getOperand(1).getImm()))
MemImmOpc = SystemZ::CLFHSI;
break;
case SystemZ::CLGFI:
if (isUInt<16>(MI.getOperand(1).getImm()))
MemImmOpc = SystemZ::CLGHSI;
break;
default: break;
}
if (MemImmOpc)
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
get(MemImmOpc))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(MI.getOperand(1).getImm());
if (Opcode == SystemZ::LGDR || Opcode == SystemZ::LDGR) {
bool Op0IsGPR = (Opcode == SystemZ::LGDR);
bool Op1IsGPR = (Opcode == SystemZ::LDGR);
if (OpNum == 0) {
unsigned StoreOpcode = Op1IsGPR ? SystemZ::STG : SystemZ::STD;
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
get(StoreOpcode))
.add(MI.getOperand(1))
.addFrameIndex(FrameIndex)
.addImm(0)
.addReg(0);
}
if (OpNum == 1) {
unsigned LoadOpcode = Op0IsGPR ? SystemZ::LG : SystemZ::LD;
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
get(LoadOpcode))
.add(MI.getOperand(0))
.addFrameIndex(FrameIndex)
.addImm(0)
.addReg(0);
}
}
if (OpNum == 0 && MI.hasOneMemOperand()) {
MachineMemOperand *MMO = *MI.memoperands_begin();
if (MMO->getSize() == Size && !MMO->isVolatile() && !MMO->isAtomic()) {
if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXLoad)) {
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
get(SystemZ::MVC))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(Size)
.add(MI.getOperand(1))
.addImm(MI.getOperand(2).getImm())
.addMemOperand(MMO);
}
if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXStore)) {
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
get(SystemZ::MVC))
.add(MI.getOperand(1))
.addImm(MI.getOperand(2).getImm())
.addImm(Size)
.addFrameIndex(FrameIndex)
.addImm(0)
.addMemOperand(MMO);
}
}
}
unsigned NumOps = MI.getNumExplicitOperands();
int MemOpcode = SystemZ::getMemOpcode(Opcode);
if (MemOpcode == -1 ||
(CCLiveAtMI && !MI.definesRegister(SystemZ::CC) &&
get(MemOpcode).hasImplicitDefOfPhysReg(SystemZ::CC)))
return nullptr;
const MCInstrDesc &MCID = MI.getDesc();
for (unsigned I = 0, E = MCID.getNumOperands(); I != E; ++I) {
const MCOperandInfo &MCOI = MCID.OpInfo[I];
if (MCOI.OperandType != MCOI::OPERAND_REGISTER || I == OpNum)
continue;
const TargetRegisterClass *RC = TRI->getRegClass(MCOI.RegClass);
if (RC == &SystemZ::VR32BitRegClass || RC == &SystemZ::VR64BitRegClass) {
Register Reg = MI.getOperand(I).getReg();
Register PhysReg = Register::isVirtualRegister(Reg)
? (VRM ? Register(VRM->getPhys(Reg)) : Register())
: Reg;
if (!PhysReg ||
!(SystemZ::FP32BitRegClass.contains(PhysReg) ||
SystemZ::FP64BitRegClass.contains(PhysReg) ||
SystemZ::VF128BitRegClass.contains(PhysReg)))
return nullptr;
}
}
bool FusedFPOp = (Opcode == SystemZ::WFMADB || Opcode == SystemZ::WFMASB ||
Opcode == SystemZ::WFMSDB || Opcode == SystemZ::WFMSSB);
if (FusedFPOp) {
Register DstReg = VRM->getPhys(MI.getOperand(0).getReg());
Register AccReg = VRM->getPhys(MI.getOperand(3).getReg());
if (OpNum == 0 || OpNum == 3 || DstReg != AccReg)
return nullptr;
}
bool NeedsCommute = false;
if ((MI.getOpcode() == SystemZ::CR || MI.getOpcode() == SystemZ::CGR ||
MI.getOpcode() == SystemZ::CLR || MI.getOpcode() == SystemZ::CLGR ||
MI.getOpcode() == SystemZ::WFCDB || MI.getOpcode() == SystemZ::WFCSB ||
MI.getOpcode() == SystemZ::WFKDB || MI.getOpcode() == SystemZ::WFKSB) &&
OpNum == 0 && prepareCompareSwapOperands(MI))
NeedsCommute = true;
bool CCOperands = false;
if (MI.getOpcode() == SystemZ::LOCRMux || MI.getOpcode() == SystemZ::LOCGR ||
MI.getOpcode() == SystemZ::SELRMux || MI.getOpcode() == SystemZ::SELGR) {
assert(MI.getNumOperands() == 6 && NumOps == 5 &&
"LOCR/SELR instruction operands corrupt?");
NumOps -= 2;
CCOperands = true;
}
if (NumOps == 3 && SystemZ::getTargetMemOpcode(MemOpcode) != -1) {
if (VRM == nullptr)
return nullptr;
else {
Register DstReg = MI.getOperand(0).getReg();
Register DstPhys =
(Register::isVirtualRegister(DstReg) ? Register(VRM->getPhys(DstReg))
: DstReg);
Register SrcReg = (OpNum == 2 ? MI.getOperand(1).getReg()
: ((OpNum == 1 && MI.isCommutable())
? MI.getOperand(2).getReg()
: Register()));
if (DstPhys && !SystemZ::GRH32BitRegClass.contains(DstPhys) && SrcReg &&
Register::isVirtualRegister(SrcReg) &&
DstPhys == VRM->getPhys(SrcReg))
NeedsCommute = (OpNum == 1);
else
return nullptr;
}
}
if ((OpNum == NumOps - 1) || NeedsCommute || FusedFPOp) {
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(*InsertPt->getParent(), InsertPt,
MI.getDebugLoc(), get(MemOpcode));
if (MI.isCompare()) {
assert(NumOps == 2 && "Expected 2 register operands for a compare.");
MIB.add(MI.getOperand(NeedsCommute ? 1 : 0));
}
else if (FusedFPOp) {
MIB.add(MI.getOperand(0));
MIB.add(MI.getOperand(3));
MIB.add(MI.getOperand(OpNum == 1 ? 2 : 1));
}
else {
MIB.add(MI.getOperand(0));
if (NeedsCommute)
MIB.add(MI.getOperand(2));
else
for (unsigned I = 1; I < OpNum; ++I)
MIB.add(MI.getOperand(I));
}
MIB.addFrameIndex(FrameIndex).addImm(Offset);
if (MemDesc.TSFlags & SystemZII::HasIndex)
MIB.addReg(0);
if (CCOperands) {
unsigned CCValid = MI.getOperand(NumOps).getImm();
unsigned CCMask = MI.getOperand(NumOps + 1).getImm();
MIB.addImm(CCValid);
MIB.addImm(NeedsCommute ? CCMask ^ CCValid : CCMask);
}
if (MIB->definesRegister(SystemZ::CC) &&
(!MI.definesRegister(SystemZ::CC) ||
MI.registerDefIsDead(SystemZ::CC))) {
MIB->addRegisterDead(SystemZ::CC, TRI);
if (CCLiveRange)
CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator());
}
for (const MachineOperand &MO : MIB->operands())
if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
Register Reg = MO.getReg();
if (MRI.getRegClass(Reg) == &SystemZ::VR32BitRegClass)
MRI.setRegClass(Reg, &SystemZ::FP32BitRegClass);
else if (MRI.getRegClass(Reg) == &SystemZ::VR64BitRegClass)
MRI.setRegClass(Reg, &SystemZ::FP64BitRegClass);
else if (MRI.getRegClass(Reg) == &SystemZ::VR128BitRegClass)
MRI.setRegClass(Reg, &SystemZ::VF128BitRegClass);
}
transferDeadCC(&MI, MIB);
transferMIFlag(&MI, MIB, MachineInstr::NoSWrap);
transferMIFlag(&MI, MIB, MachineInstr::NoFPExcept);
return MIB;
}
return nullptr;
}
MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops,
MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI,
LiveIntervals *LIS) const {
return nullptr;
}
bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
switch (MI.getOpcode()) {
case SystemZ::L128:
splitMove(MI, SystemZ::LG);
return true;
case SystemZ::ST128:
splitMove(MI, SystemZ::STG);
return true;
case SystemZ::LX:
splitMove(MI, SystemZ::LD);
return true;
case SystemZ::STX:
splitMove(MI, SystemZ::STD);
return true;
case SystemZ::LBMux:
expandRXYPseudo(MI, SystemZ::LB, SystemZ::LBH);
return true;
case SystemZ::LHMux:
expandRXYPseudo(MI, SystemZ::LH, SystemZ::LHH);
return true;
case SystemZ::LLCRMux:
expandZExtPseudo(MI, SystemZ::LLCR, 8);
return true;
case SystemZ::LLHRMux:
expandZExtPseudo(MI, SystemZ::LLHR, 16);
return true;
case SystemZ::LLCMux:
expandRXYPseudo(MI, SystemZ::LLC, SystemZ::LLCH);
return true;
case SystemZ::LLHMux:
expandRXYPseudo(MI, SystemZ::LLH, SystemZ::LLHH);
return true;
case SystemZ::LMux:
expandRXYPseudo(MI, SystemZ::L, SystemZ::LFH);
return true;
case SystemZ::LOCMux:
expandLOCPseudo(MI, SystemZ::LOC, SystemZ::LOCFH);
return true;
case SystemZ::LOCHIMux:
expandLOCPseudo(MI, SystemZ::LOCHI, SystemZ::LOCHHI);
return true;
case SystemZ::STCMux:
expandRXYPseudo(MI, SystemZ::STC, SystemZ::STCH);
return true;
case SystemZ::STHMux:
expandRXYPseudo(MI, SystemZ::STH, SystemZ::STHH);
return true;
case SystemZ::STMux:
expandRXYPseudo(MI, SystemZ::ST, SystemZ::STFH);
return true;
case SystemZ::STOCMux:
expandLOCPseudo(MI, SystemZ::STOC, SystemZ::STOCFH);
return true;
case SystemZ::LHIMux:
expandRIPseudo(MI, SystemZ::LHI, SystemZ::IIHF, true);
return true;
case SystemZ::IIFMux:
expandRIPseudo(MI, SystemZ::IILF, SystemZ::IIHF, false);
return true;
case SystemZ::IILMux:
expandRIPseudo(MI, SystemZ::IILL, SystemZ::IIHL, false);
return true;
case SystemZ::IIHMux:
expandRIPseudo(MI, SystemZ::IILH, SystemZ::IIHH, false);
return true;
case SystemZ::NIFMux:
expandRIPseudo(MI, SystemZ::NILF, SystemZ::NIHF, false);
return true;
case SystemZ::NILMux:
expandRIPseudo(MI, SystemZ::NILL, SystemZ::NIHL, false);
return true;
case SystemZ::NIHMux:
expandRIPseudo(MI, SystemZ::NILH, SystemZ::NIHH, false);
return true;
case SystemZ::OIFMux:
expandRIPseudo(MI, SystemZ::OILF, SystemZ::OIHF, false);
return true;
case SystemZ::OILMux:
expandRIPseudo(MI, SystemZ::OILL, SystemZ::OIHL, false);
return true;
case SystemZ::OIHMux:
expandRIPseudo(MI, SystemZ::OILH, SystemZ::OIHH, false);
return true;
case SystemZ::XIFMux:
expandRIPseudo(MI, SystemZ::XILF, SystemZ::XIHF, false);
return true;
case SystemZ::TMLMux:
expandRIPseudo(MI, SystemZ::TMLL, SystemZ::TMHL, false);
return true;
case SystemZ::TMHMux:
expandRIPseudo(MI, SystemZ::TMLH, SystemZ::TMHH, false);
return true;
case SystemZ::AHIMux:
expandRIPseudo(MI, SystemZ::AHI, SystemZ::AIH, false);
return true;
case SystemZ::AHIMuxK:
expandRIEPseudo(MI, SystemZ::AHI, SystemZ::AHIK, SystemZ::AIH);
return true;
case SystemZ::AFIMux:
expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false);
return true;
case SystemZ::CHIMux:
expandRIPseudo(MI, SystemZ::CHI, SystemZ::CIH, false);
return true;
case SystemZ::CFIMux:
expandRIPseudo(MI, SystemZ::CFI, SystemZ::CIH, false);
return true;
case SystemZ::CLFIMux:
expandRIPseudo(MI, SystemZ::CLFI, SystemZ::CLIH, false);
return true;
case SystemZ::CMux:
expandRXYPseudo(MI, SystemZ::C, SystemZ::CHF);
return true;
case SystemZ::CLMux:
expandRXYPseudo(MI, SystemZ::CL, SystemZ::CLHF);
return true;
case SystemZ::RISBMux: {
bool DestIsHigh = SystemZ::isHighReg(MI.getOperand(0).getReg());
bool SrcIsHigh = SystemZ::isHighReg(MI.getOperand(2).getReg());
if (SrcIsHigh == DestIsHigh)
MI.setDesc(get(DestIsHigh ? SystemZ::RISBHH : SystemZ::RISBLL));
else {
MI.setDesc(get(DestIsHigh ? SystemZ::RISBHL : SystemZ::RISBLH));
MI.getOperand(5).setImm(MI.getOperand(5).getImm() ^ 32);
}
return true;
}
case SystemZ::ADJDYNALLOC:
splitAdjDynAlloc(MI);
return true;
case TargetOpcode::LOAD_STACK_GUARD:
expandLoadStackGuard(&MI);
return true;
default:
return false;
}
}
unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
if (MI.isInlineAsm()) {
const MachineFunction *MF = MI.getParent()->getParent();
const char *AsmStr = MI.getOperand(0).getSymbolName();
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
}
else if (MI.getOpcode() == SystemZ::PATCHPOINT)
return PatchPointOpers(&MI).getNumPatchBytes();
else if (MI.getOpcode() == SystemZ::STACKMAP)
return MI.getOperand(1).getImm();
else if (MI.getOpcode() == SystemZ::FENTRY_CALL)
return 6;
return MI.getDesc().getSize();
}
SystemZII::Branch
SystemZInstrInfo::getBranchInfo(const MachineInstr &MI) const {
switch (MI.getOpcode()) {
case SystemZ::BR:
case SystemZ::BI:
case SystemZ::J:
case SystemZ::JG:
return SystemZII::Branch(SystemZII::BranchNormal, SystemZ::CCMASK_ANY,
SystemZ::CCMASK_ANY, &MI.getOperand(0));
case SystemZ::BRC:
case SystemZ::BRCL:
return SystemZII::Branch(SystemZII::BranchNormal, MI.getOperand(0).getImm(),
MI.getOperand(1).getImm(), &MI.getOperand(2));
case SystemZ::BRCT:
case SystemZ::BRCTH:
return SystemZII::Branch(SystemZII::BranchCT, SystemZ::CCMASK_ICMP,
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
case SystemZ::BRCTG:
return SystemZII::Branch(SystemZII::BranchCTG, SystemZ::CCMASK_ICMP,
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
case SystemZ::CIJ:
case SystemZ::CRJ:
return SystemZII::Branch(SystemZII::BranchC, SystemZ::CCMASK_ICMP,
MI.getOperand(2).getImm(), &MI.getOperand(3));
case SystemZ::CLIJ:
case SystemZ::CLRJ:
return SystemZII::Branch(SystemZII::BranchCL, SystemZ::CCMASK_ICMP,
MI.getOperand(2).getImm(), &MI.getOperand(3));
case SystemZ::CGIJ:
case SystemZ::CGRJ:
return SystemZII::Branch(SystemZII::BranchCG, SystemZ::CCMASK_ICMP,
MI.getOperand(2).getImm(), &MI.getOperand(3));
case SystemZ::CLGIJ:
case SystemZ::CLGRJ:
return SystemZII::Branch(SystemZII::BranchCLG, SystemZ::CCMASK_ICMP,
MI.getOperand(2).getImm(), &MI.getOperand(3));
case SystemZ::INLINEASM_BR:
return SystemZII::Branch(SystemZII::AsmGoto, 0, 0, nullptr);
default:
llvm_unreachable("Unrecognized branch opcode");
}
}
void SystemZInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC,
unsigned &LoadOpcode,
unsigned &StoreOpcode) const {
if (RC == &SystemZ::GR32BitRegClass || RC == &SystemZ::ADDR32BitRegClass) {
LoadOpcode = SystemZ::L;
StoreOpcode = SystemZ::ST;
} else if (RC == &SystemZ::GRH32BitRegClass) {
LoadOpcode = SystemZ::LFH;
StoreOpcode = SystemZ::STFH;
} else if (RC == &SystemZ::GRX32BitRegClass) {
LoadOpcode = SystemZ::LMux;
StoreOpcode = SystemZ::STMux;
} else if (RC == &SystemZ::GR64BitRegClass ||
RC == &SystemZ::ADDR64BitRegClass) {
LoadOpcode = SystemZ::LG;
StoreOpcode = SystemZ::STG;
} else if (RC == &SystemZ::GR128BitRegClass ||
RC == &SystemZ::ADDR128BitRegClass) {
LoadOpcode = SystemZ::L128;
StoreOpcode = SystemZ::ST128;
} else if (RC == &SystemZ::FP32BitRegClass) {
LoadOpcode = SystemZ::LE;
StoreOpcode = SystemZ::STE;
} else if (RC == &SystemZ::FP64BitRegClass) {
LoadOpcode = SystemZ::LD;
StoreOpcode = SystemZ::STD;
} else if (RC == &SystemZ::FP128BitRegClass) {
LoadOpcode = SystemZ::LX;
StoreOpcode = SystemZ::STX;
} else if (RC == &SystemZ::VR32BitRegClass) {
LoadOpcode = SystemZ::VL32;
StoreOpcode = SystemZ::VST32;
} else if (RC == &SystemZ::VR64BitRegClass) {
LoadOpcode = SystemZ::VL64;
StoreOpcode = SystemZ::VST64;
} else if (RC == &SystemZ::VF128BitRegClass ||
RC == &SystemZ::VR128BitRegClass) {
LoadOpcode = SystemZ::VL;
StoreOpcode = SystemZ::VST;
} else
llvm_unreachable("Unsupported regclass to load or store");
}
unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode,
int64_t Offset,
const MachineInstr *MI) const {
const MCInstrDesc &MCID = get(Opcode);
int64_t Offset2 = (MCID.TSFlags & SystemZII::Is128Bit ? Offset + 8 : Offset);
if (isUInt<12>(Offset) && isUInt<12>(Offset2)) {
int Disp12Opcode = SystemZ::getDisp12Opcode(Opcode);
if (Disp12Opcode >= 0)
return Disp12Opcode;
return Opcode;
}
if (isInt<20>(Offset) && isInt<20>(Offset2)) {
int Disp20Opcode = SystemZ::getDisp20Opcode(Opcode);
if (Disp20Opcode >= 0)
return Disp20Opcode;
if (MCID.TSFlags & SystemZII::Has20BitOffset)
return Opcode;
if (MI && MI->getOperand(0).isReg()) {
Register Reg = MI->getOperand(0).getReg();
if (Reg.isPhysical() && SystemZMC::getFirstReg(Reg) < 16) {
switch (Opcode) {
case SystemZ::VL32:
return SystemZ::LEY;
case SystemZ::VST32:
return SystemZ::STEY;
case SystemZ::VL64:
return SystemZ::LDY;
case SystemZ::VST64:
return SystemZ::STDY;
default: break;
}
}
}
}
return 0;
}
bool SystemZInstrInfo::hasDisplacementPairInsn(unsigned Opcode) const {
const MCInstrDesc &MCID = get(Opcode);
if (MCID.TSFlags & SystemZII::Has20BitOffset)
return SystemZ::getDisp12Opcode(Opcode) >= 0;
return SystemZ::getDisp20Opcode(Opcode) >= 0;
}
unsigned SystemZInstrInfo::getLoadAndTest(unsigned Opcode) const {
switch (Opcode) {
case SystemZ::L: return SystemZ::LT;
case SystemZ::LY: return SystemZ::LT;
case SystemZ::LG: return SystemZ::LTG;
case SystemZ::LGF: return SystemZ::LTGF;
case SystemZ::LR: return SystemZ::LTR;
case SystemZ::LGFR: return SystemZ::LTGFR;
case SystemZ::LGR: return SystemZ::LTGR;
case SystemZ::LER: return SystemZ::LTEBR;
case SystemZ::LDR: return SystemZ::LTDBR;
case SystemZ::LXR: return SystemZ::LTXBR;
case SystemZ::LCDFR: return SystemZ::LCDBR;
case SystemZ::LPDFR: return SystemZ::LPDBR;
case SystemZ::LNDFR: return SystemZ::LNDBR;
case SystemZ::LCDFR_32: return SystemZ::LCEBR;
case SystemZ::LPDFR_32: return SystemZ::LPEBR;
case SystemZ::LNDFR_32: return SystemZ::LNEBR;
case SystemZ::RISBGN: return SystemZ::RISBG;
default: return 0;
}
}
static bool isStringOfOnes(uint64_t Mask, unsigned &LSB, unsigned &Length) {
unsigned First = findFirstSet(Mask);
uint64_t Top = (Mask >> First) + 1;
if ((Top & -Top) == Top) {
LSB = First;
Length = findFirstSet(Top);
return true;
}
return false;
}
bool SystemZInstrInfo::isRxSBGMask(uint64_t Mask, unsigned BitSize,
unsigned &Start, unsigned &End) const {
Mask &= allOnes(BitSize);
if (Mask == 0)
return false;
unsigned LSB, Length;
if (isStringOfOnes(Mask, LSB, Length)) {
Start = 63 - (LSB + Length - 1);
End = 63 - LSB;
return true;
}
if (isStringOfOnes(Mask ^ allOnes(BitSize), LSB, Length)) {
assert(LSB > 0 && "Bottom bit must be set");
assert(LSB + Length < BitSize && "Top bit must be set");
Start = 63 - (LSB - 1);
End = 63 - (LSB + Length);
return true;
}
return false;
}
unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
SystemZII::FusedCompareType Type,
const MachineInstr *MI) const {
switch (Opcode) {
case SystemZ::CHI:
case SystemZ::CGHI:
if (!(MI && isInt<8>(MI->getOperand(1).getImm())))
return 0;
break;
case SystemZ::CLFI:
case SystemZ::CLGFI:
if (!(MI && isUInt<8>(MI->getOperand(1).getImm())))
return 0;
break;
case SystemZ::CL:
case SystemZ::CLG:
if (!STI.hasMiscellaneousExtensions())
return 0;
if (!(MI && MI->getOperand(3).getReg() == 0))
return 0;
break;
}
switch (Type) {
case SystemZII::CompareAndBranch:
switch (Opcode) {
case SystemZ::CR:
return SystemZ::CRJ;
case SystemZ::CGR:
return SystemZ::CGRJ;
case SystemZ::CHI:
return SystemZ::CIJ;
case SystemZ::CGHI:
return SystemZ::CGIJ;
case SystemZ::CLR:
return SystemZ::CLRJ;
case SystemZ::CLGR:
return SystemZ::CLGRJ;
case SystemZ::CLFI:
return SystemZ::CLIJ;
case SystemZ::CLGFI:
return SystemZ::CLGIJ;
default:
return 0;
}
case SystemZII::CompareAndReturn:
switch (Opcode) {
case SystemZ::CR:
return SystemZ::CRBReturn;
case SystemZ::CGR:
return SystemZ::CGRBReturn;
case SystemZ::CHI:
return SystemZ::CIBReturn;
case SystemZ::CGHI:
return SystemZ::CGIBReturn;
case SystemZ::CLR:
return SystemZ::CLRBReturn;
case SystemZ::CLGR:
return SystemZ::CLGRBReturn;
case SystemZ::CLFI:
return SystemZ::CLIBReturn;
case SystemZ::CLGFI:
return SystemZ::CLGIBReturn;
default:
return 0;
}
case SystemZII::CompareAndSibcall:
switch (Opcode) {
case SystemZ::CR:
return SystemZ::CRBCall;
case SystemZ::CGR:
return SystemZ::CGRBCall;
case SystemZ::CHI:
return SystemZ::CIBCall;
case SystemZ::CGHI:
return SystemZ::CGIBCall;
case SystemZ::CLR:
return SystemZ::CLRBCall;
case SystemZ::CLGR:
return SystemZ::CLGRBCall;
case SystemZ::CLFI:
return SystemZ::CLIBCall;
case SystemZ::CLGFI:
return SystemZ::CLGIBCall;
default:
return 0;
}
case SystemZII::CompareAndTrap:
switch (Opcode) {
case SystemZ::CR:
return SystemZ::CRT;
case SystemZ::CGR:
return SystemZ::CGRT;
case SystemZ::CHI:
return SystemZ::CIT;
case SystemZ::CGHI:
return SystemZ::CGIT;
case SystemZ::CLR:
return SystemZ::CLRT;
case SystemZ::CLGR:
return SystemZ::CLGRT;
case SystemZ::CLFI:
return SystemZ::CLFIT;
case SystemZ::CLGFI:
return SystemZ::CLGIT;
case SystemZ::CL:
return SystemZ::CLT;
case SystemZ::CLG:
return SystemZ::CLGT;
default:
return 0;
}
}
return 0;
}
bool SystemZInstrInfo::
prepareCompareSwapOperands(MachineBasicBlock::iterator const MBBI) const {
assert(MBBI->isCompare() && MBBI->getOperand(0).isReg() &&
MBBI->getOperand(1).isReg() && !MBBI->mayLoad() &&
"Not a compare reg/reg.");
MachineBasicBlock *MBB = MBBI->getParent();
bool CCLive = true;
SmallVector<MachineInstr *, 4> CCUsers;
for (MachineBasicBlock::iterator Itr = std::next(MBBI);
Itr != MBB->end(); ++Itr) {
if (Itr->readsRegister(SystemZ::CC)) {
unsigned Flags = Itr->getDesc().TSFlags;
if ((Flags & SystemZII::CCMaskFirst) || (Flags & SystemZII::CCMaskLast))
CCUsers.push_back(&*Itr);
else
return false;
}
if (Itr->definesRegister(SystemZ::CC)) {
CCLive = false;
break;
}
}
if (CCLive) {
LivePhysRegs LiveRegs(*MBB->getParent()->getSubtarget().getRegisterInfo());
LiveRegs.addLiveOuts(*MBB);
if (LiveRegs.contains(SystemZ::CC))
return false;
}
for (unsigned Idx = 0; Idx < CCUsers.size(); ++Idx) {
unsigned Flags = CCUsers[Idx]->getDesc().TSFlags;
unsigned FirstOpNum = ((Flags & SystemZII::CCMaskFirst) ?
0 : CCUsers[Idx]->getNumExplicitOperands() - 2);
MachineOperand &CCMaskMO = CCUsers[Idx]->getOperand(FirstOpNum + 1);
unsigned NewCCMask = SystemZ::reverseCCMask(CCMaskMO.getImm());
CCMaskMO.setImm(NewCCMask);
}
return true;
}
unsigned SystemZ::reverseCCMask(unsigned CCMask) {
return ((CCMask & SystemZ::CCMASK_CMP_EQ) |
(CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) |
(CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) |
(CCMask & SystemZ::CCMASK_CMP_UO));
}
MachineBasicBlock *SystemZ::emitBlockAfter(MachineBasicBlock *MBB) {
MachineFunction &MF = *MBB->getParent();
MachineBasicBlock *NewMBB = MF.CreateMachineBasicBlock(MBB->getBasicBlock());
MF.insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
return NewMBB;
}
MachineBasicBlock *SystemZ::splitBlockAfter(MachineBasicBlock::iterator MI,
MachineBasicBlock *MBB) {
MachineBasicBlock *NewMBB = emitBlockAfter(MBB);
NewMBB->splice(NewMBB->begin(), MBB,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
NewMBB->transferSuccessorsAndUpdatePHIs(MBB);
return NewMBB;
}
MachineBasicBlock *SystemZ::splitBlockBefore(MachineBasicBlock::iterator MI,
MachineBasicBlock *MBB) {
MachineBasicBlock *NewMBB = emitBlockAfter(MBB);
NewMBB->splice(NewMBB->begin(), MBB, MI, MBB->end());
NewMBB->transferSuccessorsAndUpdatePHIs(MBB);
return NewMBB;
}
unsigned SystemZInstrInfo::getLoadAndTrap(unsigned Opcode) const {
if (!STI.hasLoadAndTrap())
return 0;
switch (Opcode) {
case SystemZ::L:
case SystemZ::LY:
return SystemZ::LAT;
case SystemZ::LG:
return SystemZ::LGAT;
case SystemZ::LFH:
return SystemZ::LFHAT;
case SystemZ::LLGF:
return SystemZ::LLGFAT;
case SystemZ::LLGT:
return SystemZ::LLGTAT;
}
return 0;
}
void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned Reg, uint64_t Value) const {
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
unsigned Opcode = 0;
if (isInt<16>(Value))
Opcode = SystemZ::LGHI;
else if (SystemZ::isImmLL(Value))
Opcode = SystemZ::LLILL;
else if (SystemZ::isImmLH(Value)) {
Opcode = SystemZ::LLILH;
Value >>= 16;
}
else if (isInt<32>(Value))
Opcode = SystemZ::LGFI;
if (Opcode) {
BuildMI(MBB, MBBI, DL, get(Opcode), Reg).addImm(Value);
return;
}
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
assert (MRI.isSSA() && "Huge values only handled before reg-alloc .");
Register Reg0 = MRI.createVirtualRegister(&SystemZ::GR64BitRegClass);
Register Reg1 = MRI.createVirtualRegister(&SystemZ::GR64BitRegClass);
BuildMI(MBB, MBBI, DL, get(SystemZ::IMPLICIT_DEF), Reg0);
BuildMI(MBB, MBBI, DL, get(SystemZ::IIHF64), Reg1)
.addReg(Reg0).addImm(Value >> 32);
BuildMI(MBB, MBBI, DL, get(SystemZ::IILF64), Reg)
.addReg(Reg1).addImm(Value & ((uint64_t(1) << 32) - 1));
}
bool SystemZInstrInfo::verifyInstruction(const MachineInstr &MI,
StringRef &ErrInfo) const {
const MCInstrDesc &MCID = MI.getDesc();
for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) {
if (I >= MCID.getNumOperands())
break;
const MachineOperand &Op = MI.getOperand(I);
const MCOperandInfo &MCOI = MCID.OpInfo[I];
if (MCOI.OperandType == MCOI::OPERAND_MEMORY &&
((MCOI.RegClass != -1 && !Op.isReg() && !Op.isFI()) ||
(MCOI.RegClass == -1 && !Op.isImm()))) {
ErrInfo = "Addressing mode operands corrupt!";
return false;
}
}
return true;
}
bool SystemZInstrInfo::
areMemAccessesTriviallyDisjoint(const MachineInstr &MIa,
const MachineInstr &MIb) const {
if (!MIa.hasOneMemOperand() || !MIb.hasOneMemOperand())
return false;
MachineMemOperand *MMOa = *MIa.memoperands_begin();
MachineMemOperand *MMOb = *MIb.memoperands_begin();
const Value *VALa = MMOa->getValue();
const Value *VALb = MMOb->getValue();
bool SameVal = (VALa && VALb && (VALa == VALb));
if (!SameVal) {
const PseudoSourceValue *PSVa = MMOa->getPseudoValue();
const PseudoSourceValue *PSVb = MMOb->getPseudoValue();
if (PSVa && PSVb && (PSVa == PSVb))
SameVal = true;
}
if (SameVal) {
int OffsetA = MMOa->getOffset(), OffsetB = MMOb->getOffset();
int WidthA = MMOa->getSize(), WidthB = MMOb->getSize();
int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
if (LowOffset + LowWidth <= HighOffset)
return true;
}
return false;
}