-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Polly] Add vectorize metadata to loops identified as vectorizable by polly #113994
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
Conversation
… polly This patch introduces the initial implementation for annotating loops created by Polly. Polly generates RunTimeChecks (RTCs), which result in loop versioning. Specifically, the loop created by Polly is executed when the RTCs pass, otherwise, the original loop is executed. This patch adds the "llvm.loop.vectorize.enable" metadata, setting it to true for loops created by Polly. It also disables vectorization for the original fallback loop. This behavior is controlled by the 'polly-annotate-metadata-vectorize' flag, and the annotations are applied only when this flag is enabled. This flag is set to false by default. NOTE: This commit is initial patch in effort to make polly interact with Loop Vectorizer via metadata.
✅ With the latest revision this PR passed the C/C++ code formatter. |
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.
Thanks for the PR
Did you check whether LoopVectorize is also going to vectorize the loop without its own RTC check?
Co-authored-by: Michael Kruse <[email protected]>
Thanks for reviewing the patch. |
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.
This patch adds the metadata, setting it to true for loops created by Polly.
"llvm.loop.vectorize.enable" set to true will just ignore loop-vectorizer's cost heursitic, and vectorize any loop that is semantically legal to do. Being processed by Polly doesn't mean it becomes automatically profitable to vectorizer, and LoopVectorize would still vectorize it if it thinks it is beneficial without the metadata, which currently also only applies to innermost loops.
Also consider that Clang emits a warning when LoopVectorizer does not apply on a loop with "llvm.loop.vectorize.enable" set to true. Users using Polly would get a lot such warnings.
What are the long-term plans? Atm it is only okay-ish because this behaviour is disabled by a flag.
polly/lib/CodeGen/IRBuilder.cpp
Outdated
void ScopAnnotator::annotateLoopLatch(BranchInst *B, Loop *L, bool IsParallel, | ||
bool IsLoopVectorizerDisabled) const { | ||
bool setVectorizeMetadata, |
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.
bool setVectorizeMetadata, | |
bool SetVectorizeMetadata, |
Could add a doxygen comment on what the parameters mean?
I am getting confused with the flag combinations. Since its terrnary logic, consider std::optional<bool> EnableLoopVectorizer
where std::nullopt
means no metadata set.
polly/lib/CodeGen/LoopGenerators.cpp
Outdated
Annotator->annotateLoopLatch(B, NewLoop, Parallel, true, | ||
!LoopVectDisabled); | ||
else if (LoopVectDisabled) | ||
Annotator->annotateLoopLatch(B, NewLoop, Parallel, true, false); |
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.
Annotator->annotateLoopLatch(B, NewLoop, Parallel, true, false); | |
Annotator->annotateLoopLatch(B, NewLoop, Parallel, /*SetVectorizeMetadata=*/true, /*EnableLoopVectorizer=*/false); |
but why not:
if (Annotator)
Annotator->annotateLoopLatch(B, NewLoop, Parallel, /*SetVectorizeMetadata=*/PollyVectorizeMetadata||LoopVectDisabled, /*EnableLoopVectorizer=*/!LoopVectDisabled&&!PollyVectorizeMetadata);
or at least
else
Annotator->annotateLoopLatch(B, NewLoop, Parallel, /*SetVectorizeMetadata=*/LoopVectDisabled, /*EnableLoopVectorizer=*/false);
like before this commit
polly/lib/CodeGen/LoopGenerators.cpp
Outdated
Annotator->annotateLoopLatch(B, NewLoop, Parallel, LoopVectDisabled); | ||
|
||
// If the 'polly-annotate-metadata-vectorize' flag is passed, we add | ||
// the vectorize metadata. Otherwise we fall back to previous behavior |
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.
"previous behavior" referes to this commit. That does not make sense if you see this comment only in the source.
polly/lib/CodeGen/CodeGeneration.cpp
Outdated
// loop when 'polly-annotate-metadata-vectorize' is passed. | ||
if (PollyVectorizeMetadata) { | ||
for (Loop *L : LI.getLoopsInPreorder()) { | ||
if (S.contains(L)) { |
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.
if (S.contains(L)) { | |
if (!S.contains(L)) | |
continue; |
polly/lib/CodeGen/CodeGeneration.cpp
Outdated
for (BasicBlock *ControlBB : LoopLatchBlocks) { | ||
BranchInst *Br = dyn_cast<BranchInst>(ControlBB->getTerminator()); | ||
if (Br) | ||
Annotator.annotateLoopLatch(Br, L, false, true, false); |
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.
Why not directly calling addVectorizeMetadata
here? The ScopAnnotator was design with the assumption to be called on generated code only. Using it outside of it may result in unexpected situations.
Co-authored-by: Michael Kruse <[email protected]>
polly/lib/CodeGen/IRBuilder.cpp
Outdated
@@ -128,8 +128,28 @@ void ScopAnnotator::popLoop(bool IsParallel) { | |||
LoopAttrEnv.pop_back(); | |||
} | |||
|
|||
void ScopAnnotator::annotateLoopLatch(BranchInst *B, Loop *L, bool IsParallel, | |||
bool IsLoopVectorizerDisabled) const { | |||
void ScopAnnotator::addVectorizeMetadata(LLVMContext &Ctx, |
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.
void ScopAnnotator::addVectorizeMetadata(LLVMContext &Ctx, | |
static void addVectorizeMetadata(LLVMContext &Ctx, |
AFICS this does not use any ScopAnnotator
members
polly/lib/CodeGen/CodeGeneration.cpp
Outdated
// for the code flow taken when RTCs fail. Because we don't want the | ||
// Loop Vectorizer to come in later and vectorize the original fall back | ||
// loop when 'polly-annotate-metadata-vectorize' is passed. | ||
if (PollyVectorizeMetadata) { |
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.
if (PollyVectorizeMetadata) { |
I'd be fine if the loop vectorizer is always disabled for fallback code. Would it means too many test updates?
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.
I am seeing around 19 failures.
Should we have it as separate patch.
Or can it be part of this patch itself ?
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.
@Meinersbur Please provide inputs on if we have to add the test case changes for 19 failures as separate patch.
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.
You can add the test changes into PR. If that's too much work I'd accept the -polly-annotate-metadata-vectorize
opt-in as well.
polly/lib/CodeGen/IRBuilder.cpp
Outdated
// Last argument is optional, if no value is passed, we don't annotate | ||
// any vectorize metadata. |
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.
Interface descriptions usually go to the declaration in the header files as Doxygen comment (/// @param EnableVectorizeMetadata If no value is passed, we don't annotate any vectorize metadata.
)
polly/lib/CodeGen/LoopGenerators.cpp
Outdated
if (!LoopVectDisabled && !PollyVectorizeMetadata) | ||
Annotator->annotateLoopLatch(B, Parallel); | ||
else | ||
Annotator->annotateLoopLatch( | ||
B, Parallel, | ||
/*EnableVectorizeMetadata*/ !LoopVectDisabled && | ||
PollyVectorizeMetadata); |
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.
if (!LoopVectDisabled && !PollyVectorizeMetadata) | |
Annotator->annotateLoopLatch(B, Parallel); | |
else | |
Annotator->annotateLoopLatch( | |
B, Parallel, | |
/*EnableVectorizeMetadata*/ !LoopVectDisabled && | |
PollyVectorizeMetadata); | |
std::optional<bool> EnableVectorizeMetadata; | |
if (LoopVectDisabled) | |
EnableVectorizeMetadata = false; | |
else if (PollyVectorizeMetadata) | |
EnableVectorizeMetadata = true; | |
Annotator->annotateLoopLatch(B, Parallel, EnableVectorizeMetadata); |
If I got the boolean logic correct
polly/lib/CodeGen/CodeGeneration.cpp
Outdated
LLVMContext &Ctx = S.getFunction().getContext(); | ||
for (Loop *L : LI.getLoopsInPreorder()) { | ||
if (!L || !S.contains(L)) | ||
continue; | ||
MDNode *LoopID = L->getLoopID(); | ||
SmallVector<Metadata *, 3> Args; | ||
if (LoopID) | ||
for (unsigned i = 0, e = LoopID->getNumOperands(); i != e; ++i) | ||
Args.push_back(LoopID->getOperand(i)); | ||
else | ||
Args.push_back(nullptr); | ||
|
||
Annotator.addVectorizeMetadata(Ctx, &Args, false); | ||
MDNode *NewLoopID = MDNode::get(Ctx, Args); | ||
NewLoopID->replaceOperandWith(0, NewLoopID); | ||
L->setLoopID(NewLoopID); | ||
} |
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.
LLVMContext &Ctx = S.getFunction().getContext(); | |
for (Loop *L : LI.getLoopsInPreorder()) { | |
if (!L || !S.contains(L)) | |
continue; | |
MDNode *LoopID = L->getLoopID(); | |
SmallVector<Metadata *, 3> Args; | |
if (LoopID) | |
for (unsigned i = 0, e = LoopID->getNumOperands(); i != e; ++i) | |
Args.push_back(LoopID->getOperand(i)); | |
else | |
Args.push_back(nullptr); | |
Annotator.addVectorizeMetadata(Ctx, &Args, false); | |
MDNode *NewLoopID = MDNode::get(Ctx, Args); | |
NewLoopID->replaceOperandWith(0, NewLoopID); | |
L->setLoopID(NewLoopID); | |
} | |
#include "llvm/Transforms/Utils/LoopUtils.h" | |
LLVMContext &Ctx = S.getFunction().getContext(); | |
for (Loop *L : LI.getLoopsInPreorder()) { | |
if (!S.contains(L)) | |
continue; | |
addStringMetadataToLoop(L, "llvm.loop.vectorize.enable", 0) | |
} |
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.
A small query here ..
Using addStringMetadataToLoop API makes the value get set as i32.
Something like
!2 = !{!"llvm.loop.vectorize.enable", i32 0}
Though the behavior is same, Is it okay, as the value should be i1 according to LangRef.rst?
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.
It does not make a difference:
unsigned Val = C->getZExtValue(); |
Args->push_back(MDNode::get(Ctx, {PropName, PropValue})); | ||
} | ||
|
||
void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args, |
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.
void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args, | |
static void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args, |
This patch is an initial step in our long-term plan to enhance Polly’s support for the Loop Vectorizer. We are currently evaluating various representative workloads with this patch to identify any gaps, such as instances where Polly is causing the Loop Vectorizer to vectorize unprofitable loops. We are using performance and loop coverage metrics for this evaluation. Ultimately, we aim to implement more constraints on Polly’s side before enabling the metadata that forces vectorization, rather than applying it to all loops created by Polly as we do now. |
@Meinersbur @efriedma-quic |
I think it's fine to just push the remaining changes here, since the goal here still hasn't changed. |
Ping for review @Meinersbur |
ping @Meinersbur |
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.
I'd prefer -polly-annotate-metadata-vectorize
always-on which requires regression test changes. If you can do that it would be great, but the patch is already fine as-is, so LGTM.
Thanks for the review @Meinersbur. The plan is to enable the flag by default in future.
|
This patch introduces the initial implementation for annotating loops created by Polly. Polly generates RunTimeChecks (RTCs), which result in loop versioning. Specifically, the loop created by Polly is executed when the RTCs pass, otherwise, the original loop is executed.
This patch adds the "llvm.loop.vectorize.enable" metadata, setting it to true for loops created by Polly. It also disables vectorization for the original fallback loop.
This behavior is controlled by the 'polly-annotate-metadata-vectorize' flag, and the annotations are applied only when this flag is enabled. This flag is set to false by default.
NOTE: This commit is initial patch in effort to make polly interact with Loop Vectorizer via metadata.