Skip to content

[IVDesc] Unify RecurKinds [I|F]AnyOf #118393

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 1 commit into from
May 23, 2025
Merged

Conversation

artagnon
Copy link
Contributor

@artagnon artagnon commented Dec 2, 2024

No description provided.

@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Dec 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2024

@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-llvm-analysis

Author: Ramkumar Ramachandra (artagnon)

Changes

Checking RecurKind::FAnyOf in isRecurrenceDescriptor() is wasted work when it already checks RecurKind::IAnyOf. Affect a minor adjustment to the code to facilitate skipping the RecurKind::FAnyOf check, and strip the check. The patch has the side-effect of rewriting some flaky code, which would match an ICmp having the reduction phi as an operand with IAnyOf, and due to NumCmpSelectPatternInst != 1 (the select redux is also matched), it would have to rely on failing to match an FCmp with FAnyOf, setting NumCmpSelectPatternInst = 1, and successfully vectorizing an IAnyOf pattern with the incorrect debug output. There is a test for this already in select-cmp.ll: select_i32_from_icmp_same_inputs.


Full diff: https://github.com/llvm/llvm-project/pull/118393.diff

1 Files Affected:

  • (modified) llvm/lib/Analysis/IVDescriptors.cpp (+6-15)
diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp
index 23e11bdbeab4c5..9678fcdcbd7c0e 100644
--- a/llvm/lib/Analysis/IVDescriptors.cpp
+++ b/llvm/lib/Analysis/IVDescriptors.cpp
@@ -415,12 +415,9 @@ bool RecurrenceDescriptor::AddReductionVar(
     if (IsAPhi && Cur != Phi && !areAllUsesIn(Cur, VisitedInsts))
       return false;
 
-    if ((isIntMinMaxRecurrenceKind(Kind) || Kind == RecurKind::IAnyOf) &&
-        (isa<ICmpInst>(Cur) || isa<SelectInst>(Cur)))
-      ++NumCmpSelectPatternInst;
-    if ((isFPMinMaxRecurrenceKind(Kind) || Kind == RecurKind::FAnyOf) &&
-        (isa<FCmpInst>(Cur) || isa<SelectInst>(Cur)))
-      ++NumCmpSelectPatternInst;
+    if (isIntMinMaxRecurrenceKind(Kind) || isAnyOfRecurrenceKind(Kind))
+      if (match(Cur, m_Select(m_Cmp(), m_Value(), m_Value())))
+        ++NumCmpSelectPatternInst;
 
     // Check  whether we found a reduction operator.
     FoundReduxOp |= !IsAPhi && Cur != Start;
@@ -500,7 +497,7 @@ bool RecurrenceDescriptor::AddReductionVar(
   // This means we have seen one but not the other instruction of the
   // pattern or more than just a select and cmp. Zero implies that we saw a
   // llvm.min/max intrinsic, which is always OK.
-  if (isMinMaxRecurrenceKind(Kind) && NumCmpSelectPatternInst != 2 &&
+  if (isMinMaxRecurrenceKind(Kind) && NumCmpSelectPatternInst != 1 &&
       NumCmpSelectPatternInst != 0)
     return false;
 
@@ -889,8 +886,8 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
   }
   if (AddReductionVar(Phi, RecurKind::IAnyOf, TheLoop, FMF, RedDes, DB, AC, DT,
                       SE)) {
-    LLVM_DEBUG(dbgs() << "Found an integer conditional select reduction PHI."
-                      << *Phi << "\n");
+    LLVM_DEBUG(dbgs() << "Found an conditional select reduction PHI." << *Phi
+                      << "\n");
     return true;
   }
   if (AddReductionVar(Phi, RecurKind::FMul, TheLoop, FMF, RedDes, DB, AC, DT,
@@ -913,12 +910,6 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
     LLVM_DEBUG(dbgs() << "Found a float MIN reduction PHI." << *Phi << "\n");
     return true;
   }
-  if (AddReductionVar(Phi, RecurKind::FAnyOf, TheLoop, FMF, RedDes, DB, AC, DT,
-                      SE)) {
-    LLVM_DEBUG(dbgs() << "Found a float conditional select reduction PHI."
-                      << " PHI." << *Phi << "\n");
-    return true;
-  }
   if (AddReductionVar(Phi, RecurKind::FMulAdd, TheLoop, FMF, RedDes, DB, AC, DT,
                       SE)) {
     LLVM_DEBUG(dbgs() << "Found an FMulAdd reduction PHI." << *Phi << "\n");

Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

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

This effectively makes FAnyOf dead, right? In that case it should be removed and IAnyOf -> AnyOf?

@artagnon
Copy link
Contributor Author

artagnon commented Dec 3, 2024

This effectively makes FAnyOf dead, right? In that case it should be removed and IAnyOf -> AnyOf?

There is still FAnyOf matching with FCmp, and IAnyOf matching with ICmp, so I don't think it can be removed. See getReductionOpChain's call to getOpcode for example.

See also the return statement in isAnyOfPattern:

  return InstDesc(I, isa<ICmpInst>(I->getOperand(0)) ? RecurKind::IAnyOf
                                                     : RecurKind::FAnyOf);

@david-arm
Copy link
Contributor

This effectively makes FAnyOf dead, right? In that case it should be removed and IAnyOf -> AnyOf?

There is still FAnyOf matching with FCmp, and IAnyOf matching with ICmp, so I don't think it can be removed. See getReductionOpChain's call to getOpcode for example.

See also the return statement in isAnyOfPattern:

  return InstDesc(I, isa<ICmpInst>(I->getOperand(0)) ? RecurKind::IAnyOf
                                                     : RecurKind::FAnyOf);

I agree with @fhahn. Looking at the code after this patch lands there is no logical reason for distinguishing between IAnyOf and FAnyOf. You should be able to condense the two RecurKind types into a single AnyOf I think. When creating InstDesc you just always initialise it with RecurKind::AnyOf and in isAnyOfRecurrenceKind just check for AnyOf. It looks like the only place we actually distinguish between the two is in RecurrenceDescriptor::getOpcode, but you can probably infer the opcode from the type?

@david-arm
Copy link
Contributor

Also, I think if this patch is fixing a bug (which you implied from the commit message) then it probably shouldn't have NFC in the title or commit message? That sounds like a functional change.

@artagnon artagnon changed the title IVDescriptors: cut wasteful FAnyOf checking (NFC) IVDescriptors: cut wasteful FAnyOf checking Dec 3, 2024
@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from 8ce79f5 to b70d6e3 Compare December 3, 2024 11:36
@artagnon artagnon changed the title IVDescriptors: cut wasteful FAnyOf checking IVDescriptors: unify RecurKinds IAnyOf and FAnyOf Dec 3, 2024
@artagnon
Copy link
Contributor Author

artagnon commented Dec 3, 2024

This effectively makes FAnyOf dead, right? In that case it should be removed and IAnyOf -> AnyOf?

There is still FAnyOf matching with FCmp, and IAnyOf matching with ICmp, so I don't think it can be removed. See getReductionOpChain's call to getOpcode for example.
See also the return statement in isAnyOfPattern:

  return InstDesc(I, isa<ICmpInst>(I->getOperand(0)) ? RecurKind::IAnyOf
                                                     : RecurKind::FAnyOf);

I agree with @fhahn. Looking at the code after this patch lands there is no logical reason for distinguishing between IAnyOf and FAnyOf. You should be able to condense the two RecurKind types into a single AnyOf I think. When creating InstDesc you just always initialise it with RecurKind::AnyOf and in isAnyOfRecurrenceKind just check for AnyOf. It looks like the only place we actually distinguish between the two is in RecurrenceDescriptor::getOpcode, but you can probably infer the opcode from the type?

Thanks, both. FAnyOf has now been stripped altogether, and IAnyOf has been renamed to AnyOf.

@artagnon artagnon changed the title IVDescriptors: unify RecurKinds IAnyOf and FAnyOf IVDesc: unify RecurKinds IAnyOf and FAnyOf Dec 3, 2024
@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from b70d6e3 to 05ee143 Compare December 3, 2024 15:49
@artagnon
Copy link
Contributor Author

artagnon commented Dec 3, 2024

Rebased.

Copy link
Contributor

@Mel-Chen Mel-Chen left a comment

Choose a reason for hiding this comment

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

Thanks your contribution. I've done a rough review of this patch for now. On Thursday, I’ll conduct a more detailed review since I won’t be in the office this Wednesday.
I'm not sure if this is the issue you discovered. (The main patch of this pre-commit might have been lost.)
https://reviews.llvm.org/D157375
We had an internal discussion later and found that this case should be vectorizable in the form of an AnyOf reduction.

@artagnon
Copy link
Contributor Author

artagnon commented Dec 3, 2024

I'm not sure if this is the issue you discovered. (The main patch of this pre-commit might have been lost.)
https://reviews.llvm.org/D157375

Yes, it's the same issue, and there's a test for it in the tree, as the commit message mentions.

Copy link
Contributor

@Mel-Chen Mel-Chen left a comment

Choose a reason for hiding this comment

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

I support unification AnyOf.
But I don't think non-arithmetical reduction (min/max, AnyOf, FindLast...etc.) needs getOpcode. I think a better approach is to remove the dependence of non-arithmetical reduction on getOpcode and then start to unify AnyOf.
Here is my first step #118777.

@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from 71d0bc8 to 2c387ce Compare December 16, 2024 10:43
Copy link
Contributor

@Mel-Chen Mel-Chen left a comment

Choose a reason for hiding this comment

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

This is not NFC since getOpcode() returned different result from before.

@artagnon artagnon closed this Jan 14, 2025
@artagnon artagnon deleted the ivdesc-fanyof-strip branch January 14, 2025 16:54
@Mel-Chen
Copy link
Contributor

@artagnon
Sorry, I had to use strong way to prevent the merge of this patch because I was out of the office yesterday and couldn't respond.

The purpose of this PR is really good, and I think it should continue, but my concern is that the approach and results are incorrect.

I believe the real reason we cannot unify IAnyOf and FAnyOf is due to getOpcode(). In vectorizer, there are still many cases where getOpcode() is called unnecessarily, even though the execution path should not require it. Generally, getOpcode() should only have a meaningful effect for arithmetic reductions.

Earlier, I identified the locations where getOpcode() is currently being called: (the line numbers might be outdated because this information has been sitting in my notebook for about a month).

/scratch/melc/llvm-project/llvm/lib/Analysis/IVDescriptors.cpp:1066:30: #118777 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:553:37
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2133:53:
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2144:53:
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2181:78:
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2193:39:
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2231:67:
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp:2253:70: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:4874:57: preferInLoopReduction should pass kind
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:5860:27: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:5884:34: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:5922:27: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:5930:41: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7026:41: 
/scratch/melc/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:9486:57: preferPredicatedReductionSelect should pass kind
llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: 19360 [done] #122239 
llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: 20515 [look nice]

Because I've been busy with EVL tail folding, the cleanup may proceed slowly. Welcome your contribution If you’re willing and interested. Then we can continue this patch after we finish the clean up. :)

@artagnon artagnon restored the ivdesc-fanyof-strip branch January 16, 2025 12:26
@artagnon artagnon reopened this Jan 16, 2025
@artagnon artagnon marked this pull request as draft January 16, 2025 12:29
Copy link
Collaborator

@ayalz ayalz left a comment

Choose a reason for hiding this comment

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

Adding some thoughts raised by this unification effort.

Mel-Chen added a commit that referenced this pull request Apr 7, 2025
This patch changes the preferInLoopReduction function to take a
RecurKind instead of an unsigned Opcode.
This makes it possible to distinguish non-arithmetic reductions such as
min/max, AnyOf, and FindLastIV, and also helps unify IAnyOf with FAnyOf
and IFindLastIV with FFindLastIV.

Related patch #118393 #131830
Mel-Chen added a commit that referenced this pull request May 19, 2025
…ctionResult, nfc (#140245)

When reducing unrolled parts, explicitly check for min/max reductions
using the function RecurrenceDescriptor::isMinMaxRecurrenceKind. Only if
the reduction is not min/max reduction, call
RecurrenceDescriptor::getOpcode() to handle other cases via CreateBinOp.

Based on #140242
Related to #118393
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 19, 2025
…ComputeReductionResult, nfc (#140245)

When reducing unrolled parts, explicitly check for min/max reductions
using the function RecurrenceDescriptor::isMinMaxRecurrenceKind. Only if
the reduction is not min/max reduction, call
RecurrenceDescriptor::getOpcode() to handle other cases via CreateBinOp.

Based on llvm/llvm-project#140242
Related to llvm/llvm-project#118393
@Mel-Chen
Copy link
Contributor

@artagnon I think you can re-open and continue this work.

@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from af86167 to c9b44e9 Compare May 22, 2025 13:16
@artagnon artagnon marked this pull request as ready for review May 22, 2025 13:16
@artagnon
Copy link
Contributor Author

Thanks @Mel-Chen for the prerequisite work. This patch should be ready to review now.

@artagnon artagnon changed the title IVDesc: unify RecurKinds IAnyOf and FAnyOf [IVDesc] Unify RecurKinds IAnyOf and FAnyOf May 22, 2025
@artagnon artagnon changed the title [IVDesc] Unify RecurKinds IAnyOf and FAnyOf [IVDesc] Unify RecurKinds [I|F]AnyOf (NFC) May 22, 2025
@artagnon artagnon changed the title [IVDesc] Unify RecurKinds [I|F]AnyOf (NFC) [IVDesc] Unify RecurKinds [I|F]AnyOf May 22, 2025
@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from c740737 to 89e1f95 Compare May 22, 2025 18:16
Checking RecurKind::FAnyOf in isRecurrenceDescriptor() is wasted work
when it already checks RecurKind::IAnyOf. Affect a minor adjustment to
the code to facilitate skipping the RecurKind::FAnyOf check, and strip
the check. The patch has the side-effect of rewriting some flaky code,
which would match an ICmp having the reduction phi as an operand with
IAnyOf, and due to NumCmpSelectPatternInst != 1 (the select redux is
also matched), it would have to rely on failing to match an FCmp with
FAnyOf, setting NumCmpSelectPatternInst = 1, and successfully
vectorizing an IAnyOf pattern with the incorrect debug output. There is
a test for this already in select-cmp.ll:
select_i32_from_icmp_same_inputs.

Co-authored-by: Mel Chen <[email protected]>
@artagnon artagnon force-pushed the ivdesc-fanyof-strip branch from 89e1f95 to 7ddb7dd Compare May 23, 2025 08:30
Copy link
Contributor

@Mel-Chen Mel-Chen left a comment

Choose a reason for hiding this comment

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

LGTM
Maybe it's worth updating the patch description?

Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

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

LGTM, thanks

@artagnon artagnon merged commit 0240129 into llvm:main May 23, 2025
11 checks passed
@artagnon artagnon deleted the ivdesc-fanyof-strip branch May 23, 2025 10:57
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 6, 2025
…ctionResult, nfc (llvm#140245)

When reducing unrolled parts, explicitly check for min/max reductions
using the function RecurrenceDescriptor::isMinMaxRecurrenceKind. Only if
the reduction is not min/max reduction, call
RecurrenceDescriptor::getOpcode() to handle other cases via CreateBinOp.

Based on llvm#140242
Related to llvm#118393
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 backend:RISC-V llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms vectorizers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants