Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[VPlan] Verify dominance for incoming values of phi-like recipes. #124838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
May 15, 2025

Conversation

fhahn
Copy link
Contributor

@fhahn fhahn commented Jan 28, 2025

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.

@llvmbot
Copy link
Member

llvmbot commented Jan 28, 2025

@llvm/pr-subscribers-vectorizers

Author: Florian Hahn (fhahn)

Changes

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.

There are 4 different cases to consider when retrieving the incoming block:

  • VPIRInstructions wrapping phis: the incoming block from the blocks predecessors has the same index as the incoming value operand.
  • VPHeaderPhiRecipes, VPWidenPhi used in header: there's no predecessors; if the incoming value is the start value use the predecessor of the containing region, otherwise the exiting block of the region
  • 1 predecessor: Must be a VPWidenPHI used as LCSSA phi; use the predecessor
  • 2 predecessors: must be a VPPredInstPhiRecipe, use the second predecessor.

Full diff: https://github.com/llvm/llvm-project/pull/124838.diff

1 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp (+53-5)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
index 0f151c897d938e..0948452e8d19cf 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
@@ -175,6 +175,11 @@ bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
   });
 }
 
+/// Return true if \p R is a VPIRInstruction wrapping a phi.
+static bool isVPIRInstructionPhi(const VPRecipeBase &R) {
+  auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
+  return VPIRI && isa<PHINode>(VPIRI->getInstruction());
+}
 bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
   if (!verifyPhiRecipes(VPBB))
     return false;
@@ -207,14 +212,57 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
 
       for (const VPUser *U : V->users()) {
         auto *UI = cast<VPRecipeBase>(U);
-        // TODO: check dominance of incoming values for phis properly.
-        if (!UI ||
-            isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI))
+        const VPBlockBase *UserVPBB = UI->getParent();
+
+        // Verify incoming values of VPIRInstructions wrapping phis. V most
+        // dominate the end of the incoming block. The operand index of the
+        // incoming value matches the predecessor block index of the
+        // corresponding incoming block.
+        if (isVPIRInstructionPhi(*UI)) {
+          for (const auto &[Idx, Op] : enumerate(UI->operands())) {
+            if (V != Op)
+              continue;
+            const VPBlockBase *Incoming = UserVPBB->getPredecessors()[Idx];
+            if (Incoming != VPBB && !VPDT.dominates(VPBB, Incoming)) {
+              errs() << "Use before def!\n";
+              return false;
+            }
+          }
           continue;
+        }
+        // Verify incoming value of various phi-like recipes.
+        if (isa<VPWidenPHIRecipe, VPHeaderPHIRecipe, VPPredInstPHIRecipe>(UI)) {
+          const VPBlockBase *Incoming = nullptr;
+          // Get the incoming block based on the number of predecessors.
+          if (UserVPBB->getNumPredecessors() == 0) {
+            assert((isa<VPWidenPHIRecipe>(UI) || isa<VPHeaderPHIRecipe>(UI)) &&
+                   "Unexpected recipe with 0 predecessors");
+            const VPRegionBlock *UserRegion = UserVPBB->getParent();
+            Incoming = V == UI->getOperand(0)
+                           ? UserRegion->getSinglePredecessor()
+                           : UserRegion->getExiting();
+          } else if (UserVPBB->getNumPredecessors() == 1) {
+            assert(isa<VPWidenPHIRecipe>(UI) &&
+                   "Unexpected recipe with 1 predecessors");
+            Incoming = UserVPBB->getSinglePredecessor();
+          } else {
+            assert(UserVPBB->getNumPredecessors() == 2 &&
+                   isa<VPPredInstPHIRecipe>(UI) &&
+                   "Unexpected recipe with 2 or more predecessors");
+            Incoming = UserVPBB->getPredecessors()[1];
+          }
+          if (auto *R = dyn_cast<VPRegionBlock>(Incoming))
+            Incoming = R->getExiting();
+          if (Incoming != VPBB && !VPDT.dominates(VPBB, Incoming)) {
+            errs() << "Use before def!\n";
+            return false;
+          }
+          continue;
+        }
 
         // If the user is in the same block, check it comes after R in the
         // block.
