Skip to content

Commit 8bbe0d0

Browse files
authored
[VPlan] Verify dominance for incoming values of phi-like recipes. (#124838)
Update the verifier to verify dominance for incoming values for phi-like recipes. The defining recipe must dominate the incoming block for the incoming value. Builds on top of #138472 to retrieve incoming values & corresponding blocks for phi-like recipes. PR: #124838
1 parent 767a203 commit 8bbe0d0

File tree

3 files changed

+118
-11
lines changed

3 files changed

+118
-11
lines changed

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,9 @@ class VPPhiAccessors {
11351135
const VPBasicBlock *getIncomingBlock(unsigned Idx) const;
11361136

11371137
/// Returns the number of incoming values, also number of incoming blocks.
1138-
unsigned getNumIncoming() const { return getAsRecipe()->getNumOperands(); }
1138+
virtual unsigned getNumIncoming() const {
1139+
return getAsRecipe()->getNumOperands();
1140+
}
11391141

11401142
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
11411143
/// Print the recipe.
@@ -1234,7 +1236,7 @@ class VPIRInstruction : public VPRecipeBase {
12341236
/// cast/dyn_cast/isa and execute() implementation. A single VPValue operand is
12351237
/// allowed, and it is used to add a new incoming value for the single
12361238
/// predecessor VPBB.
1237-
struct VPIRPhi : public VPIRInstruction {
1239+
struct VPIRPhi : public VPIRInstruction, public VPPhiAccessors {
12381240
VPIRPhi(PHINode &PN) : VPIRInstruction(PN) {}
12391241

12401242
static inline bool classof(const VPRecipeBase *U) {
@@ -1251,6 +1253,9 @@ struct VPIRPhi : public VPIRInstruction {
12511253
void print(raw_ostream &O, const Twine &Indent,
12521254
VPSlotTracker &SlotTracker) const override;
12531255
#endif
1256+
1257+
protected:
1258+
const VPRecipeBase *getAsRecipe() const override { return this; }
12541259
};
12551260

12561261
/// Helper to manage IR metadata for recipes. It filters out metadata that
@@ -1785,13 +1790,15 @@ class VPVectorPointerRecipe : public VPRecipeWithIRFlags,
17851790
/// * VPWidenPointerInductionRecipe: Generate vector and scalar values for a
17861791
/// pointer induction. Produces either a vector PHI per-part or scalar values
17871792
/// per-lane based on the canonical induction.
1788-
class VPHeaderPHIRecipe : public VPSingleDefRecipe {
1793+
class VPHeaderPHIRecipe : public VPSingleDefRecipe, public VPPhiAccessors {
17891794
protected:
17901795
VPHeaderPHIRecipe(unsigned char VPDefID, Instruction *UnderlyingInstr,
17911796
VPValue *Start, DebugLoc DL = {})
17921797
: VPSingleDefRecipe(VPDefID, ArrayRef<VPValue *>({Start}), UnderlyingInstr, DL) {
17931798
}
17941799

1800+
const VPRecipeBase *getAsRecipe() const override { return this; }
1801+
17951802
public:
17961803
~VPHeaderPHIRecipe() override = default;
17971804

@@ -1980,6 +1987,11 @@ class VPWidenIntOrFpInductionRecipe : public VPWidenInductionRecipe {
19801987
return isUnrolled() ? getOperand(getNumOperands() - 2) : nullptr;
19811988
}
19821989

1990+
/// Returns the number of incoming values, also number of incoming blocks.
1991+
/// Note that at the moment, VPWidenIntOrFpInductionRecipes only have a single
1992+
/// incoming value, its start value.
1993+
unsigned getNumIncoming() const override { return 1; }
1994+
19831995
/// Returns the first defined value as TruncInst, if it is one or nullptr
19841996
/// otherwise.
19851997
TruncInst *getTruncInst() { return Trunc; }
@@ -3283,6 +3295,46 @@ class VPScalarIVStepsRecipe : public VPRecipeWithIRFlags,
32833295
}
32843296
};
32853297

3298+
/// Casting from VPRecipeBase -> VPPhiAccessors is supported for all recipe
3299+
/// types implementing VPPhiAccessors. Used by isa<> & co.
3300+
template <> struct CastIsPossible<VPPhiAccessors, const VPRecipeBase *> {
3301+
static inline bool isPossible(const VPRecipeBase *f) {
3302+
// TODO: include VPPredInstPHIRecipe too, once it implements VPPhiAccessors.
3303+
return isa<VPIRPhi, VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPhi>(f);
3304+
}
3305+
};
3306+
/// Support casting from VPRecipeBase -> VPPhiAccessors, by down-casting to the
3307+
/// recipe types implementing VPPhiAccessors. Used by cast<>, dyn_cast<> & co.
3308+
template <>
3309+
struct CastInfo<VPPhiAccessors, const VPRecipeBase *>
3310+
: public CastIsPossible<VPPhiAccessors, const VPRecipeBase *> {
3311+
3312+
using Self = CastInfo<VPPhiAccessors, const VPRecipeBase *>;
3313+
3314+
/// doCast is used by cast<>.
3315+
static inline VPPhiAccessors *doCast(const VPRecipeBase *R) {
3316+
return const_cast<VPPhiAccessors *>([R]() -> const VPPhiAccessors * {
3317+
switch (R->getVPDefID()) {
3318+
case VPDef::VPInstructionSC:
3319+
return cast<VPPhi>(R);
3320+
case VPDef::VPIRInstructionSC:
3321+
return cast<VPIRPhi>(R);
3322+
case VPDef::VPWidenPHISC:
3323+
return cast<VPWidenPHIRecipe>(R);
3324+
default:
3325+
return cast<VPHeaderPHIRecipe>(R);
3326+
}
3327+
}());
3328+
}
3329+
3330+
/// doCastIfPossible is used by dyn_cast<>.
3331+
static inline VPPhiAccessors *doCastIfPossible(const VPRecipeBase *f) {
3332+
if (!Self::isPossible(f))
3333+
return nullptr;
3334+
return doCast(f);
3335+
}
3336+
};
3337+
32863338
/// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It
32873339
/// holds a sequence of zero or more VPRecipe's each representing a sequence of
32883340
/// output IR instructions. All PHI-like recipes must come before any non-PHI recipes.

llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
192192
if (!verifyPhiRecipes(VPBB))
193193
return false;
194194

195-
// Verify that defs in VPBB dominate all their uses. The current
196-
// implementation is still incomplete.
195+
// Verify that defs in VPBB dominate all their uses.
197196
DenseMap<const VPRecipeBase *, unsigned> RecipeNumbering;
198197
unsigned Cnt = 0;
199198
for (const VPRecipeBase &R : *VPBB)
@@ -220,12 +219,31 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
220219

221220
for (const VPUser *U : V->users()) {
222221
auto *UI = cast<VPRecipeBase>(U);
223-
// TODO: check dominance of incoming values for phis properly.
224-
if (!UI ||
225-
isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe,
226-
VPIRPhi>(UI) ||
227-
(isa<VPInstruction>(UI) &&
228-
cast<VPInstruction>(UI)->getOpcode() == Instruction::PHI))
222+
if (auto *Phi = dyn_cast<VPPhiAccessors>(UI)) {
223+
for (unsigned Idx = 0; Idx != Phi->getNumIncoming(); ++Idx) {
224+
VPValue *IncomingVPV = Phi->getIncomingValue(Idx);
225+
if (IncomingVPV != V)
226+
continue;
227+
228+
const VPBasicBlock *IncomingVPBB = Phi->getIncomingBlock(Idx);
229+
if (VPDT.dominates(VPBB, IncomingVPBB))
230+
continue;
231+
232+
errs() << "Incoming def at index " << Idx
233+
<< " does not dominate incoming block!\n";
234+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
235+
VPSlotTracker Tracker(VPBB->getPlan());
236+
IncomingVPV->getDefiningRecipe()->print(errs(), " ", Tracker);
237+
errs() << "\n does not dominate " << IncomingVPBB->getName()
238+
<< " for\n";
239+
UI->print(errs(), " ", Tracker);
240+
#endif
241+
return false;
242+
}
243+
continue;
244+
}
245+
// TODO: Also verify VPPredInstPHIRecipe.
246+
if (isa<VPPredInstPHIRecipe>(UI))
229247
continue;
230248

231249
// If the user is in the same block, check it comes after R in the

llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,43 @@ TEST_F(VPVerifierTest, VPBlendUseBeforeDefDifferentBB) {
143143
delete Phi;
144144
}
145145

146+
TEST_F(VPVerifierTest, VPPhiIncomingValueDoesntDominateIncomingBlock) {
147+
VPlan &Plan = getPlan();
148+
IntegerType *Int32 = IntegerType::get(C, 32);
149+
VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 0));
150+
151+
VPBasicBlock *VPBB1 = Plan.getEntry();
152+
VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("");
153+
VPBasicBlock *VPBB3 = Plan.createVPBasicBlock("");
154+
155+
VPInstruction *DefI = new VPInstruction(Instruction::Add, {Zero});
156+
VPPhi *Phi = new VPPhi({DefI}, {});
157+
VPBB2->appendRecipe(Phi);
158+
VPBB2->appendRecipe(DefI);
159+
auto *CanIV = new VPCanonicalIVPHIRecipe(Zero, {});
160+
VPBB3->appendRecipe(CanIV);
161+
162+
VPRegionBlock *R1 = Plan.createVPRegionBlock(VPBB3, VPBB3, "R1");
163+
VPBlockUtils::connectBlocks(VPBB1, VPBB2);
164+
VPBlockUtils::connectBlocks(VPBB2, R1);
165+
#if GTEST_HAS_STREAM_REDIRECTION
166+
::testing::internal::CaptureStderr();
167+
#endif
168+
EXPECT_FALSE(verifyVPlanIsValid(Plan));
169+
#if GTEST_HAS_STREAM_REDIRECTION
170+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
171+
EXPECT_STREQ("Incoming def at index 0 does not dominate incoming block!\n"
172+
" EMIT vp<%2> = add ir<0>\n"
173+
" does not dominate preheader for\n"
174+
" EMIT vp<%1> = phi [ vp<%2>, preheader ]",
175+
::testing::internal::GetCapturedStderr().c_str());
176+
#else
177+
EXPECT_STREQ("Use before def!\n",
178+
::testing::internal::GetCapturedStderr().c_str());
179+
#endif
180+
#endif
181+
}
182+
146183
TEST_F(VPVerifierTest, DuplicateSuccessorsOutsideRegion) {
147184
VPlan &Plan = getPlan();
148185
VPValue *Zero = Plan.getOrAddLiveIn(ConstantInt::get(Type::getInt32Ty(C), 0));

0 commit comments

Comments
 (0)