[llvm] [VPlan] Check operand types of more VPInstruction on construction (NFC). (PR #203777)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 14 11:11:06 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/203777

Follow-up to earlier PRs, tighten VPInstruction operand type checks at construction: restrict operand types for various opcodes, and support missing opcodes.

>From 6eb8bd14e712dd3506889be2021f737c8859db9f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 13 Jun 2026 21:46:40 +0200
Subject: [PATCH] [VPlan] Check operand types of more VPInstruction on
 construction (NFC).

Follow-up to earlier PRs, tighten VPInstruction operand type checks at
construction: restrict operand types for various opcodes, and support
missing opcodes.
---
 .../lib/Transforms/Vectorize/VPlanRecipes.cpp | 61 +++++++++++++++++--
 .../Vectorize/VPlanVerifierTest.cpp           | 18 +++---
 2 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 17b90c733a817..e4ec0a2d535ab 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -459,37 +459,88 @@ Type *llvm::computeScalarTypeForInstruction(unsigned Opcode,
   LLVMContext &Ctx = Op0Ty->getContext();
   switch (Opcode) {
   case VPInstruction::BranchOnCond:
+    assert(Op0Ty->isIntegerTy(1) && "expected bool condition");
+    return Type::getVoidTy(Ctx);
   case VPInstruction::BranchOnTwoConds:
+    assert(Op0Ty->isIntegerTy(1) && "expected bool condition");
+    AssertOperandType(1, IntegerType::get(Ctx, 1));
+    return Type::getVoidTy(Ctx);
   case VPInstruction::BranchOnCount:
-  case Instruction::Store:
+    assert(Op0Ty->isIntegerTy() && "expected integer operand");
+    AssertOperandType(1, Op0Ty);
+    return Type::getVoidTy(Ctx);
+  case VPInstruction::CalculateTripCountMinusVF:
+  case VPInstruction::CanonicalIVIncrementForPart:
+    assert(Op0Ty->isIntegerTy() && "expected integer operand");
+    for (unsigned Idx = 1; Idx != Operands.size(); ++Idx)
+      AssertOperandType(Idx, Op0Ty);
+    return Op0Ty;
   case Instruction::Switch:
+    for (unsigned Idx = 1; Idx != Operands.size(); ++Idx)
+      AssertOperandType(Idx, Op0Ty);
+    return Type::getVoidTy(Ctx);
+  case Instruction::Store:
     return Type::getVoidTy(Ctx);
   case Instruction::ICmp:
+    assert(Op0Ty->isIntOrPtrTy() && "expected integer or pointer operand");
+    AssertOperandType(1, Op0Ty);
+    return IntegerType::get(Ctx, 1);
   case Instruction::FCmp:
+    assert(Op0Ty->isFloatingPointTy() && "expected floating-point operand");
+    AssertOperandType(1, Op0Ty);
+    return IntegerType::get(Ctx, 1);
   case VPInstruction::ActiveLaneMask:
+    assert(Op0Ty->isIntegerTy() && "expected integer operand");
     AssertOperandType(1, Op0Ty);
     return IntegerType::get(Ctx, 1);
+  case VPInstruction::MaskedCond:
+    assert(Op0Ty->isIntegerTy(1) && "expected bool operand");
+    return IntegerType::get(Ctx, 1);
   case VPInstruction::LogicalAnd:
   case VPInstruction::LogicalOr:
-  case VPInstruction::MaskedCond:
-    assert((!Op0Ty || Op0Ty->isIntegerTy(1)) && "expected bool operand");
+    assert(Op0Ty->isIntegerTy(1) && "expected bool operand");
     AssertOperandType(1, Op0Ty);
     return IntegerType::get(Ctx, 1);
+  case VPInstruction::AnyOf:
+    assert(Op0Ty->isIntegerTy(1) && "expected bool operand");
+    for (unsigned Idx = 1; Idx != Operands.size(); ++Idx)
+      AssertOperandType(Idx, Op0Ty);
+    return IntegerType::get(Ctx, 1);
   case VPInstruction::ExplicitVectorLength:
+    assert(Op0Ty->isIntegerTy() && "expected integer operand");
     return IntegerType::get(Ctx, 32);
   case Instruction::Select: {
+    assert((!Op0Ty || Op0Ty->isIntegerTy(1)) &&
+           "select condition must be bool");
     Type *Op1Ty = Operands[1]->getScalarType();
     AssertOperandType(2, Op1Ty);
     return Op1Ty;
   }
+  case Instruction::InsertElement:
+    // The inserted scalar (operand 1) must match the vector element type;
+    // operand 2 is the index and may have a different type.
+    AssertOperandType(1, Op0Ty);
+    return Op0Ty;
+  case VPInstruction::ReductionStartVector:
+    // The start value and the identity value (operands 0 and 1) fill the same
+    // vector and must match in type; operand 2 is the scaling factor.
+    AssertOperandType(1, Op0Ty);
+    return Op0Ty;
   case VPInstruction::ExtractLane: {
     assert(Operands.size() >= 2 && "ExtractLane requires a lane operand and "
                                    "at least one source vector operand");
+    // Operand 0 is the lane index, used for integer arithmetic.
+    assert(Op0Ty->isIntegerTy() && "expected integer operand");
     Type *Op1Ty = Operands[1]->getScalarType();
     for (unsigned Idx = 2; Idx != Operands.size(); ++Idx)
       AssertOperandType(Idx, Op1Ty);
     return Op1Ty;
   }
+  case VPInstruction::PtrAdd:
+  case VPInstruction::WidePtrAdd:
+    assert(Operands[1]->getScalarType()->isIntegerTy() &&
+           "expected integer operand");
+    return Op0Ty;
   case Instruction::ExtractValue: {
     assert(Operands.size() == 2 && "expected single level extractvalue");
     auto *StructTy = cast<StructType>(Op0Ty);
@@ -514,9 +565,7 @@ Type *llvm::computeScalarTypeForInstruction(unsigned Opcode,
   bool AllOperandsSameType =
       Instruction::isBinaryOp(Opcode) ||
       is_contained({VPInstruction::FirstOrderRecurrenceSplice,
-                    VPInstruction::CalculateTripCountMinusVF,
-                    VPInstruction::CanonicalIVIncrementForPart,
-                    VPInstruction::AnyOf, VPInstruction::BuildVector,
+                    VPInstruction::BuildVector,
                     VPInstruction::BuildStructVector},
                    Opcode);
   if (AllOperandsSameType)
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
index 638a875df86ea..64101278c08bf 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
@@ -76,7 +76,7 @@ TEST_F(VPVerifierTest, VPInstructionUseBeforeDefDifferentBB) {
       new VPInstruction(Instruction::Sub, {DefI, Zero},
                         VPIRFlags::getDefaultFlags(Instruction::Sub));
   VPInstruction *BranchOnCond =
-      new VPInstruction(VPInstruction::BranchOnCond, {UseI});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
 
   VPBasicBlock *VPBB1 = Plan.getEntry();
   VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("");
@@ -118,7 +118,7 @@ TEST_F(VPVerifierTest, VPBlendUseBeforeDefDifferentBB) {
       new VPInstruction(Instruction::Add, {Zero, Zero},
                         VPIRFlags::getDefaultFlags(Instruction::Add));
   VPInstruction *BranchOnCond =
-      new VPInstruction(VPInstruction::BranchOnCond, {DefI});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
   auto *Blend = new VPBlendRecipe(Phi, {DefI, Plan.getTrue()}, {}, {});
 
   VPBasicBlock *VPBB1 = Plan.getEntry();
@@ -206,9 +206,9 @@ TEST_F(VPVerifierTest, DuplicateSuccessorsOutsideRegion) {
       new VPInstruction(Instruction::Add, {Zero, Zero},
                         VPIRFlags::getDefaultFlags(Instruction::Add));
   VPInstruction *BranchOnCond =
-      new VPInstruction(VPInstruction::BranchOnCond, {I1});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
   VPInstruction *BranchOnCond2 =
-      new VPInstruction(VPInstruction::BranchOnCond, {I1});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
 
   VPBasicBlock *VPBB1 = Plan.getEntry();
   VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("");
@@ -235,9 +235,9 @@ TEST_F(VPVerifierTest, DuplicateSuccessorsInsideRegion) {
       new VPInstruction(Instruction::Add, {Zero, Zero},
                         VPIRFlags::getDefaultFlags(Instruction::Add));
   VPInstruction *BranchOnCond =
-      new VPInstruction(VPInstruction::BranchOnCond, {I1});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
   VPInstruction *BranchOnCond2 =
-      new VPInstruction(VPInstruction::BranchOnCond, {I1});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
 
   VPBasicBlock *VPBB1 = Plan.getEntry();
   VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("");
@@ -272,7 +272,7 @@ TEST_F(VPVerifierTest, BlockOutsideRegionWithParent) {
       new VPInstruction(Instruction::Add, {Zero, Zero},
                         VPIRFlags::getDefaultFlags(Instruction::Add));
   VPInstruction *BranchOnCond =
-      new VPInstruction(VPInstruction::BranchOnCond, {DefI});
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
 
   VPBB1->appendRecipe(DefI);
   VPBB2->appendRecipe(BranchOnCond);
@@ -296,8 +296,8 @@ TEST_F(VPVerifierTest, BlockOutsideRegionWithParent) {
 
 TEST_F(VPVerifierTest, NonHeaderPHIInHeader) {
   VPlan &Plan = getPlan();
-  VPValue *Zero = Plan.getConstantInt(32, 0);
-  auto *BranchOnCond = new VPInstruction(VPInstruction::BranchOnCond, {Zero});
+  auto *BranchOnCond =
+      new VPInstruction(VPInstruction::BranchOnCond, {Plan.getFalse()});
 
   VPBasicBlock *VPBB1 = Plan.getEntry();
   VPBasicBlock *VPBB2 = Plan.createVPBasicBlock("header");



More information about the llvm-commits mailing list