-        if (UI->getParent() == VPBB) {
+        if (UserVPBB == VPBB) {
           if (RecipeNumbering[UI] < RecipeNumbering[&R]) {
             errs() << "Use before def!\n";
             return false;
@@ -222,7 +270,7 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
           continue;
         }
 
-        if (!VPDT.dominates(VPBB, UI->getParent())) {
+        if (!VPDT.dominates(VPBB, UserVPBB)) {
           errs() << "Use before def!\n";
           return false;
         }

@llvmbot
Copy link
Member

llvmbot commented Jan 28, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

Changes

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.

There are 4 different cases to consider when retrieving the incoming block:

  • VPIRInstructions wrapping phis: the incoming block from the blocks predecessors has the same index as the incoming value operand.
  • VPHeaderPhiRecipes, VPWidenPhi used in header: there's no predecessors; if the incoming value is the start value use the predecessor of the containing region, otherwise the exiting block of the region
  • 1 predecessor: Must be a VPWidenPHI used as LCSSA phi; use the predecessor
  • 2 predecessors: must be a VPPredInstPhiRecipe, use the second predecessor.

Full diff: https://github.com/llvm/llvm-project/pull/124838.diff

1 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp (+53-5)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
index 0f151c897d938e..0948452e8d19cf 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
@@ -175,6 +175,11 @@ bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
   });
 }
 
+/// Return true if \p R is a VPIRInstruction wrapping a phi.
+static bool isVPIRInstructionPhi(const VPRecipeBase &R) {
+  auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
+  return VPIRI && isa<PHINode>(VPIRI->getInstruction());
+}
 bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
   if (!verifyPhiRecipes(VPBB))
     return false;
