-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[LV] Provide utility routine to find uncounted exit recipes #152530
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
Changes from all commits
7d75529
688eadb
3ad198d
2f81520
2fd4504
febf5ab
eb82e1b
8507a8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -101,6 +101,17 @@ bool isUniformAcrossVFsAndUFs(VPValue *V); | |
| /// Returns the header block of the first, top-level loop, or null if none | ||
| /// exist. | ||
| VPBasicBlock *getFirstLoopHeader(VPlan &Plan, VPDominatorTree &VPDT); | ||
|
|
||
| /// Returns the VPValue representing the uncountable exit comparison used by | ||
| /// AnyOf if the recipes it depends on can be traced back to live-ins and | ||
|
||
| /// the addresses (in GEP/PtrAdd form) of any (non-masked) load used in | ||
| /// generating the values for the comparison. The recipes are stored in | ||
| /// \p Recipes, and recipes forming an address for a load are also added to | ||
| /// \p GEPs. | ||
| std::optional<VPValue *> | ||
| getRecipesForUncountableExit(VPlan &Plan, | ||
| SmallVectorImpl<VPRecipeBase *> &Recipes, | ||
| SmallVectorImpl<VPRecipeBase *> &GEPs); | ||
| } // namespace vputils | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -148,6 +148,8 @@ class LLVM_ABI_FOR_TEST VPValue { | |
| return Current != user_end(); | ||
| } | ||
|
|
||
| bool hasOneUse() const { return getNumUsers() == 1; } | ||
|
||
|
|
||
| void replaceAllUsesWith(VPValue *New); | ||
|
|
||
| /// Go through the uses list for this VPValue and make each use point to \p | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| //===- llvm/unittests/Transforms/Vectorize/VPlanUncountableExitTest.cpp ---===// | ||
| // | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "../lib/Transforms/Vectorize/VPlan.h" | ||
| #include "../lib/Transforms/Vectorize/VPlanUtils.h" | ||
| #include "VPlanTestBase.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| namespace { | ||
| class VPUncountableExitTest : public VPlanTestIRBase {}; | ||
|
|
||
| TEST_F(VPUncountableExitTest, FindUncountableExitRecipes) { | ||
| const char *ModuleString = | ||
| "define void @f(ptr %array, ptr %pred) {\n" | ||
| "entry:\n" | ||
| " br label %for.body\n" | ||
| "for.body:\n" | ||
| " %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.inc ]\n" | ||
| " %st.addr = getelementptr inbounds i16, ptr %array, i64 %iv\n" | ||
| " %data = load i16, ptr %st.addr, align 2\n" | ||
| " %inc = add nsw i16 %data, 1\n" | ||
| " store i16 %inc, ptr %st.addr, align 2\n" | ||
| " %uncountable.addr = getelementptr inbounds nuw i16, ptr %pred, i64 " | ||
| "%iv\n" | ||
| " %uncountable.val = load i16, ptr %uncountable.addr, align 2\n" | ||
| " %uncountable.cond = icmp sgt i16 %uncountable.val, 500\n" | ||
| " br i1 %uncountable.cond, label %exit, label %for.inc\n" | ||
| "for.inc:\n" | ||
| " %iv.next = add nuw nsw i64 %iv, 1\n" | ||
| " %countable.cond = icmp eq i64 %iv.next, 20\n" | ||
| " br i1 %countable.cond, label %exit, label %for.body\n" | ||
| "exit:\n" | ||
| " ret void\n" | ||
| "}\n"; | ||
|
|
||
| Module &M = parseModule(ModuleString); | ||
|
|
||
| Function *F = M.getFunction("f"); | ||
| BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); | ||
| auto Plan = buildVPlan(LoopHeader, /*HasUncountableExit=*/true); | ||
| VPlanTransforms::tryToConvertVPInstructionsToVPRecipes( | ||
| Plan, [](PHINode *P) { return nullptr; }, *TLI); | ||
| VPlanTransforms::runPass(VPlanTransforms::optimize, *Plan); | ||
|
|
||
| SmallVector<VPRecipeBase *> Recipes; | ||
| SmallVector<VPRecipeBase *> GEPs; | ||
|
|
||
| std::optional<VPValue *> UncountableCondition = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would also be good to add a test without an early exit, to make sure that code path is also covered by the test
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| vputils::getRecipesForUncountableExit(*Plan, Recipes, GEPs); | ||
| ASSERT_TRUE(UncountableCondition.has_value()); | ||
| ASSERT_EQ(GEPs.size(), 1ull); | ||
| ASSERT_EQ(Recipes.size(), 3ull); | ||
| } | ||
|
|
||
| TEST_F(VPUncountableExitTest, NoUncountableExit) { | ||
| const char *ModuleString = | ||
| "define void @f(ptr %array, ptr %pred) {\n" | ||
| "entry:\n" | ||
| " br label %for.body\n" | ||
| "for.body:\n" | ||
| " %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]\n" | ||
| " %st.addr = getelementptr inbounds i16, ptr %array, i64 %iv\n" | ||
| " %data = load i16, ptr %st.addr, align 2\n" | ||
| " %inc = add nsw i16 %data, 1\n" | ||
| " store i16 %inc, ptr %st.addr, align 2\n" | ||
| " %iv.next = add nuw nsw i64 %iv, 1\n" | ||
| " %countable.cond = icmp eq i64 %iv.next, 20\n" | ||
| " br i1 %countable.cond, label %exit, label %for.body\n" | ||
| "exit:\n" | ||
| " ret void\n" | ||
| "}\n"; | ||
|
|
||
| Module &M = parseModule(ModuleString); | ||
|
|
||
| Function *F = M.getFunction("f"); | ||
| BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor(); | ||
| auto Plan = buildVPlan(LoopHeader); | ||
| VPlanTransforms::tryToConvertVPInstructionsToVPRecipes( | ||
| Plan, [](PHINode *P) { return nullptr; }, *TLI); | ||
| VPlanTransforms::runPass(VPlanTransforms::optimize, *Plan); | ||
|
|
||
| SmallVector<VPRecipeBase *> Recipes; | ||
| SmallVector<VPRecipeBase *> GEPs; | ||
|
|
||
| std::optional<VPValue *> UncountableCondition = | ||
| vputils::getRecipesForUncountableExit(*Plan, Recipes, GEPs); | ||
| ASSERT_FALSE(UncountableCondition.has_value()); | ||
| ASSERT_EQ(GEPs.size(), 0ull); | ||
| ASSERT_EQ(Recipes.size(), 0ull); | ||
| } | ||
|
|
||
| } // namespace | ||
| } // namespace llvm | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IR above suggests we've already called
handleUncountableEarlyExitand so this probably should be// Successor(s): middle.splitThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The transform PR explicitly avoids creating the split, since we won't have finished all iterations before leaving the vector body.