diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp index 91734a10cb2c8..34754a1ea3992 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp @@ -252,6 +252,13 @@ bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) { for (const VPUser *U : V->users()) { auto *UI = cast(U); + if (isa(UI) && + UI->getNumOperands() != UI->getParent()->getNumPredecessors()) { + errs() << "Phi-like recipe with different number of operands and " + "predecessors.\n"; + return false; + } + if (auto *Phi = dyn_cast(UI)) { for (const auto &[IncomingVPV, IncomingVPBB] : Phi->incoming_values_and_blocks()) { diff --git a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp index 46802826fe090..169114ed6c310 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp @@ -326,22 +326,18 @@ TEST_F(VPVerifierTest, NonHeaderPHIInHeader) { class VPIRVerifierTest : public VPlanTestIRBase {}; -TEST_F(VPIRVerifierTest, testVerifyIRPhi) { +TEST_F(VPIRVerifierTest, testVerifyIRPhiInScalarHeaderVPIRBB) { const char *ModuleString = "define void @f(ptr %A, i64 %N) {\n" "entry:\n" " br label %loop\n" "loop:\n" " %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]\n" - " %arr.idx = getelementptr inbounds i32, ptr %A, i64 %iv\n" - " %l1 = load i32, ptr %arr.idx, align 4\n" - " %res = add i32 %l1, 10\n" - " store i32 %res, ptr %arr.idx, align 4\n" " %iv.next = add i64 %iv, 1\n" " %exitcond = icmp ne i64 %iv.next, %N\n" " br i1 %exitcond, label %loop, label %for.end\n" "for.end:\n" - " %p = phi i32 [ %l1, %loop ]\n" + " %p = phi i64 [ %iv, %loop ]\n" " ret void\n" "}\n"; @@ -351,7 +347,48 @@ TEST_F(VPIRVerifierTest, testVerifyIRPhi) { BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); auto Plan = buildVPlan(LoopHeader); - Plan->getExitBlocks()[0]->front().addOperand(Plan->getConstantInt(32, 0)); +#if GTEST_HAS_STREAM_REDIRECTION + ::testing::internal::CaptureStderr(); +#endif + EXPECT_FALSE(verifyVPlanIsValid(*Plan)); +#if GTEST_HAS_STREAM_REDIRECTION + EXPECT_STREQ( + "Phi-like recipe with different number of operands and predecessors.\n", + ::testing::internal::GetCapturedStderr().c_str()); +#endif +} + +TEST_F(VPIRVerifierTest, testVerifyIRPhiInExitVPIRBB) { + const char *ModuleString = + "define void @f(ptr %A, i64 %N) {\n" + "entry:\n" + " br label %loop\n" + "loop:\n" + " %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]\n" + " %iv.next = add i64 %iv, 1\n" + " %exitcond = icmp ne i64 %iv.next, %N\n" + " br i1 %exitcond, label %loop, label %for.end\n" + "for.end:\n" + " %p = phi i64 [ %iv, %loop ]\n" + " ret void\n" + "}\n"; + + Module &M = parseModule(ModuleString); + + Function *F = M.getFunction("f"); + BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); + auto Plan = buildVPlan(LoopHeader); + + // Create a definition in the vector loop header that will be used by the phi. + auto *HeaderBlock = + cast(Plan->getVectorLoopRegion()->getEntry()); + VPInstruction *DefI = + new VPInstruction(VPInstruction::ExtractLastElement, + {HeaderBlock->front().getVPSingleValue()}); + DefI->insertBefore(Plan->getMiddleBlock()->getTerminator()); + Plan->getExitBlocks()[0]->front().addOperand(DefI); + VPValue *Zero = Plan->getConstantInt(32, 0); + Plan->getScalarHeader()->front().addOperand(Zero); #if GTEST_HAS_STREAM_REDIRECTION ::testing::internal::CaptureStderr();