@@ -207,14 +212,57 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
 
       for (const VPUser *U : V->users()) {
         auto *UI = cast<VPRecipeBase>(U);
-        // TODO: check dominance of incoming values for phis properly.
-        if (!UI ||
-            isa<VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPredInstPHIRecipe>(UI))
+        const VPBlockBase *UserVPBB = UI->getParent();
+
+        // Verify incoming values of VPIRInstructions wrapping phis. V most
+        // dominate the end of the incoming block. The operand index of the
+        // incoming value matches the predecessor block index of the
+        // corresponding incoming block.
+        if (isVPIRInstructionPhi(*UI)) {
+          for (const auto &[Idx, Op] : enumerate(UI->operands())) {
+            if (V != Op)
+              continue;
+            const VPBlockBase *Incoming = UserVPBB->getPredecessors()[Idx];
+            if (Incoming != VPBB && !VPDT.dominates(VPBB, Incoming)) {
+              errs() << "Use before def!\n";
+              return false;
+            }
+          }
           continue;
+        }
+        // Verify incoming value of various phi-like recipes.
+        if (isa<VPWidenPHIRecipe, VPHeaderPHIRecipe, VPPredInstPHIRecipe>(UI)) {
+          const VPBlockBase *Incoming = nullptr;
+          // Get the incoming block based on the number of predecessors.
+          if (UserVPBB->getNumPredecessors() == 0) {
+            assert((isa<VPWidenPHIRecipe>(UI) || isa<VPHeaderPHIRecipe>(UI)) &&
+                   "Unexpected recipe with 0 predecessors");
+            const VPRegionBlock *UserRegion = UserVPBB->getParent();
+            Incoming = V == UI->getOperand(0)
+                           ? UserRegion->getSinglePredecessor()
+                           : UserRegion->getExiting();
+          } else if (UserVPBB->getNumPredecessors() == 1) {
+            assert(isa<VPWidenPHIRecipe>(UI) &&
+                   "Unexpected recipe with 1 predecessors");
+            Incoming = UserVPBB->getSinglePredecessor();
+          } else {
+            assert(UserVPBB->getNumPredecessors() == 2 &&
+                   isa<VPPredInstPHIRecipe>(UI) &&
+                   "Unexpected recipe with 2 or more predecessors");
+            Incoming = UserVPBB->getPredecessors()[1];
+          }
+          if (auto *R = dyn_cast<VPRegionBlock>(Incoming))
+            Incoming = R->getExiting();
+          if (Incoming != VPBB && !VPDT.dominates(VPBB, Incoming)) {
+            errs() << "Use before def!\n";
+            return false;
+          }
+          continue;
+        }
 
         // If the user is in the same block, check it comes after R in the
         // block.
-        if (UI->getParent() == VPBB) {
+        if (UserVPBB == VPBB) {
           if (RecipeNumbering[UI] < RecipeNumbering[&R]) {
             errs() << "Use before def!\n";
             return false;
@@ -222,7 +270,7 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
           continue;
         }
 
-        if (!VPDT.dominates(VPBB, UI->getParent())) {
+        if (!VPDT.dominates(VPBB, UserVPBB)) {
           errs() << "Use before def!\n";
           return false;
         }

Copy link
Contributor

@david-arm david-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this - looks sensible to me. I just had a couple of comments.

static bool isVPIRInstructionPhi(const VPRecipeBase &R) {
auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
return VPIRI && isa<PHINode>(VPIRI->getInstruction());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add new line after function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adde a newline, thanks

"Unexpected recipe with 2 or more predecessors");
Incoming = UserVPBB->getPredecessors()[1];
}
if (auto *R = dyn_cast<VPRegionBlock>(Incoming))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, what's the scenario where the incoming block for a VPWidenPHIRecipe, VPHeaderPHIRecipe or VPPredInstPHIRecipe recipe would be the region? Is it the recipes we create in the middle block? If so, could this check potentially fail with uncountable early exits, i.e. the incoming block is effectively the middle.split block? I assume it's fine, but just wondering if there are missing tests for all the scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only case at the moment is in VPWidenPHIRecipes added in the VPlan-native path. I added an assert; it cannot happen in the inner-loop vectorizer path.

@fhahn fhahn force-pushed the vplan-verify-def-use-phi branch from 29aa9b0 to 695ef3c Compare January 29, 2025 20:47
@fhahn fhahn force-pushed the vplan-verify-def-use-phi branch from 695ef3c to 129e8ad Compare February 15, 2025 21:16
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping :)

Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to see this TODO being addressed, adding various comments.

@@ -207,24 +213,69 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {

for (const VPUser *U : V->users()) {
auto *UI = cast<VPRecipeBase>(U);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated nit:

Suggested change
auto *UI = cast<VPRecipeBase>(U);
auto *UR = cast<VPRecipeBase>(U);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix independently.

isa<PHINode>(cast<VPIRInstruction>(UI)->getInstruction())))
const VPBlockBase *UserVPBB = UI->getParent();

// Verify incoming values of VPIRInstructions wrapping phis. V most
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Verify incoming values of VPIRInstructions wrapping phis. V most
// Verify incoming values of VPIRInstructions wrapping phis. V must

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks


// Verify incoming values of VPIRInstructions wrapping phis. V most
// dominate the end of the incoming block. The operand index of the
// incoming value matches the predecessor block index of the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// incoming value matches the predecessor block index of the
// incoming value must match the predecessor block index of the

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks!

// incoming value matches the predecessor block index of the
// corresponding incoming block.
if (isVPIRInstructionPhi(*UI)) {
for (const auto &[Idx, Op] : enumerate(UI->operands())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (const auto &[Idx, Op] : enumerate(UI->operands())) {
for (const auto &[Index, OpAtIndex] : enumerate(UI->operands())) {

for (const auto &[Idx, Op] : enumerate(UI->operands())) {
if (V != Op)
continue;
const VPBlockBase *Incoming = UserVPBB->getPredecessors()[Idx];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const VPBlockBase *Incoming = UserVPBB->getPredecessors()[Idx];
const VPBlockBase *PredAtIndex = UserVPBB->getPredecessors()[Idx];

Comment on lines 235 to 237
if (isa<VPWidenPHIRecipe, VPHeaderPHIRecipe, VPPredInstPHIRecipe>(UI)) {
const VPBlockBase *Incoming = nullptr;
// Get the incoming block based on the number of predecessors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: better switch over the types of recipes involved, asserting the number of predecessors, than vice-versa? Nearly every recipe seems to be doing its own thing anyhow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code has been replaced by type-switch and using incoming values/blocks iterator.

"Unexpected recipe with 2 or more predecessors");
Incoming = UserVPBB->getPredecessors()[1];
}
if (auto *R = dyn_cast<VPRegionBlock>(Incoming)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (auto *R = dyn_cast<VPRegionBlock>(Incoming)) {
if (auto *IncomingRegion = dyn_cast<VPRegionBlock>(Incoming)) {

to avoid confusion with R which is also being used for the current Recipe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is gone in latest version

"VPWidenPHIRecipe");
Incoming = R->getExiting();
}
if (Incoming != VPBB && !VPDT.dominates(VPBB, Incoming)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is gone in latest version

// dominate the end of the incoming block. The operand index of the
// incoming value matches the predecessor block index of the
// corresponding incoming block.
if (isVPIRInstructionPhi(*UI)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the case of VPIRInstruction be handled along with all other phi recipes below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are cases where the block containing a VPIR Phi has multiple predecessors (some cases with early exits), for those we need the proper phi-handling

return false;
}
continue;
}

// If the user is in the same block, check it comes after R in the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If the user is in the same block, check it comes after R in the
// If the user is in the same block, check that it comes after R in the

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

independent typo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep can fix separately, thanks

fhahn added a commit to fhahn/llvm-project that referenced this pull request Mar 1, 2025
Add a VPPhiAccessors class to provide interfaces to access incoming
values and blocks, with corresponding iterators.

The first user is VPWidenPhiRecipe, with the other phi-like recipes
following soon.

This will also be used to verify def-use chains where users are phi-like
recipes, simplifying llvm#124838.
Add a VPPhiAccessors class to provide interfaces to access incoming
values and blocks, with corresponding iterators.

The first user is VPWidenPhiRecipe, with the other phi-like recipes
following soon.

This will also be used to verify def-use chains where users are phi-like
recipes, simplifying llvm#124838.
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworked the PR quite a bit and it is now building on a few additional patches:

auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
return VPIRI && isa<PHINode>(VPIRI->getInstruction());
}

bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
if (!verifyPhiRecipes(VPBB))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure how we could move the new code to verifyPhiRecipes, as here we verify def before use property looking at the uses of a defined VPValue and when looking at the uses we need to handle phi-like recipes.

@@ -175,6 +175,12 @@ bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
});
}

/// Return true if \p R is a VPIRInstruction wrapping a phi.
static bool isVPIRInstructionPhi(const VPRecipeBase &R) {
auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will check separately, thanks!

auto *VPIRI = dyn_cast<VPIRInstruction>(&R);
return VPIRI && isa<PHINode>(VPIRI->getInstruction());
}

bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {
if (!verifyPhiRecipes(VPBB))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be complete now, updated, thanks!

@@ -207,24 +213,69 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) {

for (const VPUser *U : V->users()) {
auto *UI = cast<VPRecipeBase>(U);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix independently.

isa<PHINode>(cast<VPIRInstruction>(UI)->getInstruction())))
const VPBlockBase *UserVPBB = UI->getParent();

// Verify incoming values of VPIRInstructions wrapping phis. V most
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks


// Verify incoming values of VPIRInstructions wrapping phis. V most
// dominate the end of the incoming block. The operand index of the
// incoming value matches the predecessor block index of the
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks!

// dominate the end of the incoming block. The operand index of the
// incoming value matches the predecessor block index of the
// corresponding incoming block.
if (isVPIRInstructionPhi(*UI)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are cases where the block containing a VPIR Phi has multiple predecessors (some cases with early exits), for those we need the proper phi-handling

Copy link

github-actions bot commented Mar 1, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

fhahn added a commit to fhahn/llvm-project that referenced this pull request Mar 12, 2025
Add a VPPhiAccessors class to provide interfaces to access incoming
values and blocks, with corresponding iterators.

The first user is VPWidenPhiRecipe, with the other phi-like recipes
following soon.

This will also be used to verify def-use chains where users are phi-like
recipes, simplifying llvm#124838.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…llvm#129388)

Add a VPPhiAccessors class to provide interfaces to access incoming
values and blocks.

The first user is VPWidenPhiRecipe, with the other phi-like recipes
following soon.

This will also be used to verify def-use chains where users are phi-like
recipes, simplifying llvm#124838.

PR: llvm#129388
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 8, 2025
Similarly to VPInstructionWithType and VPIRPhi, add VPPhi as a subclass
for VPInstruction. This allows implementing the VPPhiAccessors trait,
making available helpers for generic printing of incoming values /
blocks and accessors for incoming blocks and values.

It will also allow properly verifying def-uses for values used by
VPInstructions with PHI opcodes via
llvm#124838.
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 9, 2025
Similarly to VPInstructionWithType and VPIRPhi, add VPPhi as a subclass
for VPInstruction. This allows implementing the VPPhiAccessors trait,
making available helpers for generic printing of incoming values /
blocks and accessors for incoming blocks and values.

It will also allow properly verifying def-uses for values used by
VPInstructions with PHI opcodes via
llvm#124838.
fhahn added a commit to fhahn/llvm-project that referenced this pull request May 10, 2025
Similarly to VPInstructionWithType and VPIRPhi, add VPPhi as a subclass
for VPInstruction. This allows implementing the VPPhiAccessors trait,
making available helpers for generic printing of incoming values /
blocks and accessors for incoming blocks and values.

It will also allow properly verifying def-uses for values used by
VPInstructions with PHI opcodes via
llvm#124838.
fhahn added a commit that referenced this pull request May 10, 2025
…139151)

Similarly to VPInstructionWithType and VPIRPhi, add VPPhi as a subclass
for VPInstruction. This allows implementing the VPPhiAccessors trait,
making available helpers for generic printing of incoming values /
blocks and accessors for incoming blocks and values.

It will also allow properly verifying def-uses for values used by
VPInstructions with PHI opcodes via
#124838.

PR: #139151
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 10, 2025
…des.(NFC) (#139151)

Similarly to VPInstructionWithType and VPIRPhi, add VPPhi as a subclass
for VPInstruction. This allows implementing the VPPhiAccessors trait,
making available helpers for generic printing of incoming values /
blocks and accessors for incoming blocks and values.

It will also allow properly verifying def-uses for values used by
VPInstructions with PHI opcodes via
llvm/llvm-project#124838.

PR: llvm/llvm-project#139151
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping :)

Now that #138472 and #139151 landed, this should be ready for another look

@@ -1135,7 +1135,14 @@ class VPPhiAccessors {
const VPBasicBlock *getIncomingBlock(unsigned Idx) const;

/// Returns the number of incoming values, also number of incoming blocks.
unsigned getNumIncoming() const { return getAsRecipe()->getNumOperands(); }
/// Note that at the moment, VPWidenIntOrFpInductionRecipes only have a single
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this still includes bits of #138472, which looks like it hasn't landed yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#138472 simply adds additional iterators, but that is optional and not needed for the verification patch itself; they both need handling for additional recipes in getNumIncoming though. Currently #138472 is more of a follow-up after this patch

@@ -1135,7 +1135,14 @@ class VPPhiAccessors {
const VPBasicBlock *getIncomingBlock(unsigned Idx) const;

/// Returns the number of incoming values, also number of incoming blocks.
unsigned getNumIncoming() const { return getAsRecipe()->getNumOperands(); }
/// Note that at the moment, VPWidenIntOrFpInductionRecipes only have a single
/// incoming value, its start value.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better have VPWidenIntOrFpInductionRecipe override a virtual getNumIncoming()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks


static inline VPPhiAccessors *castFailed() { return nullptr; }

static inline VPPhiAccessors *doCastIfPossible(const VPRecipeBase *f) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is doCastIfPossible used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used by dyn_cast


using Self = CastInfo<VPPhiAccessors, const VPRecipeBase *>;

using CastReturnType =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is CastReturnType used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused in the latest version, removed, thanks!

@@ -3283,6 +3295,48 @@ class VPScalarIVStepsRecipe : public VPRecipeWithIRFlags,
}
};

/// Casting from VPRecipeBase -> VPPhiAccessors is supported for all recipe
/// types implementing VPPhiAccessors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this scaffolding needed for dyn_cast<VPPhiAccessors>(RecipeBase*) to work, due to its multiple inheritance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep as there's no link between RecipeBase and VPPhiAccessors. CastIsPossible is used for isa

/// Support casting from VPRecipeBase -> VPPhiAccessors, by down-casting to the
/// recipe types implementing VPPhiAccessors.
template <>
struct CastInfo<VPPhiAccessors, const VPRecipeBase *>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is CastInfo used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used by cast/dyn_cast to perform the actual cast.

const VPBasicBlock *IncVPBB = Phi->getIncomingBlock(Idx);
if (IncVPV != V)
continue;
if (IncVPBB != VPBB && !VPDT.dominates(VPBB, IncVPBB)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dominates(VPBB, IncVPBB) returns true when VPBB == IncVPBB, so suffice to check if (!VPDT.dominates(VPBB, IncVPBB))? But is it ok to have VPBB == IncVPBB, given that U is a phi - only if V is a phi too and such dependences between two phi's of the same block are allowed in VPlan, where fixed order dependences are modelled with intervening splices - for VF>1?
In any case good to continue with early continue:

Suggested change
if (IncVPBB != VPBB && !VPDT.dominates(VPBB, IncVPBB)) {
if (VPDT.properlyDominates(VPBB, IncVPBB))
continue;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to just dominates. We could have a loop with a single block, then the incoming value from the latch would be definined in the same block?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right; a value can be defined in the header and feed a header phi (of the same header block) even when the loop has additional blocks. Can check that in this case it's the 2nd incoming of the phi, i.e., across the backedge.

Comment on lines 224 to 227
VPValue *IncVPV = Phi->getIncomingValue(Idx);
const VPBasicBlock *IncVPBB = Phi->getIncomingBlock(Idx);
if (IncVPV != V)
continue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
VPValue *IncVPV = Phi->getIncomingValue(Idx);
const VPBasicBlock *IncVPBB = Phi->getIncomingBlock(Idx);
if (IncVPV != V)
continue;
VPValue *IncomingV = Phi->getIncomingValue(Idx);
if (IncomingV != V)
continue;
const VPBasicBlock *IncomingVPBB = Phi->getIncomingBlock(Idx);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thanks

/// types implementing VPPhiAccessors.
template <> struct CastIsPossible<VPPhiAccessors, const VPRecipeBase *> {
static inline bool isPossible(const VPRecipeBase *f) {
return isa<VPIRPhi, VPHeaderPHIRecipe, VPWidenPHIRecipe, VPPhi>(f);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VPPredInstPHIRecipe might be another?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I left it out for now because more work will be needed as there the operands also don't match the # of predecessors.

}
continue;
}
if (isa<VPPredInstPHIRecipe>(UI))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything to check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, added a TODO for now, thanks

return false;
}
continue;
}

// If the user is in the same block, check it comes after R in the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

independent typo.

Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@@ -3283,6 +3295,43 @@ class VPScalarIVStepsRecipe : public VPRecipeWithIRFlags,
}
};

/// Casting from VPRecipeBase -> VPPhiAccessors is supported for all recipe
/// types implementing VPPhiAccessors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// types implementing VPPhiAccessors.
/// types implementing VPPhiAccessors. CastIsPossible is used by isa.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adde a note, thanks!

/// Casting from VPRecipeBase -> VPPhiAccessors is supported for all recipe
/// types implementing VPPhiAccessors.
template <> struct CastIsPossible<VPPhiAccessors, const VPRecipeBase *> {
static inline bool isPossible(const VPRecipeBase *f) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static inline bool isPossible(const VPRecipeBase *f) {
static inline bool isPossible(const VPRecipeBase *f) {
// TODO: include VPPredInstPHIRecipe too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added thanks

}
};
/// Support casting from VPRecipeBase -> VPPhiAccessors, by down-casting to the
/// recipe types implementing VPPhiAccessors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// recipe types implementing VPPhiAccessors.
/// recipe types implementing VPPhiAccessors. CastInfo is used by cast and dyn_cast.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added thanks.

}());
}

