Skip to content

[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

Merged
merged 11 commits into from
Jan 22, 2025

Conversation

kartcq
Copy link
Contributor

@kartcq kartcq commented Oct 29, 2024

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.

… 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.
Copy link

github-actions bot commented Oct 29, 2024

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

Copy link
Member

@Meinersbur Meinersbur 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 the PR

Did you check whether LoopVectorize is also going to vectorize the loop without its own RTC check?

@kartcq
Copy link
Contributor Author

kartcq commented Oct 30, 2024

Thanks for the PR

Did you check whether LoopVectorize is also going to vectorize the loop without its own RTC check?

Thanks for reviewing the patch.
For now the answer is no, LoopVectorizer will still create RTCs. We are only preventing the fall back original loop by polly from getting versioned/vectorized by LoopVectorizer. But eventually the goal is to remove such common checks and append only if there are any additional checks from Loop Vectorizer.

Copy link
Member

@Meinersbur Meinersbur left a 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.

void ScopAnnotator::annotateLoopLatch(BranchInst *B, Loop *L, bool IsParallel,
bool IsLoopVectorizerDisabled) const {
bool setVectorizeMetadata,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
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.

Annotator->annotateLoopLatch(B, NewLoop, Parallel, true,
!LoopVectDisabled);
else if (LoopVectDisabled)
Annotator->annotateLoopLatch(B, NewLoop, Parallel, true, false);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
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

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
Copy link
Member

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.

// loop when 'polly-annotate-metadata-vectorize' is passed.
if (PollyVectorizeMetadata) {
for (Loop *L : LI.getLoopsInPreorder()) {
if (S.contains(L)) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (S.contains(L)) {
if (!S.contains(L))
continue;

Coding standard

for (BasicBlock *ControlBB : LoopLatchBlocks) {
BranchInst *Br = dyn_cast<BranchInst>(ControlBB->getTerminator());
if (Br)
Annotator.annotateLoopLatch(Br, L, false, true, false);
Copy link
Member

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.

@@ -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,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
void ScopAnnotator::addVectorizeMetadata(LLVMContext &Ctx,
static void addVectorizeMetadata(LLVMContext &Ctx,

AFICS this does not use any ScopAnnotator members

// 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) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (PollyVectorizeMetadata) {

I'd be fine if the loop vectorizer is always disabled for fallback code. Would it means too many test updates?

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 seeing around 19 failures.
Should we have it as separate patch.
Or can it be part of this patch itself ?

Copy link
Contributor Author

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.

Copy link
Member

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.

Comment on lines 148 to 149
// Last argument is optional, if no value is passed, we don't annotate
// any vectorize metadata.
Copy link
Member

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.)

Comment on lines 171 to 177
if (!LoopVectDisabled && !PollyVectorizeMetadata)
Annotator->annotateLoopLatch(B, Parallel);
else
Annotator->annotateLoopLatch(
B, Parallel,
/*EnableVectorizeMetadata*/ !LoopVectDisabled &&
PollyVectorizeMetadata);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
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

Comment on lines 246 to 262
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);
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
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)
}

Copy link
Contributor Author

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?

Copy link
Member

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:

Args->push_back(MDNode::get(Ctx, {PropName, PropValue}));
}

void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args,
static void addParallelMetadata(LLVMContext &Ctx, SmallVector<Metadata *, 3> *Args,

@kartcq
Copy link
Contributor Author

kartcq commented Nov 5, 2024

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.

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.

@kartcq
Copy link
Contributor Author

kartcq commented Dec 16, 2024

@Meinersbur @efriedma-quic
Part of this PR is merged in #119188.
For the remaining changes should I modify changes here or create a new PR.
Please provide your suggestions.

@efriedma-quic
Copy link
Collaborator

I think it's fine to just push the remaining changes here, since the goal here still hasn't changed.

@kartcq
Copy link
Contributor Author

kartcq commented Jan 2, 2025

Ping for review @Meinersbur

@kartcq
Copy link
Contributor Author

kartcq commented Jan 10, 2025

ping @Meinersbur

Copy link
Member

@Meinersbur Meinersbur left a 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.

@kartcq
Copy link
Contributor Author

kartcq commented Jan 22, 2025

Thanks for the review @Meinersbur. The plan is to enable the flag by default in future.
Merging the patch as is for now.

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.

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.

@kartcq kartcq merged commit 76672e3 into llvm:main Jan 22, 2025
8 checks passed
@kartcq kartcq deleted the codegen branch April 16, 2025 07:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants