summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h')
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h490
1 files changed, 371 insertions, 119 deletions
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
index 70aae47c8bdc..2fdc37c6dda2 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
@@ -19,6 +19,7 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include <optional>
#include "LiveDebugValues.h"
@@ -30,6 +31,7 @@ class InstrRefLDVTest;
namespace LiveDebugValues {
class MLocTracker;
+class DbgOpIDMap;
using namespace llvm;
@@ -168,6 +170,40 @@ public:
static ValueIDNum TombstoneValue;
};
+} // End namespace LiveDebugValues
+
+namespace llvm {
+using namespace LiveDebugValues;
+
+template <> struct DenseMapInfo<LocIdx> {
+ static inline LocIdx getEmptyKey() { return LocIdx::MakeIllegalLoc(); }
+ static inline LocIdx getTombstoneKey() { return LocIdx::MakeTombstoneLoc(); }
+
+ static unsigned getHashValue(const LocIdx &Loc) { return Loc.asU64(); }
+
+ static bool isEqual(const LocIdx &A, const LocIdx &B) { return A == B; }
+};
+
+template <> struct DenseMapInfo<ValueIDNum> {
+ static inline ValueIDNum getEmptyKey() { return ValueIDNum::EmptyValue; }
+ static inline ValueIDNum getTombstoneKey() {
+ return ValueIDNum::TombstoneValue;
+ }
+
+ static unsigned getHashValue(const ValueIDNum &Val) {
+ return hash_value(Val.asU64());
+ }
+
+ static bool isEqual(const ValueIDNum &A, const ValueIDNum &B) {
+ return A == B;
+ }
+};
+
+} // end namespace llvm
+
+namespace LiveDebugValues {
+using namespace llvm;
+
/// Type for a table of values in a block.
using ValueTable = std::unique_ptr<ValueIDNum[]>;
@@ -199,41 +235,219 @@ public:
/// the value, and Boolean of whether or not it's indirect.
class DbgValueProperties {
public:
- DbgValueProperties(const DIExpression *DIExpr, bool Indirect)
- : DIExpr(DIExpr), Indirect(Indirect) {}
+ DbgValueProperties(const DIExpression *DIExpr, bool Indirect, bool IsVariadic)
+ : DIExpr(DIExpr), Indirect(Indirect), IsVariadic(IsVariadic) {}
/// Extract properties from an existing DBG_VALUE instruction.
DbgValueProperties(const MachineInstr &MI) {
assert(MI.isDebugValue());
+ assert(MI.getDebugExpression()->getNumLocationOperands() == 0 ||
+ MI.isDebugValueList() || MI.isUndefDebugValue());
+ IsVariadic = MI.isDebugValueList();
DIExpr = MI.getDebugExpression();
- Indirect = MI.getOperand(1).isImm();
+ Indirect = MI.isDebugOffsetImm();
+ }
+
+ bool isJoinable(const DbgValueProperties &Other) const {
+ return DIExpression::isEqualExpression(DIExpr, Indirect, Other.DIExpr,
+ Other.Indirect);
}
bool operator==(const DbgValueProperties &Other) const {
- return std::tie(DIExpr, Indirect) == std::tie(Other.DIExpr, Other.Indirect);
+ return std::tie(DIExpr, Indirect, IsVariadic) ==
+ std::tie(Other.DIExpr, Other.Indirect, Other.IsVariadic);
}
bool operator!=(const DbgValueProperties &Other) const {
return !(*this == Other);
}
+ unsigned getLocationOpCount() const {
+ return IsVariadic ? DIExpr->getNumLocationOperands() : 1;
+ }
+
const DIExpression *DIExpr;
bool Indirect;
+ bool IsVariadic;
+};
+
+/// TODO: Might pack better if we changed this to a Struct of Arrays, since
+/// MachineOperand is width 32, making this struct width 33. We could also
+/// potentially avoid storing the whole MachineOperand (sizeof=32), instead
+/// choosing to store just the contents portion (sizeof=8) and a Kind enum,
+/// since we already know it is some type of immediate value.
+/// Stores a single debug operand, which can either be a MachineOperand for
+/// directly storing immediate values, or a ValueIDNum representing some value
+/// computed at some point in the program. IsConst is used as a discriminator.
+struct DbgOp {
+ union {
+ ValueIDNum ID;
+ MachineOperand MO;
+ };
+ bool IsConst;
+
+ DbgOp() : ID(ValueIDNum::EmptyValue), IsConst(false) {}
+ DbgOp(ValueIDNum ID) : ID(ID), IsConst(false) {}
+ DbgOp(MachineOperand MO) : MO(MO), IsConst(true) {}
+
+ bool isUndef() const { return !IsConst && ID == ValueIDNum::EmptyValue; }
+
+#ifndef NDEBUG
+ void dump(const MLocTracker *MTrack) const;
+#endif
+};
+
+/// A DbgOp whose ID (if any) has resolved to an actual location, LocIdx. Used
+/// when working with concrete debug values, i.e. when joining MLocs and VLocs
+/// in the TransferTracker or emitting DBG_VALUE/DBG_VALUE_LIST instructions in
+/// the MLocTracker.
+struct ResolvedDbgOp {
+ union {
+ LocIdx Loc;
+ MachineOperand MO;
+ };
+ bool IsConst;
+
+ ResolvedDbgOp(LocIdx Loc) : Loc(Loc), IsConst(false) {}
+ ResolvedDbgOp(MachineOperand MO) : MO(MO), IsConst(true) {}
+
+ bool operator==(const ResolvedDbgOp &Other) const {
+ if (IsConst != Other.IsConst)
+ return false;
+ if (IsConst)
+ return MO.isIdenticalTo(Other.MO);
+ return Loc == Other.Loc;
+ }
+
+#ifndef NDEBUG
+ void dump(const MLocTracker *MTrack) const;
+#endif
+};
+
+/// An ID used in the DbgOpIDMap (below) to lookup a stored DbgOp. This is used
+/// in place of actual DbgOps inside of a DbgValue to reduce its size, as
+/// DbgValue is very frequently used and passed around, and the actual DbgOp is
+/// over 8x larger than this class, due to storing a MachineOperand. This ID
+/// should be equal for all equal DbgOps, and also encodes whether the mapped
+/// DbgOp is a constant, meaning that for simple equality or const-ness checks
+/// it is not necessary to lookup this ID.
+struct DbgOpID {
+ struct IsConstIndexPair {
+ uint32_t IsConst : 1;
+ uint32_t Index : 31;
+ };
+
+ union {
+ struct IsConstIndexPair ID;
+ uint32_t RawID;
+ };
+
+ DbgOpID() : RawID(UndefID.RawID) {
+ static_assert(sizeof(DbgOpID) == 4, "DbgOpID should fit within 4 bytes.");
+ }
+ DbgOpID(uint32_t RawID) : RawID(RawID) {}
+ DbgOpID(bool IsConst, uint32_t Index) : ID({IsConst, Index}) {}
+
+ static DbgOpID UndefID;
+
+ bool operator==(const DbgOpID &Other) const { return RawID == Other.RawID; }
+ bool operator!=(const DbgOpID &Other) const { return !(*this == Other); }
+
+ uint32_t asU32() const { return RawID; }
+
+ bool isUndef() const { return *this == UndefID; }
+ bool isConst() const { return ID.IsConst && !isUndef(); }
+ uint32_t getIndex() const { return ID.Index; }
+
+#ifndef NDEBUG
+ void dump(const MLocTracker *MTrack, const DbgOpIDMap *OpStore) const;
+#endif
+};
+
+/// Class storing the complete set of values that are observed by DbgValues
+/// within the current function. Allows 2-way lookup, with `find` returning the
+/// Op for a given ID and `insert` returning the ID for a given Op (creating one
+/// if none exists).
+class DbgOpIDMap {
+
+ SmallVector<ValueIDNum, 0> ValueOps;
+ SmallVector<MachineOperand, 0> ConstOps;
+
+ DenseMap<ValueIDNum, DbgOpID> ValueOpToID;
+ DenseMap<MachineOperand, DbgOpID> ConstOpToID;
+
+public:
+ /// If \p Op does not already exist in this map, it is inserted and the
+ /// corresponding DbgOpID is returned. If Op already exists in this map, then
+ /// no change is made and the existing ID for Op is returned.
+ /// Calling this with the undef DbgOp will always return DbgOpID::UndefID.
+ DbgOpID insert(DbgOp Op) {
+ if (Op.isUndef())
+ return DbgOpID::UndefID;
+ if (Op.IsConst)
+ return insertConstOp(Op.MO);
+ return insertValueOp(Op.ID);
+ }
+ /// Returns the DbgOp associated with \p ID. Should only be used for IDs
+ /// returned from calling `insert` from this map or DbgOpID::UndefID.
+ DbgOp find(DbgOpID ID) const {
+ if (ID == DbgOpID::UndefID)
+ return DbgOp();
+ if (ID.isConst())
+ return DbgOp(ConstOps[ID.getIndex()]);
+ return DbgOp(ValueOps[ID.getIndex()]);
+ }
+
+ void clear() {
+ ValueOps.clear();
+ ConstOps.clear();
+ ValueOpToID.clear();
+ ConstOpToID.clear();
+ }
+
+private:
+ DbgOpID insertConstOp(MachineOperand &MO) {
+ auto ExistingIt = ConstOpToID.find(MO);
+ if (ExistingIt != ConstOpToID.end())
+ return ExistingIt->second;
+ DbgOpID ID(true, ConstOps.size());
+ ConstOpToID.insert(std::make_pair(MO, ID));
+ ConstOps.push_back(MO);
+ return ID;
+ }
+ DbgOpID insertValueOp(ValueIDNum VID) {
+ auto ExistingIt = ValueOpToID.find(VID);
+ if (ExistingIt != ValueOpToID.end())
+ return ExistingIt->second;
+ DbgOpID ID(false, ValueOps.size());
+ ValueOpToID.insert(std::make_pair(VID, ID));
+ ValueOps.push_back(VID);
+ return ID;
+ }
};
-/// Class recording the (high level) _value_ of a variable. Identifies either
-/// the value of the variable as a ValueIDNum, or a constant MachineOperand.
+// We set the maximum number of operands that we will handle to keep DbgValue
+// within a reasonable size (64 bytes), as we store and pass a lot of them
+// around.
+#define MAX_DBG_OPS 8
+
+/// Class recording the (high level) _value_ of a variable. Identifies the value
+/// of the variable as a list of ValueIDNums and constant MachineOperands, or as
+/// an empty list for undef debug values or VPHI values which we have not found
+/// valid locations for.
/// This class also stores meta-information about how the value is qualified.
/// Used to reason about variable values when performing the second
/// (DebugVariable specific) dataflow analysis.
class DbgValue {
+private:
+ /// If Kind is Def or VPHI, the set of IDs corresponding to the DbgOps that
+ /// are used. VPHIs set every ID to EmptyID when we have not found a valid
+ /// machine-value for every operand, and sets them to the corresponding
+ /// machine-values when we have found all of them.
+ DbgOpID DbgOps[MAX_DBG_OPS];
+ unsigned OpCount;
+
public:
- /// If Kind is Def, the value number that this value is based on. VPHIs set
- /// this field to EmptyValue if there is no machine-value for this VPHI, or
- /// the corresponding machine-value if there is one.
- ValueIDNum ID;
- /// If Kind is Const, the MachineOperand defining this value.
- Optional<MachineOperand> MO;
/// For a NoVal or VPHI DbgValue, which block it was generated in.
int BlockNo;
@@ -242,8 +456,8 @@ public:
typedef enum {
Undef, // Represents a DBG_VALUE $noreg in the transfer function only.
- Def, // This value is defined by an inst, or is a PHI value.
- Const, // A constant value contained in the MachineOperand field.
+ Def, // This value is defined by some combination of constants,
+ // instructions, or PHI values.
VPHI, // Incoming values to BlockNo differ, those values must be joined by
// a PHI in this block.
NoVal, // Empty DbgValue indicating an unknown value. Used as initializer,
@@ -252,52 +466,113 @@ public:
/// Discriminator for whether this is a constant or an in-program value.
KindT Kind;
- DbgValue(const ValueIDNum &Val, const DbgValueProperties &Prop, KindT Kind)
- : ID(Val), MO(None), BlockNo(0), Properties(Prop), Kind(Kind) {
- assert(Kind == Def);
+ DbgValue(ArrayRef<DbgOpID> DbgOps, const DbgValueProperties &Prop)
+ : OpCount(DbgOps.size()), BlockNo(0), Properties(Prop), Kind(Def) {
+ static_assert(sizeof(DbgValue) <= 64,
+ "DbgValue should fit within 64 bytes.");
+ assert(DbgOps.size() == Prop.getLocationOpCount());
+ if (DbgOps.size() > MAX_DBG_OPS ||
+ any_of(DbgOps, [](DbgOpID ID) { return ID.isUndef(); })) {
+ Kind = Undef;
+ OpCount = 0;
+#define DEBUG_TYPE "LiveDebugValues"
+ if (DbgOps.size() > MAX_DBG_OPS) {
+ LLVM_DEBUG(dbgs() << "Found DbgValue with more than maximum allowed "
+ "operands.\n");
+ }
+#undef DEBUG_TYPE
+ } else {
+ for (unsigned Idx = 0; Idx < DbgOps.size(); ++Idx)
+ this->DbgOps[Idx] = DbgOps[Idx];
+ }
}
DbgValue(unsigned BlockNo, const DbgValueProperties &Prop, KindT Kind)
- : ID(ValueIDNum::EmptyValue), MO(None), BlockNo(BlockNo),
- Properties(Prop), Kind(Kind) {
+ : OpCount(0), BlockNo(BlockNo), Properties(Prop), Kind(Kind) {
assert(Kind == NoVal || Kind == VPHI);
}
- DbgValue(const MachineOperand &MO, const DbgValueProperties &Prop, KindT Kind)
- : ID(ValueIDNum::EmptyValue), MO(MO), BlockNo(0), Properties(Prop),
- Kind(Kind) {
- assert(Kind == Const);
- }
-
DbgValue(const DbgValueProperties &Prop, KindT Kind)
- : ID(ValueIDNum::EmptyValue), MO(None), BlockNo(0), Properties(Prop),
- Kind(Kind) {
+ : OpCount(0), BlockNo(0), Properties(Prop), Kind(Kind) {
assert(Kind == Undef &&
"Empty DbgValue constructor must pass in Undef kind");
}
#ifndef NDEBUG
- void dump(const MLocTracker *MTrack) const;
+ void dump(const MLocTracker *MTrack = nullptr,
+ const DbgOpIDMap *OpStore = nullptr) const;
#endif
bool operator==(const DbgValue &Other) const {
if (std::tie(Kind, Properties) != std::tie(Other.Kind, Other.Properties))
return false;
- else if (Kind == Def && ID != Other.ID)
+ else if (Kind == Def && !equal(getDbgOpIDs(), Other.getDbgOpIDs()))
return false;
else if (Kind == NoVal && BlockNo != Other.BlockNo)
return false;
- else if (Kind == Const)
- return MO->isIdenticalTo(*Other.MO);
else if (Kind == VPHI && BlockNo != Other.BlockNo)
return false;
- else if (Kind == VPHI && ID != Other.ID)
+ else if (Kind == VPHI && !equal(getDbgOpIDs(), Other.getDbgOpIDs()))
return false;
return true;
}
bool operator!=(const DbgValue &Other) const { return !(*this == Other); }
+
+ // Returns an array of all the machine values used to calculate this variable
+ // value, or an empty list for an Undef or unjoined VPHI.
+ ArrayRef<DbgOpID> getDbgOpIDs() const { return {DbgOps, OpCount}; }
+
+ // Returns either DbgOps[Index] if this DbgValue has Debug Operands, or
+ // the ID for ValueIDNum::EmptyValue otherwise (i.e. if this is an Undef,
+ // NoVal, or an unjoined VPHI).
+ DbgOpID getDbgOpID(unsigned Index) const {
+ if (!OpCount)
+ return DbgOpID::UndefID;
+ assert(Index < OpCount);
+ return DbgOps[Index];
+ }
+ // Replaces this DbgValue's existing DbgOpIDs (if any) with the contents of
+ // \p NewIDs. The number of DbgOpIDs passed must be equal to the number of
+ // arguments expected by this DbgValue's properties (the return value of
+ // `getLocationOpCount()`).
+ void setDbgOpIDs(ArrayRef<DbgOpID> NewIDs) {
+ // We can go from no ops to some ops, but not from some ops to no ops.
+ assert(NewIDs.size() == getLocationOpCount() &&
+ "Incorrect number of Debug Operands for this DbgValue.");
+ OpCount = NewIDs.size();
+ for (unsigned Idx = 0; Idx < NewIDs.size(); ++Idx)
+ DbgOps[Idx] = NewIDs[Idx];
+ }
+
+ // The number of debug operands expected by this DbgValue's expression.
+ // getDbgOpIDs() should return an array of this length, unless this is an
+ // Undef or an unjoined VPHI.
+ unsigned getLocationOpCount() const {
+ return Properties.getLocationOpCount();
+ }
+
+ // Returns true if this or Other are unjoined PHIs, which do not have defined
+ // Loc Ops, or if the `n`th Loc Op for this has a different constness to the
+ // `n`th Loc Op for Other.
+ bool hasJoinableLocOps(const DbgValue &Other) const {
+ if (isUnjoinedPHI() || Other.isUnjoinedPHI())
+ return true;
+ for (unsigned Idx = 0; Idx < getLocationOpCount(); ++Idx) {
+ if (getDbgOpID(Idx).isConst() != Other.getDbgOpID(Idx).isConst())
+ return false;
+ }
+ return true;
+ }
+
+ bool isUnjoinedPHI() const { return Kind == VPHI && OpCount == 0; }
+
+ bool hasIdenticalValidLocOps(const DbgValue &Other) const {
+ if (!OpCount)
+ return false;
+ return equal(getDbgOpIDs(), Other.getDbgOpIDs());
+ }
};
class LocIdxToIndexFunctor {
@@ -620,9 +895,9 @@ public:
void writeRegMask(const MachineOperand *MO, unsigned CurBB, unsigned InstID);
/// Find LocIdx for SpillLoc \p L, creating a new one if it's not tracked.
- /// Returns None when in scenarios where a spill slot could be tracked, but
- /// we would likely run into resource limitations.
- Optional<SpillLocationNo> getOrTrackSpillLoc(SpillLoc L);
+ /// Returns std::nullopt when in scenarios where a spill slot could be
+ /// tracked, but we would likely run into resource limitations.
+ std::optional<SpillLocationNo> getOrTrackSpillLoc(SpillLoc L);
// Get LocIdx of a spill ID.
LocIdx getSpillMLoc(unsigned SpillID) {
@@ -667,10 +942,11 @@ public:
LLVM_DUMP_METHOD void dump_mloc_map();
#endif
- /// Create a DBG_VALUE based on machine location \p MLoc. Qualify it with the
+ /// Create a DBG_VALUE based on debug operands \p DbgOps. Qualify it with the
/// information in \pProperties, for variable Var. Don't insert it anywhere,
/// just return the builder for it.
- MachineInstrBuilder emitLoc(Optional<LocIdx> MLoc, const DebugVariable &Var,
+ MachineInstrBuilder emitLoc(const SmallVectorImpl<ResolvedDbgOp> &DbgOps,
+ const DebugVariable &Var,
const DbgValueProperties &Properties);
};
@@ -704,32 +980,16 @@ public:
public:
VLocTracker(const OverlapMap &O, const DIExpression *EmptyExpr)
- : OverlappingFragments(O), EmptyProperties(EmptyExpr, false) {}
+ : OverlappingFragments(O), EmptyProperties(EmptyExpr, false, false) {}
void defVar(const MachineInstr &MI, const DbgValueProperties &Properties,
- Optional<ValueIDNum> ID) {
- assert(MI.isDebugValue() || MI.isDebugRef());
- DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
- MI.getDebugLoc()->getInlinedAt());
- DbgValue Rec = (ID) ? DbgValue(*ID, Properties, DbgValue::Def)
- : DbgValue(Properties, DbgValue::Undef);
-
- // Attempt insertion; overwrite if it's already mapped.
- auto Result = Vars.insert(std::make_pair(Var, Rec));
- if (!Result.second)
- Result.first->second = Rec;
- Scopes[Var] = MI.getDebugLoc().get();
-
- considerOverlaps(Var, MI.getDebugLoc().get());
- }
-
- void defVar(const MachineInstr &MI, const MachineOperand &MO) {
- // Only DBG_VALUEs can define constant-valued variables.
- assert(MI.isDebugValue());
+ const SmallVectorImpl<DbgOpID> &DebugOps) {
+ assert(MI.isDebugValueLike());
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
- DbgValueProperties Properties(MI);
- DbgValue Rec = DbgValue(MO, Properties, DbgValue::Const);
+ DbgValue Rec = (DebugOps.size() > 0)
+ ? DbgValue(DebugOps, Properties)
+ : DbgValue(Properties, DbgValue::Undef);
// Attempt insertion; overwrite if it's already mapped.
auto Result = Vars.insert(std::make_pair(Var, Rec));
@@ -751,9 +1011,9 @@ public:
// The "empty" fragment is stored as DebugVariable::DefaultFragment, so
// that it overlaps with everything, however its cannonical representation
// in a DebugVariable is as "None".
- Optional<DIExpression::FragmentInfo> OptFragmentInfo = FragmentInfo;
+ std::optional<DIExpression::FragmentInfo> OptFragmentInfo = FragmentInfo;
if (DebugVariable::isDefaultFragment(FragmentInfo))
- OptFragmentInfo = None;
+ OptFragmentInfo = std::nullopt;
DebugVariable Overlapped(Var.getVariable(), OptFragmentInfo,
Var.getInlinedAt());
@@ -779,7 +1039,7 @@ public:
friend class ::InstrRefLDVTest;
using FragmentInfo = DIExpression::FragmentInfo;
- using OptFragmentInfo = Optional<DIExpression::FragmentInfo>;
+ using OptFragmentInfo = std::optional<DIExpression::FragmentInfo>;
// Helper while building OverlapMap, a map of all fragments seen for a given
// DILocalVariable.
@@ -872,12 +1132,12 @@ private:
uint64_t InstrNum;
/// Block where DBG_PHI occurred.
MachineBasicBlock *MBB;
- /// The value number read by the DBG_PHI -- or None if it didn't refer to
- /// a value.
- Optional<ValueIDNum> ValueRead;
- /// Register/Stack location the DBG_PHI reads -- or None if it referred to
- /// something unexpected.
- Optional<LocIdx> ReadLoc;
+ /// The value number read by the DBG_PHI -- or std::nullopt if it didn't
+ /// refer to a value.
+ std::optional<ValueIDNum> ValueRead;
+ /// Register/Stack location the DBG_PHI reads -- or std::nullopt if it
+ /// referred to something unexpected.
+ std::optional<LocIdx> ReadLoc;
operator unsigned() const { return InstrNum; }
};
@@ -896,7 +1156,10 @@ private:
/// DBG_INSTR_REFs that call resolveDbgPHIs. These variable references solve
/// a mini SSA problem caused by DBG_PHIs being cloned, this collection caches
/// the result.
- DenseMap<MachineInstr *, Optional<ValueIDNum>> SeenDbgPHIs;
+ DenseMap<std::pair<MachineInstr *, unsigned>, std::optional<ValueIDNum>>
+ SeenDbgPHIs;
+
+ DbgOpIDMap DbgOpStore;
/// True if we need to examine call instructions for stack clobbers. We
/// normally assume that they don't clobber SP, but stack probes on Windows
@@ -909,8 +1172,8 @@ private:
StringRef StackProbeSymbolName;
/// Tests whether this instruction is a spill to a stack slot.
- Optional<SpillLocationNo> isSpillInstruction(const MachineInstr &MI,
- MachineFunction *MF);
+ std::optional<SpillLocationNo> isSpillInstruction(const MachineInstr &MI,
+ MachineFunction *MF);
/// Decide if @MI is a spill instruction and return true if it is. We use 2
/// criteria to make this decision:
@@ -923,14 +1186,23 @@ private:
/// If a given instruction is identified as a spill, return the spill slot
/// and set \p Reg to the spilled register.
- Optional<SpillLocationNo> isRestoreInstruction(const MachineInstr &MI,
- MachineFunction *MF, unsigned &Reg);
+ std::optional<SpillLocationNo> isRestoreInstruction(const MachineInstr &MI,
+ MachineFunction *MF,
+ unsigned &Reg);
/// Given a spill instruction, extract the spill slot information, ensure it's
/// tracked, and return the spill number.
- Optional<SpillLocationNo>
+ std::optional<SpillLocationNo>
extractSpillBaseRegAndOffset(const MachineInstr &MI);
+ /// For an instruction reference given by \p InstNo and \p OpNo in instruction
+ /// \p MI returns the Value pointed to by that instruction reference if any
+ /// exists, otherwise returns None.
+ std::optional<ValueIDNum> getValueForInstrRef(unsigned InstNo, unsigned OpNo,
+ MachineInstr &MI,
+ const ValueTable *MLiveOuts,
+ const ValueTable *MLiveIns);
+
/// Observe a single instruction while stepping through a block.
void process(MachineInstr &MI, const ValueTable *MLiveOuts,
const ValueTable *MLiveIns);
@@ -972,17 +1244,18 @@ private:
/// forming another mini-ssa problem to solve.
/// \p Here the position of a DBG_INSTR_REF seeking a machine value number
/// \p InstrNum Debug instruction number defined by DBG_PHI instructions.
- /// \returns The machine value number at position Here, or None.
- Optional<ValueIDNum> resolveDbgPHIs(MachineFunction &MF,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns,
- MachineInstr &Here, uint64_t InstrNum);
+ /// \returns The machine value number at position Here, or std::nullopt.
+ std::optional<ValueIDNum> resolveDbgPHIs(MachineFunction &MF,
+ const ValueTable *MLiveOuts,
+ const ValueTable *MLiveIns,
+ MachineInstr &Here,
+ uint64_t InstrNum);
- Optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF,
- const ValueTable *MLiveOuts,
- const ValueTable *MLiveIns,
- MachineInstr &Here,
- uint64_t InstrNum);
+ std::optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF,
+ const ValueTable *MLiveOuts,
+ const ValueTable *MLiveIns,
+ MachineInstr &Here,
+ uint64_t InstrNum);
/// Step through the function, recording register definitions and movements
/// in an MLocTracker. Convert the observations into a per-block transfer
@@ -1086,14 +1359,21 @@ private:
SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
DbgValue &LiveIn);
- /// For the given block and live-outs feeding into it, try to find a
- /// machine location where all the variable values join together.
- /// \returns Value ID of a machine PHI if an appropriate one is available.
- Optional<ValueIDNum>
- pickVPHILoc(const MachineBasicBlock &MBB, const DebugVariable &Var,
+ /// For the given block and live-outs feeding into it, try to find
+ /// machine locations for each debug operand where all the values feeding
+ /// into that operand join together.
+ /// \returns true if a joined location was found for every value that needed
+ /// to be joined.
+ bool
+ pickVPHILoc(SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB,
const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders);
+ std::optional<ValueIDNum> pickOperandPHILoc(
+ unsigned DbgOpIdx, const MachineBasicBlock &MBB, const LiveIdxT &LiveOuts,
+ FuncValueTable &MOutLocs,
+ const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders);
+
/// Take collections of DBG_VALUE instructions stored in TTracker, and
/// install them into their output blocks. Preserves a stable order of
/// DBG_VALUEs produced (which would otherwise cause nondeterminism) through
@@ -1138,6 +1418,7 @@ public:
void dump_mloc_transfer(const MLocTransferMap &mloc_transfer) const;
bool isCalleeSaved(LocIdx L) const;
+ bool isCalleeSavedReg(Register R) const;
bool hasFoldedStackStore(const MachineInstr &MI) {
// Instruction must have a memory operand that's a stack slot, and isn't
@@ -1152,38 +1433,9 @@ public:
&& !MemOperand->getPseudoValue()->isAliased(MFI);
}
- Optional<LocIdx> findLocationForMemOperand(const MachineInstr &MI);
+ std::optional<LocIdx> findLocationForMemOperand(const MachineInstr &MI);
};
} // namespace LiveDebugValues
-namespace llvm {
-using namespace LiveDebugValues;
-
-template <> struct DenseMapInfo<LocIdx> {
- static inline LocIdx getEmptyKey() { return LocIdx::MakeIllegalLoc(); }
- static inline LocIdx getTombstoneKey() { return LocIdx::MakeTombstoneLoc(); }
-
- static unsigned getHashValue(const LocIdx &Loc) { return Loc.asU64(); }
-
- static bool isEqual(const LocIdx &A, const LocIdx &B) { return A == B; }
-};
-
-template <> struct DenseMapInfo<ValueIDNum> {
- static inline ValueIDNum getEmptyKey() { return ValueIDNum::EmptyValue; }
- static inline ValueIDNum getTombstoneKey() {
- return ValueIDNum::TombstoneValue;
- }
-
- static unsigned getHashValue(const ValueIDNum &Val) {
- return hash_value(Val.asU64());
- }
-
- static bool isEqual(const ValueIDNum &A, const ValueIDNum &B) {
- return A == B;
- }
-};
-
-} // end namespace llvm
-
#endif /* LLVM_LIB_CODEGEN_LIVEDEBUGVALUES_INSTRREFBASEDLDV_H */