static inline VPPhiAccessors *doCastIfPossible(const VPRecipeBase *f) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static inline VPPhiAccessors *doCastIfPossible(const VPRecipeBase *f) {
/// doCastIfPossible is used by dyn_cast.
static inline VPPhiAccessors *doCastIfPossible(const VPRecipeBase *f) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added thanks

if (IncVPV != V)
continue;
const VPBasicBlock *IncVPBB = Phi->getIncomingBlock(Idx);
if (!VPDT.dominates(VPBB, IncVPBB)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another early-continue?

Suggested change
if (!VPDT.dominates(VPBB, IncVPBB)) {
if (VPDT.dominates(VPBB, IncVPBB))
continue;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated thanks

const VPBasicBlock *IncVPBB = Phi->getIncomingBlock(Idx);
if (IncVPV != V)
continue;
if (IncVPBB != VPBB && !VPDT.dominates(VPBB, IncVPBB)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right; a value can be defined in the header and feed a header phi (of the same header block) even when the loop has additional blocks. Can check that in this case it's the 2nd incoming of the phi, i.e., across the backedge.

cast<VPInstruction>(UI)->getOpcode() == Instruction::PHI))
if (auto *Phi = dyn_cast<VPPhiAccessors>(UI)) {
for (unsigned Idx = 0; Idx != Phi->getNumIncoming(); ++Idx) {
VPValue *IncVPV = Phi->getIncomingValue(Idx);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Inc" is ambiguous - e.g., also stands for "Increment". Hence suggested renaming to IncomingV and IncomingVPBB.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, thanks

@fhahn fhahn merged commit 8bbe0d0 into llvm:main May 15, 2025
10 of 11 checks passed
@fhahn fhahn deleted the vplan-verify-def-use-phi branch May 15, 2025 11:20
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 15, 2025

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-win-fast running on as-builder-3 while building llvm at step 7 "test-build-unified-tree-check-llvm-unit".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/2/builds/24015

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-llvm-unit) failure: test (failure)
******************** TEST 'LLVM-Unit :: Transforms/Vectorize/./VectorizeTests.exe/46/51' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:C:\buildbot\as-builder-3\llvm-clang-x86_64-win-fast\build\unittests\Transforms\Vectorize\.\VectorizeTests.exe-LLVM-Unit-3468-46-51.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=51 GTEST_SHARD_INDEX=46 C:\buildbot\as-builder-3\llvm-clang-x86_64-win-fast\build\unittests\Transforms\Vectorize\.\VectorizeTests.exe
--

Script:
--
C:\buildbot\as-builder-3\llvm-clang-x86_64-win-fast\build\unittests\Transforms\Vectorize\.\VectorizeTests.exe --gtest_filter=VPVerifierTest.VPPhiIncomingValueDoesntDominateIncomingBlock
--
C:\buildbot\as-builder-3\llvm-clang-x86_64-win-fast\llvm-project\llvm\unittests\Transforms\Vectorize\VPlanVerifierTest.cpp(178): error: Expected equality of these values:
  "Use before def!\n"
  ::testing::internal::GetCapturedStderr().c_str()
    Which is: "Incoming def at index 0 does not dominate incoming block!\n"


C:\buildbot\as-builder-3\llvm-clang-x86_64-win-fast\llvm-project\llvm\unittests\Transforms\Vectorize\VPlanVerifierTest.cpp:178
Expected equality of these values:
  "Use before def!\n"
  ::testing::internal::GetCapturedStderr().c_str()
    Which is: "Incoming def at index 0 does not dominate incoming block!\n"



********************


@llvm-ci
Copy link
Collaborator

llvm-ci commented May 15, 2025

LLVM Buildbot has detected a new failure on builder sanitizer-aarch64-linux running on sanitizer-buildbot8 while building llvm at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/51/builds/16196

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
[182/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64-with-call.o
[183/186] Generating Msan-aarch64-with-call-Test
[184/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64.o
[185/186] Generating Msan-aarch64-Test
[185/186] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/interception/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 5915 tests, 72 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
FAIL: libFuzzer-aarch64-static-libcxx-Linux :: reduce_inputs.test (5833 of 5915)
******************** TEST 'libFuzzer-aarch64-static-libcxx-Linux :: reduce_inputs.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
rm -rf /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C # RUN: at line 3
+ rm -rf /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
mkdir -p /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C # RUN: at line 4
+ mkdir -p /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer  -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest # RUN: at line 5
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer  -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest # RUN: at line 6
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test # RUN: at line 7
+ /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
+ FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT # RUN: at line 11
+ FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT
+ /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test:12:8: error: COUNT: expected string not found in input
COUNT: seed corpus: files: 4
       ^
<stdin>:1:1: note: scanning from here
INFO: Running with entropic power schedule (0xFF, 100).
^
<stdin>:7:7: note: possible intended match here
INFO: seed corpus: files: 3 min: 2b max: 3b total: 7b rss: 32Mb
      ^

Input file: <stdin>
Check file: /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: INFO: Running with entropic power schedule (0xFF, 100). 
check:12'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
Step 9 (test compiler-rt symbolizer) failure: test compiler-rt symbolizer (failure)
...
[182/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64-with-call.o
[183/186] Generating Msan-aarch64-with-call-Test
[184/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64.o
[185/186] Generating Msan-aarch64-Test
[185/186] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/interception/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 5915 tests, 72 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
FAIL: libFuzzer-aarch64-static-libcxx-Linux :: reduce_inputs.test (5833 of 5915)
******************** TEST 'libFuzzer-aarch64-static-libcxx-Linux :: reduce_inputs.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
rm -rf /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C # RUN: at line 3
+ rm -rf /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
mkdir -p /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C # RUN: at line 4
+ mkdir -p /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer  -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest # RUN: at line 5
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer  -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest # RUN: at line 6
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/lib/fuzzer -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test # RUN: at line 7
+ /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
+ FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT # RUN: at line 11
+ FileCheck /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT
+ /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/AARCH64StaticLibcxxLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test:12:8: error: COUNT: expected string not found in input
COUNT: seed corpus: files: 4
       ^
<stdin>:1:1: note: scanning from here
INFO: Running with entropic power schedule (0xFF, 100).
^
<stdin>:7:7: note: possible intended match here
INFO: seed corpus: files: 3 min: 2b max: 3b total: 7b rss: 32Mb
      ^

Input file: <stdin>
Check file: /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: INFO: Running with entropic power schedule (0xFF, 100). 
check:12'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 15, 2025
…ecipes. (#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 llvm/llvm-project#138472 to
retrieve incoming values & corresponding blocks for phi-like recipes.

PR: llvm/llvm-project#124838
@vvereschaka
Copy link
Contributor

@fhahn ,

these changes cause a crash for the following tests on the expensive check builders such as llvm-clang-x86_64-expensive-checks-ubuntu:

  • first-order-recurrence.ll
  • pointer_iv.ll
  • pr48340.ll

more details here https://lab.llvm.org/buildbot/#/builders/187/builds/5956

/home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/opt -passes=loop-vectorize --force-vector-width=4 --force-vector-interleave=0 -S -o - < /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/test/Transforms/LoopVectorize/X86/pr48340.ll | /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/FileCheck /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/test/Transforms/LoopVectorize/X86/pr48340.ll # RUN: at line 2
+ /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/opt -passes=loop-vectorize --force-vector-width=4 --force-vector-interleave=0 -S -o -
+ /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/FileCheck /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/test/Transforms/LoopVectorize/X86/pr48340.ll
opt: /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.cpp:787: const llvm::VPBasicBlock* llvm::VPBasicBlock::getCFGPredecessor(unsigned int) const: Assertion `Idx < 2 && Region->getNumPredecessors() == 1 && "loop region has a single predecessor (preheader), its entry block " "has 2 incoming blocks"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/opt -passes=loop-vectorize --force-vector-width=4 --force-vector-interleave=0 -S -o -
1.	Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "<stdin>"
2.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "foo"
 #0 0x00005581969b7064 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Support/Unix/Signals.inc:804:22
 #1 0x00005581969b74f7 PrintStackTraceSignalHandler(void*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Support/Unix/Signals.inc:888:1
 #2 0x00005581969b48b3 llvm::sys::RunSignalHandlers() /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Support/Signals.cpp:105:20
 #3 0x00005581969b68d3 SignalHandler(int, siginfo_t*, void*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Support/Unix/Signals.inc:418:13
 #4 0x00007fc006abf520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #5 0x00007fc006b139fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #6 0x00007fc006abf476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #7 0x00007fc006aa57f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #8 0x00007fc006aa571b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #9 0x00007fc006ab6e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#10 0x0000558193c88f1b llvm::VPBasicBlock::getCFGPredecessor(unsigned int) const /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.cpp:793:21
#11 0x00005581939f1a4c llvm::VPPhiAccessors::getIncomingBlock(unsigned int) const /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.h:3487:1
#12 0x0000558193d3a979 (anonymous namespace)::VPlanVerifier::verifyVPBasicBlock(llvm::VPBasicBlock const*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:228:69
#13 0x0000558193d3b32c (anonymous namespace)::VPlanVerifier::verifyBlock(llvm::VPBlockBase const*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:362:16
#14 0x0000558193d3b452 (anonymous namespace)::VPlanVerifier::verifyBlocksInRegion(llvm::VPRegionBlock const*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:373:9
#15 0x0000558193d3b5cf (anonymous namespace)::VPlanVerifier::verifyRegion(llvm::VPRegionBlock const*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:393:37
#16 0x0000558193d3b670 (anonymous namespace)::VPlanVerifier::verifyRegionRec(llvm::VPRegionBlock const*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:398:31
#17 0x0000558193d3b7e2 (anonymous namespace)::VPlanVerifier::verify(llvm::VPlan const&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:412:7
#18 0x0000558193d3baf2 llvm::verifyVPlanIsValid(llvm::VPlan const&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp:461:25
#19 0x0000558193a0ae3d void llvm::VPlanTransforms::runPass<unsigned int, llvm::LLVMContext&>(void (*)(llvm::VPlan&, unsigned int, llvm::LLVMContext&), llvm::VPlan&, std::remove_reference<unsigned int>::type&, std::remove_reference<llvm::LLVMContext&>::type&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/VPlanTransforms.h:54:3
#20 0x00005581939c5c1f llvm::LoopVectorizationPlanner::executePlan(llvm::ElementCount, unsigned int, llvm::VPlan&, llvm::InnerLoopVectorizer&, llvm::DominatorTree*, bool) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7796:27
#21 0x00005581939d7f2c llvm::LoopVectorizePass::processLoop(llvm::Loop*) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:10980:24
#22 0x00005581939d859a llvm::LoopVectorizePass::runImpl(llvm::Function&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:11059:27
#23 0x00005581939d88e7 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:11096:39
#24 0x0000558192f7e657 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:92:3
#25 0x00005581966d27ad llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:18
#26 0x0000558190a78fab llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:92:3
#27 0x00005581966d1682 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/lib/IR/PassManager.cpp:129:23
#28 0x0000558190a78d25 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:92:3
#29 0x00005581966d23d9 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/include/llvm/IR/PassManagerImpl.h:85:18
#30 0x00005581901732f9 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/tools/opt/NewPMDriver.cpp:557:10
#31 0x00005581901437eb optMain /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/tools/opt/optdriver.cpp:729:27
#32 0x0000558190141001 main /home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/llvm-project/llvm/tools/opt/opt.cpp:25:64
#33 0x00007fc006aa6d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#34 0x00007fc006aa6e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#35 0x0000558190140ee5 _start (/home/buildbot/worker/as-builder-4/ramdisk/expensive-checks/build/bin/opt+0xfdeee5)
FileCheck error: '<stdin>' is empty.

would you fix the problem as soon as it possible or revert these changes

@fhahn
Copy link
Contributor Author

fhahn commented May 17, 2025

@vvereschaka should be back to green after b3e7e4b

fhahn referenced this pull request May 18, 2025
Similar to VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe
only has a single incoming value and no backedge value.

Currently NFC as there are no problematic uses at the moment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants