namespace LiveDebugValues {
class MLocTracker;
+class DbgOpIDMap;
using namespace llvm;
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[]>;
bool IsVariadic;
};
-/// Class recording the (high level) _value_ of a variable. Identifies either
-/// the value of the variable as a ValueIDNum, or a constant MachineOperand.
+/// 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 {
+ union {
+ struct {
+ uint32_t IsConst : 1;
+ uint32_t Index : 31;
+ } 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;
+ }
+};
+
+// 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;
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,
/// 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 {
: OverlappingFragments(O), EmptyProperties(EmptyExpr, false, false) {}
void defVar(const MachineInstr &MI, const DbgValueProperties &Properties,
- Optional<ValueIDNum> ID) {
+ const SmallVectorImpl<DbgOpID> &DebugOps) {
assert(MI.isDebugValue() || MI.isDebugRef());
+ assert(DebugOps.size() <= 1);
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());
- 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));
/// the result.
DenseMap<MachineInstr *, 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
/// do.
} // 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 */
LDV->VTracker = &*VTracker;
}
+ DbgOpID addValueDbgOp(ValueIDNum V) {
+ return LDV->DbgOpStore.insert(DbgOp(V));
+ }
+ DbgOpID addConstDbgOp(MachineOperand MO) {
+ return LDV->DbgOpStore.insert(DbgOp(MO));
+ }
+
// Some routines for bouncing into LDV,
void buildMLocValueMap(FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
ValueIDNum RspPHIInBlk2(Br2Blk, 0, RspLoc);
ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
+ DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
Optional<ValueIDNum> Result;
// Simple case: join two distinct values on entry to the block.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 3.
EXPECT_TRUE(Result);
// Swap back,
std::swap(VLiveOuts[1], VLiveOuts[2]);
// Setting one of these to being a constant should prohibit merging.
- VLiveOuts[1].Kind = DbgValue::Const;
- VLiveOuts[1].MO = MachineOperand::CreateImm(0);
+ VLiveOuts[1].setDbgOpIDs(addConstDbgOp(MachineOperand::CreateImm(0)));
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
EXPECT_FALSE(Result);
// NoVals shouldn't join with anything else.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// such a scenario: first, where one incoming edge has a VPHI with no known
// value. This represents an edge where there was a PHI value that can't be
// found in the register file -- we can't subsequently find a PHI here.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
- EXPECT_EQ(VLiveOuts[2].ID, ValueIDNum::EmptyValue);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// location. Use a PHI machine-value for doing this, as VPHIs should always
// have PHI values, or they should have been eliminated.
MOutLocs[2][0] = RspPHIInBlk2;
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
- VLiveOuts[2].ID = RspPHIInBlk2; // Set location where PHI happens.
+ VLiveOuts[2].setDbgOpIDs(RspPHIInBlk2ID); // Set location where PHI happens.
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
DIExpression *NewExpr =
DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
DbgValueProperties PropsWithExpr(NewExpr, false, false);
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
}
ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
+ DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
Optional<ValueIDNum> Result;
// See that we can merge as normal on a backedge.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 1.
EXPECT_TRUE(Result);
MOutLocs[0][1] = LiveInRsp;
MOutLocs[1][0] = RaxPHIInBlk1;
MOutLocs[1][1] = RaxPHIInBlk1;
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
// Crucially, a VPHI originating in this block:
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
// Additionally, if the VPHI coming back on the loop backedge isn't from
// this block (block 1), we can't merge it.
MOutLocs[1][1] = RaxPHIInBlk1;
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
ValueIDNum RbxPHIInBlk1(Loop1Blk, 0, RbxLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID LiveInRbxID = addValueDbgOp(LiveInRbx);
+ DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
+ DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
+ DbgOpID RbxPHIInBlk1ID = addValueDbgOp(RbxPHIInBlk1);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
Optional<ValueIDNum> Result;
// See that we can merge as normal on a backedge.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 1.
EXPECT_TRUE(Result);
// If the variables value on that edge is a VPHI feeding into itself, that's
// fine.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
- VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
+ VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
// Likewise: the other backedge being a VPHI from block 1 should be accepted.
MOutLocs[2][0] = RspPHIInBlk1;
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
- ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
- ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
- ValueIDNum RspPHIInBlkBr2Blk(Br2Blk, 0, RspLoc);
- ValueIDNum RspPHIInBlkRetBlk(RetBlk, 0, RspLoc);
+ DbgOpID LiveInRspID = DbgOpID(false, 0);
+ DbgOpID LiveInRaxID = DbgOpID(false, 1);
+ DbgOpID RspPHIInBlkBr2BlkID = DbgOpID(false, 2);
+ DbgOpID RspPHIInBlkRetBlkID = DbgOpID(false, 3);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
// vlocJoin is here to propagate incoming values, and eliminate PHIs. Start
// off by propagating a value into the merging block, number 3.
DbgValue JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
bool Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result); // Output locs should have changed.
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// And if we did it a second time, leaving the live-ins as it was, then
// we should report no change.
// If the live-in variable values are different, but there's no PHI placed
// in this block, then just pick a location. It should be the first (in RPO)
// predecessor to avoid being a backedge.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
// RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor
// of this join.
- EXPECT_EQ(JoinedLoc.ID, LiveInRax);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID);
// No tests for whether vlocJoin will pass-through a variable with differing
// expressions / properties. Those can only come about due to assignments; and
EXPECT_FALSE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
// This should not have been assigned a fixed value.
- EXPECT_EQ(JoinedLoc.ID, ValueIDNum::EmptyValue);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
EXPECT_EQ(JoinedLoc.BlockNo, 3);
// Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both
// incoming edges. Re-load in and out-locs with unrelated values; they're
// irrelevant.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// Try the same PHI elimination but with one incoming value being a VPHI
// referring to the same value.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
- VLiveOuts[2].ID = LiveInRsp;
+ VLiveOuts[2].setDbgOpIDs(LiveInRspID);
JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// If the "current" live-in is a VPHI, but not a VPHI generated in the current
// block, then it's the remains of an earlier value propagation. We should
// value propagate through this merge. Even if the current incoming values
// disagree, because we've previously determined any VPHI here is redundant.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRax); // from block 2
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID); // from block 2
// The above test, but test that we will install one value-propagated VPHI
// over another.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(0, EmptyProps, DbgValue::VPHI);
JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
// We shouldn't eliminate PHIs when properties disagree.
DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_FALSE(Result);
// Even if properties disagree, we should still value-propagate if there's no
// PHI to be eliminated. The disagreeing values should work themselves out,
// seeing how we've determined no PHI is necessary.
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// Also check properties come from block 2, the first RPO predecessor to block
// three.
EXPECT_EQ(JoinedLoc.Properties, PropsWithIndirect);
DIExpression *NewExpr =
DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
DbgValueProperties PropsWithExpr(NewExpr, false, false);
- VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def);
+ VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_FALSE(Result);
+
+ // Try placing a PHI with variadic debug values. With differing input values
+ // (LiveInRsp, LiveInRax), this PHI should not be eliminated.
+ DIExpression *TwoOpExpr =
+ DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
+ 1, dwarf::DW_OP_plus});
+ DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
+ DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
+ DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
+ JoinedLoc = DbgValue(3, TwoOpProps, DbgValue::VPHI);
+ VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
+ VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
+ Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
+ // Expect no change.
+ EXPECT_FALSE(Result);
+ EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
+ // This should not have been assigned a fixed value.
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
+ EXPECT_EQ(JoinedLoc.BlockNo, 3);
}
TEST_F(InstrRefLDVTest, vlocJoinLoops) {
unsigned EntryBlk = 0, LoopBlk = 1;
- ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
- ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
- ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
+ DbgOpID LiveInRspID = DbgOpID(false, 0);
+ DbgOpID LiveInRaxID = DbgOpID(false, 1);
+ DbgOpID RspPHIInBlk1ID = DbgOpID(false, 2);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
// First: when there's no VPHI placed already, propagate the live-in value of
// the first RPO predecessor.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
- DbgValue JoinedLoc = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
+ DbgValue JoinedLoc = DbgValue(LiveInRaxID, EmptyProps);
bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// If there is a VPHI: don't elimiante it if there are disagreeing values.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_FALSE(Result);
EXPECT_EQ(JoinedLoc.BlockNo, 1);
// If we feed this VPHI back into itself though, we can eliminate it.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// Don't eliminate backedge VPHIs if the predecessors have different
// properties.
DIExpression *NewExpr =
DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
DbgValueProperties PropsWithExpr(NewExpr, false, false);
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, PropsWithExpr, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_EQ(JoinedLoc.BlockNo, 1);
// Backedges with VPHIs, but from the wrong block, shouldn't be eliminated.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
unsigned EntryBlk = 0;
- ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
- ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
- ValueIDNum LiveInRbx(EntryBlk, 0, RbxLoc);
+ DbgOpID LiveInRspID = DbgOpID(false, 0);
+ DbgOpID LiveInRaxID = DbgOpID(false, 1);
+ DbgOpID LiveInRbxID = DbgOpID(false, 2);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
AllVars.insert(Var);
// Test a normal VPHI isn't eliminated.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
- VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
- VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
+ VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
+ VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
DbgValue JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_FALSE(Result);
EXPECT_EQ(JoinedLoc.BlockNo, 1);
// Common VPHIs on backedges should merge.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
EXPECT_TRUE(Result);
EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
- EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
+ EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
// They shouldn't merge if one of their properties is different.
DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
VLiveOuts[2] = DbgValue(1, PropsWithIndirect, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
EXPECT_EQ(JoinedLoc.BlockNo, 1);
// VPHIs from different blocks should not merge.
- VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
+ VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
std::tie(MInLocs, MOutLocs) = allocValueTables(1, 2);
ValueIDNum LiveInRsp = ValueIDNum(0, 0, RspLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
MInLocs[0][0] = MOutLocs[0][0] = LiveInRsp;
DebugVariable Var(FuncVariable, None, nullptr);
// If we put an assignment in the transfer function, that should... well,
// do nothing, because we don't store the live-outs.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output.size(), 0ul);
ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
ValueIDNum RspPHIInBlk3 = ValueIDNum(RetBlk, 0, RspLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
FuncValueTable MInLocs, MOutLocs;
std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
// An assignment in the end block should also not affect other blocks; or
// produce any live-ins.
- VLocs[3].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[3].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
// Assignments in either of the side-of-diamond blocks should also not be
// propagated anywhere.
VLocs[3].Vars.clear();
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
VLocs[2].Vars.clear();
ClearOutputs();
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
// However: putting an assignment in the first block should propagate variable
// values through to all other blocks, as it dominates.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
ASSERT_EQ(Output[3].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
// should still be propagated, as buildVLocValueMap shouldn't care about
// what's in the registers (except for PHIs).
// values through to all other blocks, as it dominates.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
ASSERT_EQ(Output[3].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
// We should get a live-in to the merging block, if there are two assigns of
// the same value in either side of the diamond.
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
EXPECT_EQ(Output[2].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[1].Vars.clear();
VLocs[2].Vars.clear();
// If we assign a value in the entry block, then 'undef' on a branch, we
// shouldn't have a live-in in the merge block.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[3].size(), 0ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// Having different values joining into the merge block should mean we have
// no live-in in that block. Block ones LiveInRax value doesn't appear as a
// live-in anywhere, it's block internal.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[3].size(), 0ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// But on the other hand, if there's a location in the register file where
// those two values can be joined, do so.
MOutLocs[1][0] = LiveInRax;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
ASSERT_EQ(Output[3].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, RspPHIInBlk3);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspPHIInBlk3ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
ValueIDNum RspPHIInBlk1 = ValueIDNum(LoopBlk, 0, RspLoc);
ValueIDNum RspDefInBlk1 = ValueIDNum(LoopBlk, 1, RspLoc);
ValueIDNum RaxPHIInBlk1 = ValueIDNum(LoopBlk, 0, RaxLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
+ DbgOpID RspDefInBlk1ID = addValueDbgOp(RspDefInBlk1);
+ DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
FuncValueTable MInLocs, MOutLocs;
std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
Output.resize(3);
// Easy starter: a dominating assign should propagate to all blocks.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// Put an undef assignment in the loop. Should get no live-in value.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
VLocs[1].Vars.clear();
// Assignment of the same value should naturally join.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// Assignment of different values shouldn't join with no machine PHI vals.
// Will be live-in to exit block as it's dominated.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
EXPECT_EQ(Output[1].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// with unrelated assign in loop block again.
MInLocs[1][0] = RspPHIInBlk1;
MOutLocs[1][0] = RspDefInBlk1;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
EXPECT_EQ(Output[1].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// find the appropriate PHI.
MInLocs[1][0] = RspPHIInBlk1;
MOutLocs[1][0] = RspDefInBlk1;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
MOutLocs[1][0] = LiveInRsp;
MInLocs[1][1] = RaxPHIInBlk1;
MOutLocs[1][1] = RspDefInBlk1;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, RaxPHIInBlk1);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RaxPHIInBlk1ID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
MOutLocs[1][0] = RspDefInBlk1;
MInLocs[1][1] = RaxPHIInBlk1;
MOutLocs[1][1] = RspDefInBlk1;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
// Today, the first register is picked.
- EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
MOutLocs[1][0] = RspPHIInBlk1;
MInLocs[1][1] = LiveInRax;
MOutLocs[1][1] = LiveInRax;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(RspPHIInBlk1, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(RspPHIInBlk1ID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, RspPHIInBlk1);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk1ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// because there's a def in in.
MInLocs[1][0] = LiveInRsp;
MOutLocs[1][0] = LiveInRsp;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[1].size(), 1ul);
ASSERT_EQ(Output[2].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
ValueIDNum RspPHIInBlk1 = ValueIDNum(Loop1Blk, 0, RspLoc);
ValueIDNum RspPHIInBlk2 = ValueIDNum(Loop2Blk, 0, RspLoc);
ValueIDNum RspDefInBlk2 = ValueIDNum(Loop2Blk, 1, RspLoc);
+ DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
+ DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
+ DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
+ DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
+ DbgOpID RspDefInBlk2ID = addValueDbgOp(RspDefInBlk2);
FuncValueTable MInLocs, MOutLocs;
std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
Output.resize(5);
// A dominating assign should propagate to all blocks.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
// Test that an assign in the inner loop causes unresolved PHIs at the heads
// of both loops, and no output location. Dominated blocks do get values.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[2].Vars.clear();
// Same test, but with no assignment in block 0. We should still get values
// in dominated blocks.
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[2].Vars.clear();
// Similarly, assignments in the outer loop gives location to dominated
// blocks, but no PHI locations are found at the outer loop head.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[3].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[3].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
EXPECT_EQ(Output[3].size(), 0ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[3].Vars.clear();
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// With an assignment of the same value in the inner loop, we should work out
// that all PHIs can be eliminated and the same value is live-through the
// whole function.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRsp);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[2].Vars.clear();
// one. Even though RspPHIInBlk2 isn't available later in the function, we
// should still produce a live-in value. The fact it's unavailable is a
// different concern.
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[2].Vars.clear();
MOutLocs[2][0] = RspDefInBlk2;
MInLocs[3][0] = RspDefInBlk2;
MOutLocs[3][0] = RspDefInBlk2;
- VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
- VLocs[2].Vars.insert({Var, DbgValue(RspDefInBlk2, EmptyProps, DbgValue::Def)});
+ VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
+ VLocs[2].Vars.insert({Var, DbgValue(RspDefInBlk2ID, EmptyProps)});
buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
MOutLocs, MInLocs, VLocs);
EXPECT_EQ(Output[0].size(), 0ul);
ASSERT_EQ(Output[3].size(), 1ul);
ASSERT_EQ(Output[4].size(), 1ul);
EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
+ EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[2][0].second.ID, RspPHIInBlk2);
+ EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk2ID);
EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[3][0].second.ID, RspDefInBlk2);
+ EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspDefInBlk2ID);
EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
- EXPECT_EQ(Output[4][0].second.ID, RspDefInBlk2);
+ EXPECT_EQ(Output[4][0].second.getDbgOpID(0), RspDefInBlk2ID);
ClearOutputs();
VLocs[0].Vars.clear();
VLocs[2].Vars.clear();