[DebugInfo] Let InstrRefBasedLDV handle joins for lists of debug ops

In preparation for adding support for DBG_VALUE_LIST instructions in
InstrRefLDV, this patch updates the logic for joining variables at block
joins to support joining variables that use multiple debug operands.
This is one of the more meaty "logical" changes, although the line count
isn't too high - this changes pickVPHILoc to find a valid joined
location for every operand, with part of the function being split off
into pickValuePHILoc which finds a location for a single operand.

Differential Revision: https://reviews.llvm.org/D128180
This commit is contained in:
Stephen Tozer 2022-06-18 01:09:13 +01:00
parent 5d794552bc
commit 53fd5af689
3 changed files with 278 additions and 89 deletions

View File

@ -2419,33 +2419,104 @@ void InstrRefBasedLDV::BlockPHIPlacement(
IDF.calculate(PHIBlocks);
}
Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
const MachineBasicBlock &MBB, const DebugVariable &Var,
bool InstrRefBasedLDV::pickVPHILoc(
SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB,
const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
// Collect a set of locations from predecessor where its live-out value can
// be found.
SmallVector<SmallVector<LocIdx, 4>, 8> Locs;
SmallVector<const DbgValueProperties *, 4> Properties;
unsigned NumLocs = MTracker->getNumLocs();
// No predecessors means no PHIs.
if (BlockOrders.empty())
return None;
return false;
for (const auto *p : BlockOrders) {
unsigned ThisBBNum = p->getNumber();
// All the location operands that do not already agree need to be joined,
// track the indices of each such location operand here.
SmallDenseSet<unsigned> LocOpsToJoin;
auto FirstValueIt = LiveOuts.find(BlockOrders[0]);
if (FirstValueIt == LiveOuts.end())
return false;
const DbgValue &FirstValue = *FirstValueIt->second;
for (const auto p : BlockOrders) {
auto OutValIt = LiveOuts.find(p);
if (OutValIt == LiveOuts.end())
// If we have a predecessor not in scope, we'll never find a PHI position.
return None;
return false;
const DbgValue &OutVal = *OutValIt->second;
if (OutVal.getDbgOpID(0).isConst() || OutVal.Kind == DbgValue::NoVal)
// Consts and no-values cannot have locations we can join on.
return None;
// No-values cannot have locations we can join on.
if (OutVal.Kind == DbgValue::NoVal)
return false;
Properties.push_back(&OutVal.Properties);
// For unjoined VPHIs where we don't know the location, we definitely
// can't find a join loc unless the VPHI is a backedge.
if (OutVal.isUnjoinedPHI() && OutVal.BlockNo != MBB.getNumber())
return false;
if (FirstValue.Properties != OutVal.Properties)
return false;
for (unsigned Idx = 0; Idx < FirstValue.getLocationOpCount(); ++Idx) {
// An unjoined PHI has no defined locations, and so a shared location must
// be found for every operand.
if (OutVal.isUnjoinedPHI()) {
LocOpsToJoin.insert(Idx);
continue;
}
DbgOpID FirstValOp = FirstValue.getDbgOpID(Idx);
DbgOpID OutValOp = OutVal.getDbgOpID(Idx);
if (FirstValOp != OutValOp) {
// We can never join constant ops - the ops must either both be equal
// constant ops or non-const ops.
if (FirstValOp.isConst() || OutValOp.isConst())
return false;
else
LocOpsToJoin.insert(Idx);
}
}
}
SmallVector<DbgOpID> NewDbgOps;
for (unsigned Idx = 0; Idx < FirstValue.getLocationOpCount(); ++Idx) {
// If this op doesn't need to be joined because the values agree, use that
// already-agreed value.
if (!LocOpsToJoin.contains(Idx)) {
NewDbgOps.push_back(FirstValue.getDbgOpID(Idx));
continue;
}
Optional<ValueIDNum> JoinedOpLoc =
pickOperandPHILoc(Idx, MBB, LiveOuts, MOutLocs, BlockOrders);
if (!JoinedOpLoc)
return false;
NewDbgOps.push_back(DbgOpStore.insert(*JoinedOpLoc));
}
OutValues.append(NewDbgOps);
return true;
}
Optional<ValueIDNum> InstrRefBasedLDV::pickOperandPHILoc(
unsigned DbgOpIdx, const MachineBasicBlock &MBB, const LiveIdxT &LiveOuts,
FuncValueTable &MOutLocs,
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
// Collect a set of locations from predecessor where its live-out value can
// be found.
SmallVector<SmallVector<LocIdx, 4>, 8> Locs;
unsigned NumLocs = MTracker->getNumLocs();
for (const auto p : BlockOrders) {
unsigned ThisBBNum = p->getNumber();
auto OutValIt = LiveOuts.find(p);
assert(OutValIt != LiveOuts.end());
const DbgValue &OutVal = *OutValIt->second;
DbgOpID OutValOpID = OutVal.getDbgOpID(DbgOpIdx);
DbgOp OutValOp = DbgOpStore.find(OutValOpID);
assert(!OutValOp.IsConst);
// Create new empty vector of locations.
Locs.resize(Locs.size() + 1);
@ -2454,8 +2525,8 @@ Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
// present. Do the same for VPHIs where we know the VPHI value.
if (OutVal.Kind == DbgValue::Def ||
(OutVal.Kind == DbgValue::VPHI && OutVal.BlockNo != MBB.getNumber() &&
!OutVal.getDbgOpID(0).isUndef())) {
ValueIDNum ValToLookFor = DbgOpStore.find(OutVal.getDbgOpID(0)).ID;
!OutValOp.isUndef())) {
ValueIDNum ValToLookFor = OutValOp.ID;
// Search the live-outs of the predecessor for the specified value.
for (unsigned int I = 0; I < NumLocs; ++I) {
if (MOutLocs[ThisBBNum][I] == ValToLookFor)
@ -2463,11 +2534,6 @@ Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
}
} else {
assert(OutVal.Kind == DbgValue::VPHI);
// For VPHIs where we don't know the location, we definitely can't find
// a join loc.
if (OutVal.BlockNo != MBB.getNumber())
return None;
// Otherwise: this is a VPHI on a backedge feeding back into itself, i.e.
// a value that's live-through the whole loop. (It has to be a backedge,
// because a block can't dominate itself). We can accept as a PHI location
@ -2481,17 +2547,9 @@ Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
}
}
}
// We should have found locations for all predecessors, or returned.
assert(Locs.size() == BlockOrders.size());
// Check that all properties are the same. We can't pick a location if they're
// not.
const DbgValueProperties *Properties0 = Properties[0];
for (const auto *Prop : Properties)
if (*Prop != *Properties0)
return None;
// Starting with the first set of locations, take the intersection with
// subsequent sets.
SmallVector<LocIdx, 4> CandidateLocs = Locs[0];
@ -2582,7 +2640,7 @@ bool InstrRefBasedLDV::vlocJoin(
// Scan for variable values that can never be resolved: if they have
// different DIExpressions, different indirectness, or are mixed constants /
// non-constants.
for (auto &V : Values) {
for (const auto &V : Values) {
if (V.second->Properties != FirstVal.Properties)
return false;
if (V.second->Kind == DbgValue::NoVal)
@ -2847,13 +2905,13 @@ void InstrRefBasedLDV::buildVLocValueMap(
// eliminated and transitions from VPHI-with-location to
// live-through-value. As a result, the selected location of any VPHI
// might change, so we need to re-compute it on each iteration.
Optional<ValueIDNum> ValueNum =
pickVPHILoc(*MBB, Var, LiveOutIdx, MOutLocs, Preds);
SmallVector<DbgOpID> JoinedOps;
if (ValueNum) {
DbgOpID ValueID = DbgOpStore.insert(*ValueNum);
InLocsChanged |= LiveIn->getDbgOpID(0) != ValueID;
LiveIn->setDbgOpIDs(ValueID);
if (pickVPHILoc(JoinedOps, *MBB, LiveOutIdx, MOutLocs, Preds)) {
bool NewLocPicked = !equal(LiveIn->getDbgOpIDs(), JoinedOps);
InLocsChanged |= NewLocPicked;
if (NewLocPicked)
LiveIn->setDbgOpIDs(JoinedOps);
}
}

View File

@ -1342,14 +1342,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);
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

View File

@ -198,11 +198,12 @@ public:
LDV->placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
}
Optional<ValueIDNum>
pickVPHILoc(const MachineBasicBlock &MBB, const DebugVariable &Var,
const InstrRefBasedLDV::LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
bool
pickVPHILoc(SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB,
const InstrRefBasedLDV::LiveIdxT &LiveOuts,
FuncValueTable &MOutLocs,
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
return LDV->pickVPHILoc(MBB, Var, LiveOuts, MOutLocs, BlockOrders);
return LDV->pickVPHILoc(OutValues, MBB, LiveOuts, MOutLocs, BlockOrders);
}
bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs,
@ -1805,13 +1806,20 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
ValueIDNum RspPHIInBlk2(Br2Blk, 0, RspLoc);
ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
ValueIDNum RaxPHIInBlk3(RetBlk, 0, RaxLoc);
DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
addValueDbgOp(RspPHIInBlk3);
DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
DbgOpID RaxPHIInBlk3ID = addValueDbgOp(RaxPHIInBlk3);
DbgOpID ConstZeroID = addConstDbgOp(MachineOperand::CreateImm(0));
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
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);
SmallVector<DbgValue, 32> VLiveOuts;
VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
@ -1828,42 +1836,51 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
MOutLocs[1][0] = LiveInRsp;
MOutLocs[2][0] = LiveInRax;
Optional<ValueIDNum> Result;
bool Result;
SmallVector<DbgOpID> OutValues;
// Simple case: join two distinct values on entry to the block.
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 3.
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk3);
EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
}
// If the incoming values are swapped between blocks, we should not
// successfully join. The CFG merge would select the right values, but in
// the wrong conditions.
std::swap(VLiveOuts[1], VLiveOuts[2]);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Swap back,
std::swap(VLiveOuts[1], VLiveOuts[2]);
// Setting one of these to being a constant should prohibit merging.
VLiveOuts[1].setDbgOpIDs(addConstDbgOp(MachineOperand::CreateImm(0)));
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
VLiveOuts[1].setDbgOpIDs(ConstZeroID);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Seeing both to being a constant -> still prohibit, it shouldn't become
// a value in the register file anywhere.
// Setting both to being identical constants should result in a valid join
// with a constant value.
VLiveOuts[2] = VLiveOuts[1];
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(OutValues[0], ConstZeroID);
}
// NoVals shouldn't join with anything else.
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// We might merge in another VPHI in such a join. Present pickVPHILoc with
@ -1872,7 +1889,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
// found in the register file -- we can't subsequently find a PHI here.
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// However, if we know the value of the incoming VPHI, we can search for its
@ -1882,31 +1900,80 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
VLiveOuts[2].setDbgOpIDs(RspPHIInBlk2ID); // Set location where PHI happens.
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk3);
EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
}
// If that value isn't available from that block, don't join.
MOutLocs[2][0] = LiveInRsp;
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Check that we don't pick values when the properties disagree, for example
// different indirectness or DIExpression.
MOutLocs[2][0] = LiveInRax;
DIExpression *NewExpr =
DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
DbgValueProperties PropsWithExpr(NewExpr, false, false);
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// When we have operands with values [A, B] and [B, A], we do not necessarily
// pick identical join locations for each operand if the locations of those
// values differ between incoming basic blocks.
MOutLocs[1][0] = LiveInRsp;
MOutLocs[2][0] = LiveInRax;
MOutLocs[1][1] = LiveInRax;
MOutLocs[2][1] = LiveInRsp;
DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
// Should have picked PHIs in block 3.
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
EXPECT_EQ(OutValues[1], RaxPHIInBlk3ID);
}
// When joining identical constants for an operand, we should simply keep that
// constant while joining the remaining operands as normal.
DbgOpID Locs2[] = {LiveInRspID, ConstZeroID};
DbgOpID Locs3[] = {LiveInRaxID, ConstZeroID};
VLiveOuts[1] = DbgValue(Locs2, TwoOpProps);
VLiveOuts[2] = DbgValue(Locs3, TwoOpProps);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
EXPECT_EQ(OutValues[1], ConstZeroID);
}
// If the debug values have different constants for the same operand, they
// cannot be joined.
DbgOpID ConstOneID = addConstDbgOp(MachineOperand::CreateImm(1));
DbgOpID Locs4[] = {LiveInRaxID, ConstOneID};
VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
VLiveOuts[2] = DbgValue(Locs2, TwoOpProps);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
}
@ -1938,11 +2005,15 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
addValueDbgOp(RspPHIInBlk1);
addValueDbgOp(RaxPHIInBlk1);
DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
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);
SmallVector<DbgValue, 32> VLiveOuts;
VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
@ -1958,21 +2029,24 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
MOutLocs[0][0] = LiveInRsp;
MOutLocs[1][0] = LiveInRax;
Optional<ValueIDNum> Result;
bool Result;
SmallVector<DbgOpID> OutValues;
// See that we can merge as normal on a backedge.
VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 1.
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk1);
EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
}
// And that, if the desired values aren't available, we don't merge.
MOutLocs[1][0] = LiveInRsp;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Test the backedge behaviour: PHIs that feed back into themselves can
@ -1986,16 +2060,35 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
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);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RaxPHIInBlk1);
EXPECT_EQ(OutValues[0], RaxPHIInBlk1ID);
}
// Test that we can also find a location when joining a backedge PHI with
// a variadic debug value.
MOutLocs[1][0] = RspPHIInBlk1;
MOutLocs[0][1] = LiveInRax;
DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
VLiveOuts[0] = DbgValue(Locs0, TwoOpProps);
// Crucially, a VPHI originating in this block:
VLiveOuts[1] = DbgValue(1, TwoOpProps, DbgValue::VPHI);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
EXPECT_EQ(OutValues[1], RaxPHIInBlk1ID);
}
// Merging should not be permitted if there's a usable PHI on the backedge,
// but it's in the wrong place. (Overwrite $rax).
MOutLocs[1][1] = LiveInRax;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Additionally, if the VPHI coming back on the loop backedge isn't from
@ -2003,7 +2096,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
MOutLocs[1][1] = RaxPHIInBlk1;
VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
}
@ -2045,9 +2139,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
DbgOpID LiveInRbxID = addValueDbgOp(LiveInRbx);
addValueDbgOp(RspPHIInBlk1);
DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
addValueDbgOp(RaxPHIInBlk1);
addValueDbgOp(RbxPHIInBlk1);
DbgOpID RbxPHIInBlk1ID = addValueDbgOp(RbxPHIInBlk1);
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
@ -2071,24 +2165,27 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
MOutLocs[1][0] = LiveInRax;
MOutLocs[2][0] = LiveInRbx;
Optional<ValueIDNum> Result;
bool Result;
SmallVector<DbgOpID> OutValues;
// See that we can merge as normal on a backedge.
VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
// Should have picked a PHI in $rsp in block 1.
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk1);
EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
}
// Check too that permuting the live-out locations prevents merging
MOutLocs[0][0] = LiveInRax;
MOutLocs[1][0] = LiveInRbx;
MOutLocs[2][0] = LiveInRsp;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
MOutLocs[0][0] = LiveInRsp;
@ -2098,7 +2195,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
// Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
// wants LiveInRax).
MOutLocs[1][0] = RspPHIInBlk1;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// If the variables value on that edge is a VPHI feeding into itself, that's
@ -2106,10 +2204,11 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk1);
EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
}
// Likewise: the other backedge being a VPHI from block 1 should be accepted.
@ -2117,17 +2216,19 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
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);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RspPHIInBlk1);
EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
}
// Here's where it becomes tricky: we should not merge if there are two
// _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
// and rax for example. We can only pick one location as the live-in.
MOutLocs[2][0] = RaxPHIInBlk1;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// The above test sources correct machine-PHI-value from two places. Now
@ -2138,7 +2239,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
MOutLocs[1][0] = RspPHIInBlk1;
MOutLocs[2][0] = LiveInRsp;
MOutLocs[2][1] = RspPHIInBlk1;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_FALSE(Result);
// Scatter various PHI values across the available locations. Only rbx (loc 2)
@ -2151,10 +2253,11 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
MOutLocs[2][0] = LiveInRsp;
MOutLocs[2][1] = RspPHIInBlk1;
MOutLocs[2][2] = RbxPHIInBlk1;
Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
OutValues.clear();
Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
EXPECT_TRUE(Result);
if (Result) {
EXPECT_EQ(*Result, RbxPHIInBlk1);
EXPECT_EQ(OutValues[0], RbxPHIInBlk1ID);
}
}
@ -2835,6 +2938,10 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
DebugVariable Var(FuncVariable, None, nullptr);
DbgValueProperties EmptyProps(EmptyExpr, false, false);
DIExpression *TwoOpExpr =
DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
1, dwarf::DW_OP_plus});
DbgValueProperties VariadicProps(TwoOpExpr, false, true);
SmallSet<DebugVariable, 4> AllVars;
AllVars.insert(Var);
@ -2876,6 +2983,23 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
VLocs[0].Vars.clear();
VLocs[1].Vars.clear();
// A variadic assignment should behave the same.
DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
VLocs[0].Vars.insert({Var, DbgValue(Locs0, VariadicProps)});
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.getDbgOpID(0), LiveInRspID);
EXPECT_EQ(Output[1][0].second.getDbgOpID(1), LiveInRaxID);
EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
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(LiveInRspID, EmptyProps)});
VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});