#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineInstrBundle.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/IR/Operator.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <utility>
using namespace llvm;
static const MachineFunction *getMFIfAvailable(const MachineInstr &MI) {
if (const MachineBasicBlock *MBB = MI.getParent())
if (const MachineFunction *MF = MBB->getParent())
return MF;
return nullptr;
}
static void tryToGetTargetInfo(const MachineInstr &MI,
const TargetRegisterInfo *&TRI,
const MachineRegisterInfo *&MRI,
const TargetIntrinsicInfo *&IntrinsicInfo,
const TargetInstrInfo *&TII) {
if (const MachineFunction *MF = getMFIfAvailable(MI)) {
TRI = MF->getSubtarget().getRegisterInfo();
MRI = &MF->getRegInfo();
IntrinsicInfo = MF->getTarget().getIntrinsicInfo();
TII = MF->getSubtarget().getInstrInfo();
}
}
void MachineInstr::addImplicitDefUseOperands(MachineFunction &MF) {
if (MCID->ImplicitDefs)
for (const MCPhysReg *ImpDefs = MCID->getImplicitDefs(); *ImpDefs;
++ImpDefs)
addOperand(MF, MachineOperand::CreateReg(*ImpDefs, true, true));
if (MCID->ImplicitUses)
for (const MCPhysReg *ImpUses = MCID->getImplicitUses(); *ImpUses;
++ImpUses)
addOperand(MF, MachineOperand::CreateReg(*ImpUses, false, true));
}
MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &TID,
DebugLoc DL, bool NoImp)
: MCID(&TID), DbgLoc(std::move(DL)), DebugInstrNum(0) {
assert(DbgLoc.hasTrivialDestructor() && "Expected trivial destructor");
if (unsigned NumOps = MCID->getNumOperands() +
MCID->getNumImplicitDefs() + MCID->getNumImplicitUses()) {
CapOperands = OperandCapacity::get(NumOps);
Operands = MF.allocateOperandArray(CapOperands);
}
if (!NoImp)
addImplicitDefUseOperands(MF);
}
MachineInstr::MachineInstr(MachineFunction &MF, const MachineInstr &MI)
: MCID(&MI.getDesc()), Info(MI.Info), DbgLoc(MI.getDebugLoc()),
DebugInstrNum(0) {
assert(DbgLoc.hasTrivialDestructor() && "Expected trivial destructor");
CapOperands = OperandCapacity::get(MI.getNumOperands());
Operands = MF.allocateOperandArray(CapOperands);
for (const MachineOperand &MO : MI.operands())
addOperand(MF, MO);
setFlags(MI.Flags);
}
void MachineInstr::moveBefore(MachineInstr *MovePos) {
MovePos->getParent()->splice(MovePos, getParent(), getIterator());
}
MachineRegisterInfo *MachineInstr::getRegInfo() {
if (MachineBasicBlock *MBB = getParent())
return &MBB->getParent()->getRegInfo();
return nullptr;
}
void MachineInstr::removeRegOperandsFromUseLists(MachineRegisterInfo &MRI) {
for (MachineOperand &MO : operands())
if (MO.isReg())
MRI.removeRegOperandFromUseList(&MO);
}
void MachineInstr::addRegOperandsToUseLists(MachineRegisterInfo &MRI) {
for (MachineOperand &MO : operands())
if (MO.isReg())
MRI.addRegOperandToUseList(&MO);
}
void MachineInstr::addOperand(const MachineOperand &Op) {
MachineBasicBlock *MBB = getParent();
assert(MBB && "Use MachineInstrBuilder to add operands to dangling instrs");
MachineFunction *MF = MBB->getParent();
assert(MF && "Use MachineInstrBuilder to add operands to dangling instrs");
addOperand(*MF, Op);
}
static void moveOperands(MachineOperand *Dst, MachineOperand *Src,
unsigned NumOps, MachineRegisterInfo *MRI) {
if (MRI)
return MRI->moveOperands(Dst, Src, NumOps);
assert(Dst && Src && "Unknown operands");
std::memmove(Dst, Src, NumOps * sizeof(MachineOperand));
}
void MachineInstr::addOperand(MachineFunction &MF, const MachineOperand &Op) {
assert(MCID && "Cannot add operands before providing an instr descriptor");
if (&Op >= Operands && &Op < Operands + NumOperands) {
MachineOperand CopyOp(Op);
return addOperand(MF, CopyOp);
}
unsigned OpNo = getNumOperands();
bool isImpReg = Op.isReg() && Op.isImplicit();
if (!isImpReg && !isInlineAsm()) {
while (OpNo && Operands[OpNo-1].isReg() && Operands[OpNo-1].isImplicit()) {
--OpNo;
assert(!Operands[OpNo].isTied() && "Cannot move tied operands");
}
}
assert((MCID->isVariadic() || OpNo < MCID->getNumOperands() ||
Op.isValidExcessOperand()) &&
"Trying to add an operand to a machine instr that is already done!");
MachineRegisterInfo *MRI = getRegInfo();
OperandCapacity OldCap = CapOperands;
MachineOperand *OldOperands = Operands;
if (!OldOperands || OldCap.getSize() == getNumOperands()) {
CapOperands = OldOperands ? OldCap.getNext() : OldCap.get(1);
Operands = MF.allocateOperandArray(CapOperands);
if (OpNo)
moveOperands(Operands, OldOperands, OpNo, MRI);
}
if (OpNo != NumOperands)
moveOperands(Operands + OpNo + 1, OldOperands + OpNo, NumOperands - OpNo,
MRI);
++NumOperands;
if (OldOperands != Operands && OldOperands)
MF.deallocateOperandArray(OldCap, OldOperands);
MachineOperand *NewMO = new (Operands + OpNo) MachineOperand(Op);
NewMO->ParentMI = this;
if (NewMO->isReg()) {
NewMO->Contents.Reg.Prev = nullptr;
NewMO->TiedTo = 0;
if (MRI)
MRI->addRegOperandToUseList(NewMO);
if (!isImpReg) {
if (NewMO->isUse()) {
int DefIdx = MCID->getOperandConstraint(OpNo, MCOI::TIED_TO);
if (DefIdx != -1)
tieOperands(DefIdx, OpNo);
}
if (MCID->getOperandConstraint(OpNo, MCOI::EARLY_CLOBBER) != -1)
NewMO->setIsEarlyClobber(true);
}
if (NewMO->isUse() && isDebugInstr())
NewMO->setIsDebug();
}
}
void MachineInstr::removeOperand(unsigned OpNo) {
assert(OpNo < getNumOperands() && "Invalid operand number");
untieRegOperand(OpNo);
#ifndef NDEBUG
for (unsigned i = OpNo + 1, e = getNumOperands(); i != e; ++i)
if (Operands[i].isReg())
assert(!Operands[i].isTied() && "Cannot move tied operands");
#endif
MachineRegisterInfo *MRI = getRegInfo();
if (MRI && Operands[OpNo].isReg())
MRI->removeRegOperandFromUseList(Operands + OpNo);
if (unsigned N = NumOperands - 1 - OpNo)
moveOperands(Operands + OpNo, Operands + OpNo + 1, N, MRI);
--NumOperands;
}
void MachineInstr::setExtraInfo(MachineFunction &MF,
ArrayRef<MachineMemOperand *> MMOs,
MCSymbol *PreInstrSymbol,
MCSymbol *PostInstrSymbol,
MDNode *HeapAllocMarker) {
bool HasPreInstrSymbol = PreInstrSymbol != nullptr;
bool HasPostInstrSymbol = PostInstrSymbol != nullptr;
bool HasHeapAllocMarker = HeapAllocMarker != nullptr;
int NumPointers =
MMOs.size() + HasPreInstrSymbol + HasPostInstrSymbol + HasHeapAllocMarker;
if (NumPointers <= 0) {
Info.clear();
return;
}
else if (NumPointers > 1 || HasHeapAllocMarker) {
Info.set<EIIK_OutOfLine>(MF.createMIExtraInfo(
MMOs, PreInstrSymbol, PostInstrSymbol, HeapAllocMarker));
return;
}
if (HasPreInstrSymbol)
Info.set<EIIK_PreInstrSymbol>(PreInstrSymbol);
else if (HasPostInstrSymbol)
Info.set<EIIK_PostInstrSymbol>(PostInstrSymbol);
else
Info.set<EIIK_MMO>(MMOs[0]);
}
void MachineInstr::dropMemRefs(MachineFunction &MF) {
if (memoperands_empty())
return;
setExtraInfo(MF, {}, getPreInstrSymbol(), getPostInstrSymbol(),
getHeapAllocMarker());
}
void MachineInstr::setMemRefs(MachineFunction &MF,
ArrayRef<MachineMemOperand *> MMOs) {
if (MMOs.empty()) {
dropMemRefs(MF);
return;
}
setExtraInfo(MF, MMOs, getPreInstrSymbol(), getPostInstrSymbol(),
getHeapAllocMarker());
}
void MachineInstr::addMemOperand(MachineFunction &MF,
MachineMemOperand *MO) {
SmallVector<MachineMemOperand *, 2> MMOs;
MMOs.append(memoperands_begin(), memoperands_end());
MMOs.push_back(MO);
setMemRefs(MF, MMOs);
}
void MachineInstr::cloneMemRefs(MachineFunction &MF, const MachineInstr &MI) {
if (this == &MI)
return;
assert(&MF == MI.getMF() &&
"Invalid machine functions when cloning memory refrences!");
if (getPreInstrSymbol() == MI.getPreInstrSymbol() &&
getPostInstrSymbol() == MI.getPostInstrSymbol() &&
getHeapAllocMarker() == MI.getHeapAllocMarker()) {
Info = MI.Info;
return;
}
setMemRefs(MF, MI.memoperands());
}
static bool hasIdenticalMMOs(ArrayRef<MachineMemOperand *> LHS,
ArrayRef<MachineMemOperand *> RHS) {
if (LHS.size() != RHS.size())
return false;
auto LHSPointees = make_pointee_range(LHS);
auto RHSPointees = make_pointee_range(RHS);
return std::equal(LHSPointees.begin(), LHSPointees.end(),
RHSPointees.begin());
}
void MachineInstr::cloneMergedMemRefs(MachineFunction &MF,
ArrayRef<const MachineInstr *> MIs) {
if (MIs.empty()) {
dropMemRefs(MF);
return;
}
if (MIs.size() == 1) {
cloneMemRefs(MF, *MIs[0]);
return;
}
if (MIs[0]->memoperands_empty()) {
dropMemRefs(MF);
return;
}
SmallVector<MachineMemOperand *, 2> MergedMMOs;
assert(&MF == MIs[0]->getMF() &&
"Invalid machine functions when cloning memory references!");
MergedMMOs.append(MIs[0]->memoperands_begin(), MIs[0]->memoperands_end());
for (const MachineInstr &MI : make_pointee_range(MIs.slice(1))) {
assert(&MF == MI.getMF() &&
"Invalid machine functions when cloning memory references!");
if (hasIdenticalMMOs(MIs[0]->memoperands(), MI.memoperands()))
continue;
if (MI.memoperands_empty()) {
dropMemRefs(MF);
return;
}
MergedMMOs.append(MI.memoperands_begin(), MI.memoperands_end());
}
setMemRefs(MF, MergedMMOs);
}
void MachineInstr::setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) {
if (Symbol == getPreInstrSymbol())
return;
if (!Symbol && Info.is<EIIK_PreInstrSymbol>()) {
Info.clear();
return;
}
setExtraInfo(MF, memoperands(), Symbol, getPostInstrSymbol(),
getHeapAllocMarker());
}
void MachineInstr::setPostInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) {
if (Symbol == getPostInstrSymbol())
return;
if (!Symbol && Info.is<EIIK_PostInstrSymbol>()) {
Info.clear();
return;
}
setExtraInfo(MF, memoperands(), getPreInstrSymbol(), Symbol,
getHeapAllocMarker());
}
void MachineInstr::setHeapAllocMarker(MachineFunction &MF, MDNode *Marker) {
if (Marker == getHeapAllocMarker())
return;
setExtraInfo(MF, memoperands(), getPreInstrSymbol(), getPostInstrSymbol(),
Marker);
}
void MachineInstr::cloneInstrSymbols(MachineFunction &MF,
const MachineInstr &MI) {
if (this == &MI)
return;
assert(&MF == MI.getMF() &&
"Invalid machine functions when cloning instruction symbols!");
setPreInstrSymbol(MF, MI.getPreInstrSymbol());
setPostInstrSymbol(MF, MI.getPostInstrSymbol());
setHeapAllocMarker(MF, MI.getHeapAllocMarker());
}
uint16_t MachineInstr::mergeFlagsWith(const MachineInstr &Other) const {
return getFlags() | Other.getFlags();
}
uint16_t MachineInstr::copyFlagsFromInstruction(const Instruction &I) {
uint16_t MIFlags = 0;
if (const OverflowingBinaryOperator *OB =
dyn_cast<OverflowingBinaryOperator>(&I)) {
if (OB->hasNoSignedWrap())
MIFlags |= MachineInstr::MIFlag::NoSWrap;
if (OB->hasNoUnsignedWrap())
MIFlags |= MachineInstr::MIFlag::NoUWrap;
}
if (const PossiblyExactOperator *PE = dyn_cast<PossiblyExactOperator>(&I))
if (PE->isExact())
MIFlags |= MachineInstr::MIFlag::IsExact;
if (const FPMathOperator *FP = dyn_cast<FPMathOperator>(&I)) {
const FastMathFlags Flags = FP->getFastMathFlags();
if (Flags.noNaNs())
MIFlags |= MachineInstr::MIFlag::FmNoNans;
if (Flags.noInfs())
MIFlags |= MachineInstr::MIFlag::FmNoInfs;
if (Flags.noSignedZeros())
MIFlags |= MachineInstr::MIFlag::FmNsz;
if (Flags.allowReciprocal())
MIFlags |= MachineInstr::MIFlag::FmArcp;
if (Flags.allowContract())
MIFlags |= MachineInstr::MIFlag::FmContract;
if (Flags.approxFunc())
MIFlags |= MachineInstr::MIFlag::FmAfn;
if (Flags.allowReassoc())
MIFlags |= MachineInstr::MIFlag::FmReassoc;
}
return MIFlags;
}
void MachineInstr::copyIRFlags(const Instruction &I) {
Flags = copyFlagsFromInstruction(I);
}
bool MachineInstr::hasPropertyInBundle(uint64_t Mask, QueryType Type) const {
assert(!isBundledWithPred() && "Must be called on bundle header");
for (MachineBasicBlock::const_instr_iterator MII = getIterator();; ++MII) {
if (MII->getDesc().getFlags() & Mask) {
if (Type == AnyInBundle)
return true;
} else {
if (Type == AllInBundle && !MII->isBundle())
return false;
}
if (!MII->isBundledWithSucc())
return Type == AllInBundle;
}
}
bool MachineInstr::isIdenticalTo(const MachineInstr &Other,
MICheckType Check) const {
if (Other.getOpcode() != getOpcode() ||
Other.getNumOperands() != getNumOperands())
return false;
if (isBundle()) {
assert(Other.isBundle() && "Expected that both instructions are bundles.");
MachineBasicBlock::const_instr_iterator I1 = getIterator();
MachineBasicBlock::const_instr_iterator I2 = Other.getIterator();
while (I1->isBundledWithSucc() && I2->isBundledWithSucc()) {
++I1;
++I2;
if (!I1->isIdenticalTo(*I2, Check))
return false;
}
if (I1->isBundledWithSucc() || I2->isBundledWithSucc())
return false;
}
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
const MachineOperand &OMO = Other.getOperand(i);
if (!MO.isReg()) {
if (!MO.isIdenticalTo(OMO))
return false;
continue;
}
if (MO.isDef()) {
if (Check == IgnoreDefs)
continue;
else if (Check == IgnoreVRegDefs) {
if (!Register::isVirtualRegister(MO.getReg()) ||
!Register::isVirtualRegister(OMO.getReg()))
if (!MO.isIdenticalTo(OMO))
return false;
} else {
if (!MO.isIdenticalTo(OMO))
return false;
if (Check == CheckKillDead && MO.isDead() != OMO.isDead())
return false;
}
} else {
if (!MO.isIdenticalTo(OMO))
return false;
if (Check == CheckKillDead && MO.isKill() != OMO.isKill())
return false;
}
}
if (isDebugInstr())
if (getDebugLoc() && Other.getDebugLoc() &&
getDebugLoc() != Other.getDebugLoc())
return false;
return true;
}
const MachineFunction *MachineInstr::getMF() const {
return getParent()->getParent();
}
MachineInstr *MachineInstr::removeFromParent() {
assert(getParent() && "Not embedded in a basic block!");
return getParent()->remove(this);
}
MachineInstr *MachineInstr::removeFromBundle() {
assert(getParent() && "Not embedded in a basic block!");
return getParent()->remove_instr(this);
}
void MachineInstr::eraseFromParent() {
assert(getParent() && "Not embedded in a basic block!");
getParent()->erase(this);
}
void MachineInstr::eraseFromBundle() {
assert(getParent() && "Not embedded in a basic block!");
getParent()->erase_instr(this);
}
bool MachineInstr::isCandidateForCallSiteEntry(QueryType Type) const {
if (!isCall(Type))
return false;
switch (getOpcode()) {
case TargetOpcode::PATCHPOINT:
case TargetOpcode::STACKMAP:
case TargetOpcode::STATEPOINT:
case TargetOpcode::FENTRY_CALL:
return false;
}
return true;
}
bool MachineInstr::shouldUpdateCallSiteInfo() const {
if (isBundle())
return isCandidateForCallSiteEntry(MachineInstr::AnyInBundle);
return isCandidateForCallSiteEntry();
}
unsigned MachineInstr::getNumExplicitOperands() const {
unsigned NumOperands = MCID->getNumOperands();
if (!MCID->isVariadic())
return NumOperands;
for (unsigned I = NumOperands, E = getNumOperands(); I != E; ++I) {
const MachineOperand &MO = getOperand(I);
if (MO.isReg() && MO.isImplicit())
break;
++NumOperands;
}
return NumOperands;
}
unsigned MachineInstr::getNumExplicitDefs() const {
unsigned NumDefs = MCID->getNumDefs();
if (!MCID->isVariadic())
return NumDefs;
for (unsigned I = NumDefs, E = getNumOperands(); I != E; ++I) {
const MachineOperand &MO = getOperand(I);
if (!MO.isReg() || !MO.isDef() || MO.isImplicit())
break;
++NumDefs;
}
return NumDefs;
}
void MachineInstr::bundleWithPred() {
assert(!isBundledWithPred() && "MI is already bundled with its predecessor");
setFlag(BundledPred);
MachineBasicBlock::instr_iterator Pred = getIterator();
--Pred;
assert(!Pred->isBundledWithSucc() && "Inconsistent bundle flags");
Pred->setFlag(BundledSucc);
}
void MachineInstr::bundleWithSucc() {
assert(!isBundledWithSucc() && "MI is already bundled with its successor");
setFlag(BundledSucc);
MachineBasicBlock::instr_iterator Succ = getIterator();
++Succ;
assert(!Succ->isBundledWithPred() && "Inconsistent bundle flags");
Succ->setFlag(BundledPred);
}
void MachineInstr::unbundleFromPred() {
assert(isBundledWithPred() && "MI isn't bundled with its predecessor");
clearFlag(BundledPred);
MachineBasicBlock::instr_iterator Pred = getIterator();
--Pred;
assert(Pred->isBundledWithSucc() && "Inconsistent bundle flags");
Pred->clearFlag(BundledSucc);
}
void MachineInstr::unbundleFromSucc() {
assert(isBundledWithSucc() && "MI isn't bundled with its successor");
clearFlag(BundledSucc);
MachineBasicBlock::instr_iterator Succ = getIterator();
++Succ;
assert(Succ->isBundledWithPred() && "Inconsistent bundle flags");
Succ->clearFlag(BundledPred);
}
bool MachineInstr::isStackAligningInlineAsm() const {
if (isInlineAsm()) {
unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
return true;
}
return false;
}
InlineAsm::AsmDialect MachineInstr::getInlineAsmDialect() const {
assert(isInlineAsm() && "getInlineAsmDialect() only works for inline asms!");
unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
return InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect) != 0);
}
int MachineInstr::findInlineAsmFlagIdx(unsigned OpIdx,
unsigned *GroupNo) const {
assert(isInlineAsm() && "Expected an inline asm instruction");
assert(OpIdx < getNumOperands() && "OpIdx out of range");
if (OpIdx < InlineAsm::MIOp_FirstOperand)
return -1;
unsigned Group = 0;
unsigned NumOps;
for (unsigned i = InlineAsm::MIOp_FirstOperand, e = getNumOperands(); i < e;
i += NumOps) {
const MachineOperand &FlagMO = getOperand(i);
if (!FlagMO.isImm())
return -1;
NumOps = 1 + InlineAsm::getNumOperandRegisters(FlagMO.getImm());
if (i + NumOps > OpIdx) {
if (GroupNo)
*GroupNo = Group;
return i;
}
++Group;
}
return -1;
}
const DILabel *MachineInstr::getDebugLabel() const {
assert(isDebugLabel() && "not a DBG_LABEL");
return cast<DILabel>(getOperand(0).getMetadata());
}
const MachineOperand &MachineInstr::getDebugVariableOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
}
MachineOperand &MachineInstr::getDebugVariableOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
}
const DILocalVariable *MachineInstr::getDebugVariable() const {
return cast<DILocalVariable>(getDebugVariableOp().getMetadata());
}
const MachineOperand &MachineInstr::getDebugExpressionOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
}
MachineOperand &MachineInstr::getDebugExpressionOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
}
const DIExpression *MachineInstr::getDebugExpression() const {
return cast<DIExpression>(getDebugExpressionOp().getMetadata());
}
bool MachineInstr::isDebugEntryValue() const {
return isDebugValue() && getDebugExpression()->isEntryValue();
}
const TargetRegisterClass*
MachineInstr::getRegClassConstraint(unsigned OpIdx,
const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI) const {
assert(getParent() && "Can't have an MBB reference here!");
assert(getMF() && "Can't have an MF reference here!");
const MachineFunction &MF = *getMF();
if (!isInlineAsm())
return TII->getRegClass(getDesc(), OpIdx, TRI, MF);
if (!getOperand(OpIdx).isReg())
return nullptr;
unsigned DefIdx;
if (getOperand(OpIdx).isUse() && isRegTiedToDefOperand(OpIdx, &DefIdx))
OpIdx = DefIdx;
int FlagIdx = findInlineAsmFlagIdx(OpIdx);
if (FlagIdx < 0)
return nullptr;
unsigned Flag = getOperand(FlagIdx).getImm();
unsigned RCID;
if ((InlineAsm::getKind(Flag) == InlineAsm::Kind_RegUse ||
InlineAsm::getKind(Flag) == InlineAsm::Kind_RegDef ||
InlineAsm::getKind(Flag) == InlineAsm::Kind_RegDefEarlyClobber) &&
InlineAsm::hasRegClassConstraint(Flag, RCID))
return TRI->getRegClass(RCID);
if (InlineAsm::getKind(Flag) == InlineAsm::Kind_Mem)
return TRI->getPointerRegClass(MF);
return nullptr;
}
const TargetRegisterClass *MachineInstr::getRegClassConstraintEffectForVReg(
Register Reg, const TargetRegisterClass *CurRC, const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI, bool ExploreBundle) const {
if (ExploreBundle)
for (ConstMIBundleOperands OpndIt(*this); OpndIt.isValid() && CurRC;
++OpndIt)
CurRC = OpndIt->getParent()->getRegClassConstraintEffectForVRegImpl(
OpndIt.getOperandNo(), Reg, CurRC, TII, TRI);
else
for (unsigned i = 0, e = NumOperands; i < e && CurRC; ++i)
CurRC = getRegClassConstraintEffectForVRegImpl(i, Reg, CurRC, TII, TRI);
return CurRC;
}
const TargetRegisterClass *MachineInstr::getRegClassConstraintEffectForVRegImpl(
unsigned OpIdx, Register Reg, const TargetRegisterClass *CurRC,
const TargetInstrInfo *TII, const TargetRegisterInfo *TRI) const {
assert(CurRC && "Invalid initial register class");
const MachineOperand &MO = getOperand(OpIdx);
if (!MO.isReg() || MO.getReg() != Reg)
return CurRC;
return getRegClassConstraintEffect(OpIdx, CurRC, TII, TRI);
}
const TargetRegisterClass *MachineInstr::getRegClassConstraintEffect(
unsigned OpIdx, const TargetRegisterClass *CurRC,
const TargetInstrInfo *TII, const TargetRegisterInfo *TRI) const {
const TargetRegisterClass *OpRC = getRegClassConstraint(OpIdx, TII, TRI);
const MachineOperand &MO = getOperand(OpIdx);
assert(MO.isReg() &&
"Cannot get register constraints for non-register operand");
assert(CurRC && "Invalid initial register class");
if (unsigned SubIdx = MO.getSubReg()) {
if (OpRC)
CurRC = TRI->getMatchingSuperRegClass(CurRC, OpRC, SubIdx);
else
CurRC = TRI->getSubClassWithSubReg(CurRC, SubIdx);
} else if (OpRC)
CurRC = TRI->getCommonSubClass(CurRC, OpRC);
return CurRC;
}
unsigned MachineInstr::getBundleSize() const {
MachineBasicBlock::const_instr_iterator I = getIterator();
unsigned Size = 0;
while (I->isBundledWithSucc()) {
++Size;
++I;
}
return Size;
}
bool MachineInstr::hasRegisterImplicitUseOperand(Register Reg) const {
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
if (MO.isReg() && MO.isUse() && MO.isImplicit() && MO.getReg() == Reg)
return true;
}
return false;
}
int MachineInstr::findRegisterUseOperandIdx(
Register Reg, bool isKill, const TargetRegisterInfo *TRI) const {
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
if (!MO.isReg() || !MO.isUse())
continue;
Register MOReg = MO.getReg();
if (!MOReg)
continue;
if (MOReg == Reg || (TRI && Reg && MOReg && TRI->regsOverlap(MOReg, Reg)))
if (!isKill || MO.isKill())
return i;
}
return -1;
}
std::pair<bool,bool>
MachineInstr::readsWritesVirtualRegister(Register Reg,
SmallVectorImpl<unsigned> *Ops) const {
bool PartDef = false; bool FullDef = false; bool Use = false;
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
if (!MO.isReg() || MO.getReg() != Reg)
continue;
if (Ops)
Ops->push_back(i);
if (MO.isUse())
Use |= !MO.isUndef();
else if (MO.getSubReg() && !MO.isUndef())
PartDef = true;
else
FullDef = true;
}
return std::make_pair(Use || (PartDef && !FullDef), PartDef || FullDef);
}
int
MachineInstr::findRegisterDefOperandIdx(Register Reg, bool isDead, bool Overlap,
const TargetRegisterInfo *TRI) const {
bool isPhys = Register::isPhysicalRegister(Reg);
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
if (isPhys && Overlap && MO.isRegMask() && MO.clobbersPhysReg(Reg))
return i;
if (!MO.isReg() || !MO.isDef())
continue;
Register MOReg = MO.getReg();
bool Found = (MOReg == Reg);
if (!Found && TRI && isPhys && Register::isPhysicalRegister(MOReg)) {
if (Overlap)
Found = TRI->regsOverlap(MOReg, Reg);
else
Found = TRI->isSubRegister(MOReg, Reg);
}
if (Found && (!isDead || MO.isDead()))
return i;
}
return -1;
}
int MachineInstr::findFirstPredOperandIdx() const {
const MCInstrDesc &MCID = getDesc();
if (MCID.isPredicable()) {
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
if (MCID.OpInfo[i].isPredicate())
return i;
}
return -1;
}
const unsigned TiedMax = 15;
void MachineInstr::tieOperands(unsigned DefIdx, unsigned UseIdx) {
MachineOperand &DefMO = getOperand(DefIdx);
MachineOperand &UseMO = getOperand(UseIdx);
assert(DefMO.isDef() && "DefIdx must be a def operand");
assert(UseMO.isUse() && "UseIdx must be a use operand");
assert(!DefMO.isTied() && "Def is already tied to another use");
assert(!UseMO.isTied() && "Use is already tied to another def");
if (DefIdx < TiedMax)
UseMO.TiedTo = DefIdx + 1;
else {
assert((isInlineAsm() || getOpcode() == TargetOpcode::STATEPOINT) &&
"DefIdx out of range");
UseMO.TiedTo = TiedMax;
}
DefMO.TiedTo = std::min(UseIdx + 1, TiedMax);
}
unsigned MachineInstr::findTiedOperandIdx(unsigned OpIdx) const {
const MachineOperand &MO = getOperand(OpIdx);
assert(MO.isTied() && "Operand isn't tied");
if (MO.TiedTo < TiedMax)
return MO.TiedTo - 1;
if (!isInlineAsm() && getOpcode() != TargetOpcode::STATEPOINT) {
if (MO.isUse())
return TiedMax - 1;
for (unsigned i = TiedMax - 1, e = getNumOperands(); i != e; ++i) {
const MachineOperand &UseMO = getOperand(i);
if (UseMO.isReg() && UseMO.isUse() && UseMO.TiedTo == OpIdx + 1)
return i;
}
llvm_unreachable("Can't find tied use");
}
if (getOpcode() == TargetOpcode::STATEPOINT) {
StatepointOpers SO(this);
unsigned CurUseIdx = SO.getFirstGCPtrIdx();
assert(CurUseIdx != -1U && "only gc pointer statepoint operands can be tied");
unsigned NumDefs = getNumDefs();
for (unsigned CurDefIdx = 0; CurDefIdx < NumDefs; ++CurDefIdx) {
while (!getOperand(CurUseIdx).isReg())
CurUseIdx = StackMaps::getNextMetaArgIdx(this, CurUseIdx);
if (OpIdx == CurDefIdx)
return CurUseIdx;
if (OpIdx == CurUseIdx)
return CurDefIdx;
CurUseIdx = StackMaps::getNextMetaArgIdx(this, CurUseIdx);
}
llvm_unreachable("Can't find tied use");
}
SmallVector<unsigned, 8> GroupIdx;
unsigned OpIdxGroup = ~0u;
unsigned NumOps;
for (unsigned i = InlineAsm::MIOp_FirstOperand, e = getNumOperands(); i < e;
i += NumOps) {
const MachineOperand &FlagMO = getOperand(i);
assert(FlagMO.isImm() && "Invalid tied operand on inline asm");
unsigned CurGroup = GroupIdx.size();
GroupIdx.push_back(i);
NumOps = 1 + InlineAsm::getNumOperandRegisters(FlagMO.getImm());
if (OpIdx > i && OpIdx < i + NumOps)
OpIdxGroup = CurGroup;
unsigned TiedGroup;
if (!InlineAsm::isUseOperandTiedToDef(FlagMO.getImm(), TiedGroup))
continue;
unsigned Delta = i - GroupIdx[TiedGroup];
if (OpIdxGroup == CurGroup)
return OpIdx - Delta;
if (OpIdxGroup == TiedGroup)
return OpIdx + Delta;
}
llvm_unreachable("Invalid tied operand on inline asm");
}
void MachineInstr::clearKillInfo() {
for (MachineOperand &MO : operands()) {
if (MO.isReg() && MO.isUse())
MO.setIsKill(false);
}
}
void MachineInstr::substituteRegister(Register FromReg, Register ToReg,
unsigned SubIdx,
const TargetRegisterInfo &RegInfo) {
if (Register::isPhysicalRegister(ToReg)) {
if (SubIdx)
ToReg = RegInfo.getSubReg(ToReg, SubIdx);
for (MachineOperand &MO : operands()) {
if (!MO.isReg() || MO.getReg() != FromReg)
continue;
MO.substPhysReg(ToReg, RegInfo);
}
} else {
for (MachineOperand &MO : operands()) {
if (!MO.isReg() || MO.getReg() != FromReg)
continue;
MO.substVirtReg(ToReg, SubIdx, RegInfo);
}
}
}
bool MachineInstr::isSafeToMove(AAResults *AA, bool &SawStore) const {
if (mayStore() || isCall() || isPHI() ||
(mayLoad() && hasOrderedMemoryRef())) {
SawStore = true;
return false;
}
if (isPosition() || isDebugInstr() || isTerminator() ||
mayRaiseFPException() || hasUnmodeledSideEffects())
return false;
if (mayLoad() && !isDereferenceableInvariantLoad())
return !SawStore;
return true;
}
static bool MemOperandsHaveAlias(const MachineFrameInfo &MFI, AAResults *AA,
bool UseTBAA, const MachineMemOperand *MMOa,
const MachineMemOperand *MMOb) {
int64_t OffsetA = MMOa->getOffset();
int64_t OffsetB = MMOb->getOffset();
int64_t MinOffset = std::min(OffsetA, OffsetB);
uint64_t WidthA = MMOa->getSize();
uint64_t WidthB = MMOb->getSize();
bool KnownWidthA = WidthA != MemoryLocation::UnknownSize;
bool KnownWidthB = WidthB != MemoryLocation::UnknownSize;
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 && ValB && !PSVa->mayAlias(&MFI))
return false;
if (PSVb && ValA && !PSVb->mayAlias(&MFI))
return false;
if (PSVa && PSVb && (PSVa == PSVb))
SameVal = true;
}
if (SameVal) {
if (!KnownWidthA || !KnownWidthB)
return true;
int64_t MaxOffset = std::max(OffsetA, OffsetB);
int64_t LowWidth = (MinOffset == OffsetA) ? WidthA : WidthB;
return (MinOffset + LowWidth > MaxOffset);
}
if (!AA)
return true;
if (!ValA || !ValB)
return true;
assert((OffsetA >= 0) && "Negative MachineMemOperand offset");
assert((OffsetB >= 0) && "Negative MachineMemOperand offset");
int64_t OverlapA =
KnownWidthA ? WidthA + OffsetA - MinOffset : MemoryLocation::UnknownSize;
int64_t OverlapB =
KnownWidthB ? WidthB + OffsetB - MinOffset : MemoryLocation::UnknownSize;
return !AA->isNoAlias(
MemoryLocation(ValA, OverlapA, UseTBAA ? MMOa->getAAInfo() : AAMDNodes()),
MemoryLocation(ValB, OverlapB,
UseTBAA ? MMOb->getAAInfo() : AAMDNodes()));
}
bool MachineInstr::mayAlias(AAResults *AA, const MachineInstr &Other,
bool UseTBAA) const {
const MachineFunction *MF = getMF();
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
const MachineFrameInfo &MFI = MF->getFrameInfo();
if (isCall() || Other.isCall())
return true;
if (!mayStore() && !Other.mayStore())
return false;
if (!mayLoadOrStore() || !Other.mayLoadOrStore())
return false;
if (TII->areMemAccessesTriviallyDisjoint(*this, Other))
return false;
if (memoperands_empty() || Other.memoperands_empty())
return true;
auto NumChecks = getNumMemOperands() * Other.getNumMemOperands();
if (NumChecks > TII->getMemOperandAACheckLimit())
return true;
for (auto *MMOa : memoperands())
for (auto *MMOb : Other.memoperands())
if (MemOperandsHaveAlias(MFI, AA, UseTBAA, MMOa, MMOb))
return true;
return false;
}
bool MachineInstr::hasOrderedMemoryRef() const {
if (!mayStore() &&
!mayLoad() &&
!isCall() &&
!hasUnmodeledSideEffects())
return false;
if (memoperands_empty())
return true;
return llvm::any_of(memoperands(), [](const MachineMemOperand *MMO) {
return !MMO->isUnordered();
});
}
bool MachineInstr::isDereferenceableInvariantLoad() const {
if (!mayLoad())
return false;
if (memoperands_empty())
return false;
const MachineFrameInfo &MFI = getParent()->getParent()->getFrameInfo();
for (MachineMemOperand *MMO : memoperands()) {
if (!MMO->isUnordered())
return false;
if (MMO->isStore()) return false;
if (MMO->isInvariant() && MMO->isDereferenceable())
continue;
if (const PseudoSourceValue *PSV = MMO->getPseudoValue()) {
if (PSV->isConstant(&MFI))
continue;
}
return false;
}
return true;
}
unsigned MachineInstr::isConstantValuePHI() const {
if (!isPHI())
return 0;
assert(getNumOperands() >= 3 &&
"It's illegal to have a PHI without source operands");
Register Reg = getOperand(1).getReg();
for (unsigned i = 3, e = getNumOperands(); i < e; i += 2)
if (getOperand(i).getReg() != Reg)
return 0;
return Reg;
}
bool MachineInstr::hasUnmodeledSideEffects() const {
if (hasProperty(MCID::UnmodeledSideEffects))
return true;
if (isInlineAsm()) {
unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
return true;
}
return false;
}
bool MachineInstr::isLoadFoldBarrier() const {
return mayStore() || isCall() ||
(hasUnmodeledSideEffects() && !isPseudoProbe());
}
bool MachineInstr::allDefsAreDead() const {
for (const MachineOperand &MO : operands()) {
if (!MO.isReg() || MO.isUse())
continue;
if (!MO.isDead())
return false;
}
return true;
}
void MachineInstr::copyImplicitOps(MachineFunction &MF,
const MachineInstr &MI) {
for (const MachineOperand &MO :
llvm::drop_begin(MI.operands(), MI.getDesc().getNumOperands()))
if ((MO.isReg() && MO.isImplicit()) || MO.isRegMask())
addOperand(MF, MO);
}
bool MachineInstr::hasComplexRegisterTies() const {
const MCInstrDesc &MCID = getDesc();
if (MCID.Opcode == TargetOpcode::STATEPOINT)
return true;
for (unsigned I = 0, E = getNumOperands(); I < E; ++I) {
const auto &Operand = getOperand(I);
if (!Operand.isReg() || Operand.isDef())
continue;
int ExpectedTiedIdx = MCID.getOperandConstraint(I, MCOI::TIED_TO);
int TiedIdx = Operand.isTied() ? int(findTiedOperandIdx(I)) : -1;
if (ExpectedTiedIdx != TiedIdx)
return true;
}
return false;
}
LLT MachineInstr::getTypeToPrint(unsigned OpIdx, SmallBitVector &PrintedTypes,
const MachineRegisterInfo &MRI) const {
const MachineOperand &Op = getOperand(OpIdx);
if (!Op.isReg())
return LLT{};
if (isVariadic() || OpIdx >= getNumExplicitOperands())
return MRI.getType(Op.getReg());
auto &OpInfo = getDesc().OpInfo[OpIdx];
if (!OpInfo.isGenericType())
return MRI.getType(Op.getReg());
if (PrintedTypes[OpInfo.getGenericTypeIndex()])
return LLT{};
LLT TypeToPrint = MRI.getType(Op.getReg());
if (TypeToPrint.isValid())
PrintedTypes.set(OpInfo.getGenericTypeIndex());
return TypeToPrint;
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void MachineInstr::dump() const {
dbgs() << " ";
print(dbgs());
}
LLVM_DUMP_METHOD void MachineInstr::dumprImpl(
const MachineRegisterInfo &MRI, unsigned Depth, unsigned MaxDepth,
SmallPtrSetImpl<const MachineInstr *> &AlreadySeenInstrs) const {
if (Depth >= MaxDepth)
return;
if (!AlreadySeenInstrs.insert(this).second)
return;
if (Depth)
fdbgs().PadToColumn(Depth * 2);
print(fdbgs());
for (const MachineOperand &MO : operands()) {
if (!MO.isReg() || MO.isDef())
continue;
Register Reg = MO.getReg();
if (Reg.isPhysical())
continue;
const MachineInstr *NewMI = MRI.getUniqueVRegDef(Reg);
if (NewMI == nullptr)
continue;
NewMI->dumprImpl(MRI, Depth + 1, MaxDepth, AlreadySeenInstrs);
}
}
LLVM_DUMP_METHOD void MachineInstr::dumpr(const MachineRegisterInfo &MRI,
unsigned MaxDepth) const {
SmallPtrSet<const MachineInstr *, 16> AlreadySeenInstrs;
dumprImpl(MRI, 0, MaxDepth, AlreadySeenInstrs);
}
#endif
void MachineInstr::print(raw_ostream &OS, bool IsStandalone, bool SkipOpers,
bool SkipDebugLoc, bool AddNewLine,
const TargetInstrInfo *TII) const {
const Module *M = nullptr;
const Function *F = nullptr;
if (const MachineFunction *MF = getMFIfAvailable(*this)) {
F = &MF->getFunction();
M = F->getParent();
if (!TII)
TII = MF->getSubtarget().getInstrInfo();
}
ModuleSlotTracker MST(M);
if (F)
MST.incorporateFunction(*F);
print(OS, MST, IsStandalone, SkipOpers, SkipDebugLoc, AddNewLine, TII);
}
void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
bool IsStandalone, bool SkipOpers, bool SkipDebugLoc,
bool AddNewLine, const TargetInstrInfo *TII) const {
const TargetRegisterInfo *TRI = nullptr;
const MachineRegisterInfo *MRI = nullptr;
const TargetIntrinsicInfo *IntrinsicInfo = nullptr;
tryToGetTargetInfo(*this, TRI, MRI, IntrinsicInfo, TII);
if (isCFIInstruction())
assert(getNumOperands() == 1 && "Expected 1 operand in CFI instruction");
SmallBitVector PrintedTypes(8);
bool ShouldPrintRegisterTies = IsStandalone || hasComplexRegisterTies();
auto getTiedOperandIdx = [&](unsigned OpIdx) {
if (!ShouldPrintRegisterTies)
return 0U;
const MachineOperand &MO = getOperand(OpIdx);
if (MO.isReg() && MO.isTied() && !MO.isDef())
return findTiedOperandIdx(OpIdx);
return 0U;
};
unsigned StartOp = 0;
unsigned e = getNumOperands();
while (StartOp < e) {
const MachineOperand &MO = getOperand(StartOp);
if (!MO.isReg() || !MO.isDef() || MO.isImplicit())
break;
if (StartOp != 0)
OS << ", ";
LLT TypeToPrint = MRI ? getTypeToPrint(StartOp, PrintedTypes, *MRI) : LLT{};
unsigned TiedOperandIdx = getTiedOperandIdx(StartOp);
MO.print(OS, MST, TypeToPrint, StartOp, false, IsStandalone,
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
++StartOp;
}
if (StartOp != 0)
OS << " = ";
if (getFlag(MachineInstr::FrameSetup))
OS << "frame-setup ";
if (getFlag(MachineInstr::FrameDestroy))
OS << "frame-destroy ";
if (getFlag(MachineInstr::FmNoNans))
OS << "nnan ";
if (getFlag(MachineInstr::FmNoInfs))
OS << "ninf ";
if (getFlag(MachineInstr::FmNsz))
OS << "nsz ";
if (getFlag(MachineInstr::FmArcp))
OS << "arcp ";
if (getFlag(MachineInstr::FmContract))
OS << "contract ";
if (getFlag(MachineInstr::FmAfn))
OS << "afn ";
if (getFlag(MachineInstr::FmReassoc))
OS << "reassoc ";
if (getFlag(MachineInstr::NoUWrap))
OS << "nuw ";
if (getFlag(MachineInstr::NoSWrap))
OS << "nsw ";
if (getFlag(MachineInstr::IsExact))
OS << "exact ";
if (getFlag(MachineInstr::NoFPExcept))
OS << "nofpexcept ";
if (getFlag(MachineInstr::NoMerge))
OS << "nomerge ";
if (TII)
OS << TII->getName(getOpcode());
else
OS << "UNKNOWN";
if (SkipOpers)
return;
bool FirstOp = true;
unsigned AsmDescOp = ~0u;
unsigned AsmOpCount = 0;
if (isInlineAsm() && e >= InlineAsm::MIOp_FirstOperand) {
OS << " ";
const unsigned OpIdx = InlineAsm::MIOp_AsmString;
LLT TypeToPrint = MRI ? getTypeToPrint(OpIdx, PrintedTypes, *MRI) : LLT{};
unsigned TiedOperandIdx = getTiedOperandIdx(OpIdx);
getOperand(OpIdx).print(OS, MST, TypeToPrint, OpIdx, true, IsStandalone,
ShouldPrintRegisterTies, TiedOperandIdx, TRI,
IntrinsicInfo);
unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
OS << " [sideeffect]";
if (ExtraInfo & InlineAsm::Extra_MayLoad)
OS << " [mayload]";
if (ExtraInfo & InlineAsm::Extra_MayStore)
OS << " [maystore]";
if (ExtraInfo & InlineAsm::Extra_IsConvergent)
OS << " [isconvergent]";
if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
OS << " [alignstack]";
if (getInlineAsmDialect() == InlineAsm::AD_ATT)
OS << " [attdialect]";
if (getInlineAsmDialect() == InlineAsm::AD_Intel)
OS << " [inteldialect]";
StartOp = AsmDescOp = InlineAsm::MIOp_FirstOperand;
FirstOp = false;
}
for (unsigned i = StartOp, e = getNumOperands(); i != e; ++i) {
const MachineOperand &MO = getOperand(i);
if (FirstOp) FirstOp = false; else OS << ",";
OS << " ";
if (isDebugValue() && MO.isMetadata()) {
auto *DIV = dyn_cast<DILocalVariable>(MO.getMetadata());
if (DIV && !DIV->getName().empty())
OS << "!\"" << DIV->getName() << '\"';
else {
LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{};
unsigned TiedOperandIdx = getTiedOperandIdx(i);
MO.print(OS, MST, TypeToPrint, i, true, IsStandalone,
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
}
} else if (isDebugLabel() && MO.isMetadata()) {
auto *DIL = dyn_cast<DILabel>(MO.getMetadata());
if (DIL && !DIL->getName().empty())
OS << "\"" << DIL->getName() << '\"';
else {
LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{};
unsigned TiedOperandIdx = getTiedOperandIdx(i);
MO.print(OS, MST, TypeToPrint, i, true, IsStandalone,
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
}
} else if (i == AsmDescOp && MO.isImm()) {
OS << '$' << AsmOpCount++;
unsigned Flag = MO.getImm();
OS << ":[";
OS << InlineAsm::getKindName(InlineAsm::getKind(Flag));
unsigned RCID = 0;
if (!InlineAsm::isImmKind(Flag) && !InlineAsm::isMemKind(Flag) &&
InlineAsm::hasRegClassConstraint(Flag, RCID)) {
if (TRI) {
OS << ':' << TRI->getRegClassName(TRI->getRegClass(RCID));
} else
OS << ":RC" << RCID;
}
if (InlineAsm::isMemKind(Flag)) {
unsigned MCID = InlineAsm::getMemoryConstraintID(Flag);
OS << ":" << InlineAsm::getMemConstraintName(MCID);
}
unsigned TiedTo = 0;
if (InlineAsm::isUseOperandTiedToDef(Flag, TiedTo))
OS << " tiedto:$" << TiedTo;
OS << ']';
AsmDescOp += 1 + InlineAsm::getNumOperandRegisters(Flag);
} else {
LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{};
unsigned TiedOperandIdx = getTiedOperandIdx(i);
if (MO.isImm() && isOperandSubregIdx(i))
MachineOperand::printSubRegIdx(OS, MO.getImm(), TRI);
else
MO.print(OS, MST, TypeToPrint, i, true, IsStandalone,
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
}
}
if (MCSymbol *PreInstrSymbol = getPreInstrSymbol()) {
if (!FirstOp) {
FirstOp = false;
OS << ',';
}
OS << " pre-instr-symbol ";
MachineOperand::printSymbol(OS, *PreInstrSymbol);
}
if (MCSymbol *PostInstrSymbol = getPostInstrSymbol()) {
if (!FirstOp) {
FirstOp = false;
OS << ',';
}
OS << " post-instr-symbol ";
MachineOperand::printSymbol(OS, *PostInstrSymbol);
}
if (MDNode *HeapAllocMarker = getHeapAllocMarker()) {
if (!FirstOp) {
FirstOp = false;
OS << ',';
}
OS << " heap-alloc-marker ";
HeapAllocMarker->printAsOperand(OS, MST);
}
if (DebugInstrNum) {
if (!FirstOp)
OS << ",";
OS << " debug-instr-number " << DebugInstrNum;
}
if (!SkipDebugLoc) {
if (const DebugLoc &DL = getDebugLoc()) {
if (!FirstOp)
OS << ',';
OS << " debug-location ";
DL->printAsOperand(OS, MST);
}
}
if (!memoperands_empty()) {
SmallVector<StringRef, 0> SSNs;
const LLVMContext *Context = nullptr;
std::unique_ptr<LLVMContext> CtxPtr;
const MachineFrameInfo *MFI = nullptr;
if (const MachineFunction *MF = getMFIfAvailable(*this)) {
MFI = &MF->getFrameInfo();
Context = &MF->getFunction().getContext();
} else {
CtxPtr = std::make_unique<LLVMContext>();
Context = CtxPtr.get();
}
OS << " :: ";
bool NeedComma = false;
for (const MachineMemOperand *Op : memoperands()) {
if (NeedComma)
OS << ", ";
Op->print(OS, MST, SSNs, *Context, MFI, TII);
NeedComma = true;
}
}
if (SkipDebugLoc)
return;
bool HaveSemi = false;
if (const DebugLoc &DL = getDebugLoc()) {
if (!HaveSemi) {
OS << ';';
HaveSemi = true;
}
OS << ' ';
DL.print(OS);
}
if (isDebugValue() && getDebugVariableOp().isMetadata()) {
if (!HaveSemi) {
OS << ";";
HaveSemi = true;
}
auto *DV = getDebugVariable();
OS << " line no:" << DV->getLine();
if (isIndirectDebugValue())
OS << " indirect";
}
if (AddNewLine)
OS << '\n';
}
bool MachineInstr::addRegisterKilled(Register IncomingReg,
const TargetRegisterInfo *RegInfo,
bool AddIfNotFound) {
bool isPhysReg = Register::isPhysicalRegister(IncomingReg);
bool hasAliases = isPhysReg &&
MCRegAliasIterator(IncomingReg, RegInfo, false).isValid();
bool Found = false;
SmallVector<unsigned,4> DeadOps;
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
MachineOperand &MO = getOperand(i);
if (!MO.isReg() || !MO.isUse() || MO.isUndef())
continue;
if (MO.isDebug())
continue;
Register Reg = MO.getReg();
if (!Reg)
continue;
if (Reg == IncomingReg) {
if (!Found) {
if (MO.isKill())
return true;
if (isPhysReg && isRegTiedToDefOperand(i))
return true;
MO.setIsKill();
Found = true;
}
} else if (hasAliases && MO.isKill() && Register::isPhysicalRegister(Reg)) {
if (RegInfo->isSuperRegister(IncomingReg, Reg))
return true;
if (RegInfo->isSubRegister(IncomingReg, Reg))
DeadOps.push_back(i);
}
}
while (!DeadOps.empty()) {
unsigned OpIdx = DeadOps.back();
if (getOperand(OpIdx).isImplicit() &&
(!isInlineAsm() || findInlineAsmFlagIdx(OpIdx) < 0))
removeOperand(OpIdx);
else
getOperand(OpIdx).setIsKill(false);
DeadOps.pop_back();
}
if (!Found && AddIfNotFound) {
addOperand(MachineOperand::CreateReg(IncomingReg,
false ,
true ,
true ));
return true;
}
return Found;
}
void MachineInstr::clearRegisterKills(Register Reg,
const TargetRegisterInfo *RegInfo) {
if (!Register::isPhysicalRegister(Reg))
RegInfo = nullptr;
for (MachineOperand &MO : operands()) {
if (!MO.isReg() || !MO.isUse() || !MO.isKill())
continue;
Register OpReg = MO.getReg();
if ((RegInfo && RegInfo->regsOverlap(Reg, OpReg)) || Reg == OpReg)
MO.setIsKill(false);
}
}
bool MachineInstr::addRegisterDead(Register Reg,
const TargetRegisterInfo *RegInfo,
bool AddIfNotFound) {
bool isPhysReg = Register::isPhysicalRegister(Reg);
bool hasAliases = isPhysReg &&
MCRegAliasIterator(Reg, RegInfo, false).isValid();
bool Found = false;
SmallVector<unsigned,4> DeadOps;
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
MachineOperand &MO = getOperand(i);
if (!MO.isReg() || !MO.isDef())
continue;
Register MOReg = MO.getReg();
if (!MOReg)
continue;
if (MOReg == Reg) {
MO.setIsDead();
Found = true;
} else if (hasAliases && MO.isDead() &&
Register::isPhysicalRegister(MOReg)) {
if (RegInfo->isSuperRegister(Reg, MOReg))
return true;
if (RegInfo->isSubRegister(Reg, MOReg))
DeadOps.push_back(i);
}
}
while (!DeadOps.empty()) {
unsigned OpIdx = DeadOps.back();
if (getOperand(OpIdx).isImplicit() &&
(!isInlineAsm() || findInlineAsmFlagIdx(OpIdx) < 0))
removeOperand(OpIdx);
else
getOperand(OpIdx).setIsDead(false);
DeadOps.pop_back();
}
if (Found || !AddIfNotFound)
return Found;
addOperand(MachineOperand::CreateReg(Reg,
true ,
true ,
false ,
true ));
return true;
}
void MachineInstr::clearRegisterDeads(Register Reg) {
for (MachineOperand &MO : operands()) {
if (!MO.isReg() || !MO.isDef() || MO.getReg() != Reg)
continue;
MO.setIsDead(false);
}
}
void MachineInstr::setRegisterDefReadUndef(Register Reg, bool IsUndef) {
for (MachineOperand &MO : operands()) {
if (!MO.isReg() || !MO.isDef() || MO.getReg() != Reg || MO.getSubReg() == 0)
continue;
MO.setIsUndef(IsUndef);
}
}
void MachineInstr::addRegisterDefined(Register Reg,
const TargetRegisterInfo *RegInfo) {
if (Register::isPhysicalRegister(Reg)) {
MachineOperand *MO = findRegisterDefOperand(Reg, false, false, RegInfo);
if (MO)
return;
} else {
for (const MachineOperand &MO : operands()) {
if (MO.isReg() && MO.getReg() == Reg && MO.isDef() &&
MO.getSubReg() == 0)
return;
}
}
addOperand(MachineOperand::CreateReg(Reg,
true ,
true ));
}
void MachineInstr::setPhysRegsDeadExcept(ArrayRef<Register> UsedRegs,
const TargetRegisterInfo &TRI) {
bool HasRegMask = false;
for (MachineOperand &MO : operands()) {
if (MO.isRegMask()) {
HasRegMask = true;
continue;
}
if (!MO.isReg() || !MO.isDef()) continue;
Register Reg = MO.getReg();
if (!Reg.isPhysical())
continue;
if (llvm::none_of(UsedRegs,
[&](MCRegister Use) { return TRI.regsOverlap(Use, Reg); }))
MO.setIsDead();
}
if (HasRegMask)
for (const Register &UsedReg : UsedRegs)
addRegisterDefined(UsedReg, &TRI);
}
unsigned
MachineInstrExpressionTrait::getHashValue(const MachineInstr* const &MI) {
SmallVector<size_t, 16> HashComponents;
HashComponents.reserve(MI->getNumOperands() + 1);
HashComponents.push_back(MI->getOpcode());
for (const MachineOperand &MO : MI->operands()) {
if (MO.isReg() && MO.isDef() && Register::isVirtualRegister(MO.getReg()))
continue;
HashComponents.push_back(hash_value(MO));
}
return hash_combine_range(HashComponents.begin(), HashComponents.end());
}
void MachineInstr::emitError(StringRef Msg) const {
uint64_t LocCookie = 0;
const MDNode *LocMD = nullptr;
for (unsigned i = getNumOperands(); i != 0; --i) {
if (getOperand(i-1).isMetadata() &&
(LocMD = getOperand(i-1).getMetadata()) &&
LocMD->getNumOperands() != 0) {
if (const ConstantInt *CI =
mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
LocCookie = CI->getZExtValue();
break;
}
}
}
if (const MachineBasicBlock *MBB = getParent())
if (const MachineFunction *MF = MBB->getParent())
return MF->getMMI().getModule()->getContext().emitError(LocCookie, Msg);
report_fatal_error(Msg);
}
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
Register Reg, const MDNode *Variable,
const MDNode *Expr) {
assert(isa<DILocalVariable>(Variable) && "not a variable");
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
auto MIB = BuildMI(MF, DL, MCID).addReg(Reg);
if (IsIndirect)
MIB.addImm(0U);
else
MIB.addReg(0U);
return MIB.addMetadata(Variable).addMetadata(Expr);
}
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
const MachineOperand &MO,
const MDNode *Variable, const MDNode *Expr) {
assert(isa<DILocalVariable>(Variable) && "not a variable");
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
if (MO.isReg())
return BuildMI(MF, DL, MCID, IsIndirect, MO.getReg(), Variable, Expr);
auto MIB = BuildMI(MF, DL, MCID).add(MO);
if (IsIndirect)
MIB.addImm(0U);
else
MIB.addReg(0U);
return MIB.addMetadata(Variable).addMetadata(Expr);
}
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr) {
assert(isa<DILocalVariable>(Variable) && "not a variable");
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
if (MCID.Opcode == TargetOpcode::DBG_VALUE)
return BuildMI(MF, DL, MCID, IsIndirect, MOs[0], Variable, Expr);
auto MIB = BuildMI(MF, DL, MCID);
MIB.addMetadata(Variable).addMetadata(Expr);
for (const MachineOperand &MO : MOs)
if (MO.isReg())
MIB.addReg(MO.getReg());
else
MIB.add(MO);
return MIB;
}
MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, const MCInstrDesc &MCID,
bool IsIndirect, Register Reg,
const MDNode *Variable, const MDNode *Expr) {
MachineFunction &MF = *BB.getParent();
MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, Reg, Variable, Expr);
BB.insert(I, MI);
return MachineInstrBuilder(MF, MI);
}
MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, const MCInstrDesc &MCID,
bool IsIndirect, MachineOperand &MO,
const MDNode *Variable, const MDNode *Expr) {
MachineFunction &MF = *BB.getParent();
MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, MO, Variable, Expr);
BB.insert(I, MI);
return MachineInstrBuilder(MF, *MI);
}
MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, const MCInstrDesc &MCID,
bool IsIndirect, ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr) {
MachineFunction &MF = *BB.getParent();
MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, MOs, Variable, Expr);
BB.insert(I, MI);
return MachineInstrBuilder(MF, *MI);
}
static const DIExpression *
computeExprForSpill(const MachineInstr &MI,
SmallVectorImpl<const MachineOperand *> &SpilledOperands) {
assert(MI.getDebugVariable()->isValidLocationForIntrinsic(MI.getDebugLoc()) &&
"Expected inlined-at fields to agree");
const DIExpression *Expr = MI.getDebugExpression();
if (MI.isIndirectDebugValue()) {
assert(MI.getDebugOffset().getImm() == 0 &&
"DBG_VALUE with nonzero offset");
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
} else if (MI.isDebugValueList()) {
std::array<uint64_t, 1> Ops{{dwarf::DW_OP_deref}};
for (const MachineOperand *Op : SpilledOperands) {
unsigned OpIdx = MI.getDebugOperandIndex(Op);
Expr = DIExpression::appendOpsToArg(Expr, Ops, OpIdx);
}
}
return Expr;
}
static const DIExpression *computeExprForSpill(const MachineInstr &MI,
Register SpillReg) {
assert(MI.hasDebugOperandForReg(SpillReg) && "Spill Reg is not used in MI.");
SmallVector<const MachineOperand *> SpillOperands;
for (const MachineOperand &Op : MI.getDebugOperandsForReg(SpillReg))
SpillOperands.push_back(&Op);
return computeExprForSpill(MI, SpillOperands);
}
MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const MachineInstr &Orig,
int FrameIndex, Register SpillReg) {
const DIExpression *Expr = computeExprForSpill(Orig, SpillReg);
MachineInstrBuilder NewMI =
BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc());
if (Orig.isNonListDebugValue())
NewMI.addFrameIndex(FrameIndex).addImm(0U);
NewMI.addMetadata(Orig.getDebugVariable()).addMetadata(Expr);
if (Orig.isDebugValueList()) {
for (const MachineOperand &Op : Orig.debug_operands())
if (Op.isReg() && Op.getReg() == SpillReg)
NewMI.addFrameIndex(FrameIndex);
else
NewMI.add(MachineOperand(Op));
}
return NewMI;
}
MachineInstr *llvm::buildDbgValueForSpill(
MachineBasicBlock &BB, MachineBasicBlock::iterator I,
const MachineInstr &Orig, int FrameIndex,
SmallVectorImpl<const MachineOperand *> &SpilledOperands) {
const DIExpression *Expr = computeExprForSpill(Orig, SpilledOperands);
MachineInstrBuilder NewMI =
BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc());
if (Orig.isNonListDebugValue())
NewMI.addFrameIndex(FrameIndex).addImm(0U);
NewMI.addMetadata(Orig.getDebugVariable()).addMetadata(Expr);
if (Orig.isDebugValueList()) {
for (const MachineOperand &Op : Orig.debug_operands())
if (is_contained(SpilledOperands, &Op))
NewMI.addFrameIndex(FrameIndex);
else
NewMI.add(MachineOperand(Op));
}
return NewMI;
}
void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex,
Register Reg) {
const DIExpression *Expr = computeExprForSpill(Orig, Reg);
if (Orig.isNonListDebugValue())
Orig.getDebugOffset().ChangeToImmediate(0U);
for (MachineOperand &Op : Orig.getDebugOperandsForReg(Reg))
Op.ChangeToFrameIndex(FrameIndex);
Orig.getDebugExpressionOp().setMetadata(Expr);
}
void MachineInstr::collectDebugValues(
SmallVectorImpl<MachineInstr *> &DbgValues) {
MachineInstr &MI = *this;
if (!MI.getOperand(0).isReg())
return;
MachineBasicBlock::iterator DI = MI; ++DI;
for (MachineBasicBlock::iterator DE = MI.getParent()->end();
DI != DE; ++DI) {
if (!DI->isDebugValue())
return;
if (DI->hasDebugOperandForReg(MI.getOperand(0).getReg()))
DbgValues.push_back(&*DI);
}
}
void MachineInstr::changeDebugValuesDefReg(Register Reg) {
SmallVector<MachineInstr *, 2> DbgValues;
if (!getOperand(0).isReg())
return;
Register DefReg = getOperand(0).getReg();
auto *MRI = getRegInfo();
for (auto &MO : MRI->use_operands(DefReg)) {
auto *DI = MO.getParent();
if (!DI->isDebugValue())
continue;
if (DI->hasDebugOperandForReg(DefReg)) {
DbgValues.push_back(DI);
}
}
for (auto *DBI : DbgValues)
for (MachineOperand &Op : DBI->getDebugOperandsForReg(DefReg))
Op.setReg(Reg);
}
using MMOList = SmallVector<const MachineMemOperand *, 2>;
static unsigned getSpillSlotSize(const MMOList &Accesses,
const MachineFrameInfo &MFI) {
unsigned Size = 0;
for (const auto *A : Accesses)
if (MFI.isSpillSlotObjectIndex(
cast<FixedStackPseudoSourceValue>(A->getPseudoValue())
->getFrameIndex()))
Size += A->getSize();
return Size;
}
Optional<unsigned>
MachineInstr::getSpillSize(const TargetInstrInfo *TII) const {
int FI;
if (TII->isStoreToStackSlotPostFE(*this, FI)) {
const MachineFrameInfo &MFI = getMF()->getFrameInfo();
if (MFI.isSpillSlotObjectIndex(FI))
return (*memoperands_begin())->getSize();
}
return None;
}
Optional<unsigned>
MachineInstr::getFoldedSpillSize(const TargetInstrInfo *TII) const {
MMOList Accesses;
if (TII->hasStoreToStackSlot(*this, Accesses))
return getSpillSlotSize(Accesses, getMF()->getFrameInfo());
return None;
}
Optional<unsigned>
MachineInstr::getRestoreSize(const TargetInstrInfo *TII) const {
int FI;
if (TII->isLoadFromStackSlotPostFE(*this, FI)) {
const MachineFrameInfo &MFI = getMF()->getFrameInfo();
if (MFI.isSpillSlotObjectIndex(FI))
return (*memoperands_begin())->getSize();
}
return None;
}
Optional<unsigned>
MachineInstr::getFoldedRestoreSize(const TargetInstrInfo *TII) const {
MMOList Accesses;
if (TII->hasLoadFromStackSlot(*this, Accesses))
return getSpillSlotSize(Accesses, getMF()->getFrameInfo());
return None;
}
unsigned MachineInstr::getDebugInstrNum() {
if (DebugInstrNum == 0)
DebugInstrNum = getParent()->getParent()->getNewDebugInstrNum();
return DebugInstrNum;
}
unsigned MachineInstr::getDebugInstrNum(MachineFunction &MF) {
if (DebugInstrNum == 0)
DebugInstrNum = MF.getNewDebugInstrNum();
return DebugInstrNum;
}