Skip to content

[NFC][Scalarizer][TargetTransformInfo] Add isVectorIntrinsicWithOverloadTypeAtArg api #114849

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 10 commits into from
Nov 21, 2024

Conversation

inbelic
Copy link
Contributor

@inbelic inbelic commented Nov 4, 2024

This changes allows target intrinsic to specify and overwrite overloaded types.

This change will let us add scalarization for asdouble: #114847

…loadTypeAtArg`

This changes allows target intrinsic to specify overloaded types.

This change will let us add scalarization for `asdouble`:
- change code pattern to avoid calling TTI if we don't have a target
specific intrinsics
  - change type from unsigned to int
@llvmbot
Copy link
Member

llvmbot commented Nov 4, 2024

@llvm/pr-subscribers-vectorizers
@llvm/pr-subscribers-llvm-analysis
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-backend-directx

Author: Finn Plummer (inbelic)

Changes

This changes allows target intrinsic to specify and overwrite overloaded types.

This change will let us add scalarization for asdouble: #114847


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

7 Files Affected:

  • (modified) llvm/include/llvm/Analysis/TargetTransformInfo.h (+10)
  • (modified) llvm/include/llvm/Analysis/TargetTransformInfoImpl.h (+5)
  • (modified) llvm/include/llvm/CodeGen/BasicTTIImpl.h (+5)
  • (modified) llvm/lib/Analysis/TargetTransformInfo.cpp (+5)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp (+8)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h (+2)
  • (modified) llvm/lib/Transforms/Scalar/Scalarizer.cpp (+11-3)
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index 0459941fe05cdc..26fa20be184383 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -896,6 +896,9 @@ class TargetTransformInfo {
   bool isTargetIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,
                                           unsigned ScalarOpdIdx) const;
 
+  bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                              int ScalarOpdIdx) const;
+
   /// Estimate the overhead of scalarizing an instruction. Insert and Extract
   /// are set if the demanded result elements need to be inserted and/or
   /// extracted from vectors.
@@ -1969,6 +1972,8 @@ class TargetTransformInfo::Concept {
   virtual bool isTargetIntrinsicTriviallyScalarizable(Intrinsic::ID ID) = 0;
   virtual bool isTargetIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,
                                                   unsigned ScalarOpdIdx) = 0;
+  virtual bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                                      int ScalarOpdIdx) = 0;
   virtual InstructionCost getScalarizationOverhead(VectorType *Ty,
                                                    const APInt &DemandedElts,
                                                    bool Insert, bool Extract,
@@ -2530,6 +2535,11 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
     return Impl.isTargetIntrinsicWithScalarOpAtArg(ID, ScalarOpdIdx);
   }
 
+  bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                              int ScalarOpdIdx) override {
+    return Impl.isVectorIntrinsicWithOverloadTypeAtArg(ID, ScalarOpdIdx);
+  }
+
   InstructionCost getScalarizationOverhead(VectorType *Ty,
                                            const APInt &DemandedElts,
                                            bool Insert, bool Extract,
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index dbdfb4d8cdfa32..dd76e0b8dc8a21 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -392,6 +392,11 @@ class TargetTransformInfoImplBase {
     return false;
   }
 
+  bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                              int ScalarOpdIdx) const {
+    return ScalarOpdIdx == -1;
+  }
+
   InstructionCost getScalarizationOverhead(VectorType *Ty,
                                            const APInt &DemandedElts,
                                            bool Insert, bool Extract,
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index db3b5cddd7c1c3..3ec63c095f7c9a 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -798,6 +798,11 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
     return false;
   }
 
+  bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                              int ScalarOpdIdx) const {
+    return ScalarOpdIdx == -1;
+  }
+
   /// Helper wrapper for the DemandedElts variant of getScalarizationOverhead.
   InstructionCost getScalarizationOverhead(VectorType *InTy, bool Insert,
                                            bool Extract,
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index a47462b61e03b2..f79348d27e78ff 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -612,6 +612,11 @@ bool TargetTransformInfo::isTargetIntrinsicWithScalarOpAtArg(
   return TTIImpl->isTargetIntrinsicWithScalarOpAtArg(ID, ScalarOpdIdx);
 }
 
+bool TargetTransformInfo::isVectorIntrinsicWithOverloadTypeAtArg(
+    Intrinsic::ID ID, int ScalarOpdIdx) const {
+  return TTIImpl->isVectorIntrinsicWithOverloadTypeAtArg(ID, ScalarOpdIdx);
+}
+
 InstructionCost TargetTransformInfo::getScalarizationOverhead(
     VectorType *Ty, const APInt &DemandedElts, bool Insert, bool Extract,
     TTI::TargetCostKind CostKind) const {
diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
index 231afd8ae3eeaf..1c54887d9f56e2 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
@@ -25,6 +25,14 @@ bool DirectXTTIImpl::isTargetIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,
   }
 }
 
+bool DirectXTTIImpl::isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                                            int ScalarOpdIdx) {
+  switch (ID) {
+  default:
+    return ScalarOpdIdx == -1;
+  }
+}
+
 bool DirectXTTIImpl::isTargetIntrinsicTriviallyScalarizable(
     Intrinsic::ID ID) const {
   switch (ID) {
diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
index 30b57ed97d6370..a18e4a28625756 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
+++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
@@ -37,6 +37,8 @@ class DirectXTTIImpl : public BasicTTIImplBase<DirectXTTIImpl> {
   bool isTargetIntrinsicTriviallyScalarizable(Intrinsic::ID ID) const;
   bool isTargetIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,
                                           unsigned ScalarOpdIdx);
+  bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                              int ScalarOpdIdx);
 };
 } // namespace llvm
 
diff --git a/llvm/lib/Transforms/Scalar/Scalarizer.cpp b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
index 772f4c6c35ddec..1c61aa2712e8c7 100644
--- a/llvm/lib/Transforms/Scalar/Scalarizer.cpp
+++ b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
@@ -280,6 +280,7 @@ class ScalarizerVisitor : public InstVisitor<ScalarizerVisitor, bool> {
   bool visit(Function &F);
 
   bool isTriviallyScalarizable(Intrinsic::ID ID);
+  bool isIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID, int ScalarOpdIdx);
 
   // InstVisitor methods.  They return true if the instruction was scalarized,
   // false if nothing changed.
@@ -696,6 +697,13 @@ bool ScalarizerVisitor::isTriviallyScalarizable(Intrinsic::ID ID) {
          TTI->isTargetIntrinsicTriviallyScalarizable(ID);
 }
 
+bool ScalarizerVisitor::isIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
+                                                         int ScalarOpdIdx) {
+  return Intrinsic::isTargetIntrinsic(ID)
+             ? TTI->isVectorIntrinsicWithOverloadTypeAtArg(ID, ScalarOpdIdx)
+             : isVectorIntrinsicWithOverloadTypeAtArg(ID, ScalarOpdIdx);
+}
+
 /// If a call to a vector typed intrinsic function, split into a scalar call per
 /// element if possible for the intrinsic.
 bool ScalarizerVisitor::splitCall(CallInst &CI) {
@@ -727,7 +735,7 @@ bool ScalarizerVisitor::splitCall(CallInst &CI) {
 
   SmallVector<llvm::Type *, 3> Tys;
   // Add return type if intrinsic is overloaded on it.
-  if (isVectorIntrinsicWithOverloadTypeAtArg(ID, -1))
+  if (isIntrinsicWithOverloadTypeAtArg(ID, -1))
     Tys.push_back(VS->SplitTy);
 
   if (AreAllVectorsOfMatchingSize) {
@@ -767,13 +775,13 @@ bool ScalarizerVisitor::splitCall(CallInst &CI) {
       }
 
       Scattered[I] = scatter(&CI, OpI, *OpVS);
-      if (isVectorIntrinsicWithOverloadTypeAtArg(ID, I)) {
+      if (isIntrinsicWithOverloadTypeAtArg(ID, I)) {
         OverloadIdx[I] = Tys.size();
         Tys.push_back(OpVS->SplitTy);
       }
     } else {
       ScalarOperands[I] = OpI;
-      if (isVectorIntrinsicWithOverloadTypeAtArg(ID, I))
+      if (isIntrinsicWithOverloadTypeAtArg(ID, I))
         Tys.push_back(OpI->getType());
     }
   }

Copy link
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

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

This feels like a partial change which leaves us in an odd state.

Instead of cleaning up all the uses of the VectorUtils isVectorIntrinsicWithOverloadTypeAtArg, you only updated the uses in the Scalarizer, which in turn makes the Scalarizer's implementation a bit odd.

farzonl

This comment was marked as outdated.

@inbelic
Copy link
Contributor Author

inbelic commented Nov 6, 2024

Hmm, okay. Are you suggesting that we should replace all the uses or that we can't do such a change?

Having looked at the other uses of isVectorIntrinsicWithOverloadTypeAtArg, they don't appear to have access to any target transform info ( eg SLPVectorizer/ReplaceWithVeclib) so I don't think there is a way forward to replace all the uses.

@farzonl
Copy link
Member

farzonl commented Nov 6, 2024

This feels like a partial change which leaves us in an odd state.

Instead of cleaning up all the uses of the VectorUtils isVectorIntrinsicWithOverloadTypeAtArg, you only updated the uses in the Scalarizer, which in turn makes the Scalarizer's implementation a bit odd.

@llvm-beanz I think I misunderstood what you were asking. We aren't implementing the TTI for all of VectorUtils. We don't have tests for target intrinsics that are vectorizable. Maybe one day it makes sense to add them for SPIRV? But for DirectX keeping these changes in the Scalairzer is our path forward. It looks like @inbelic did update all the Scalairzer uses.

@llvm-beanz
Copy link
Collaborator

@llvm-beanz I think I misunderstood what you were asking. We aren't implementing the TTI for all of VectorUtils.
I was not asking you to do that. I understand this is just one method.

We don't have tests for target intrinsics that are vectorizable. Maybe one day it makes sense to add them for SPIRV? But for DirectX keeping these changes in the Scalairzer is our path forward. It looks like @inbelic did update all the Scalairzer uses.

I'm also unsure how this relates to my comment.

This change partially moves isVectorIntrinsicWithOverloadTypeAtArg from VectorUtils to TTI. It doesn't completely move it, it just half moves it... That seems like a really odd place to leave the code. The SLPVectorizer or VPlanRecipes not having TTI is a solvable problem.

It seems to me that we should have one way to query isVectorIntrinsicWithOverloadTypeAtArg across all passes, not two.

(cc @bogner)

- consolidate the usage of isVectorIntrinsicWithOverloadTypeAtArg into
one place of VectorUtils.cppp
@@ -152,7 +152,8 @@ bool isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,

/// Identifies if the vector form of the intrinsic is overloaded on the type of
/// the operand at index \p OpdIdx, or on the return type if \p OpdIdx is -1.
bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID, int OpdIdx);
bool isVectorIntrinsicWithOverloadTypeAtArg(
Intrinsic::ID ID, int OpdIdx, const TargetTransformInfo *TTI = nullptr);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could also do with an std::optional pointer here, not sure on what is preferred.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this should be optional. In any case where this argument matters it would be a bug to not pass it.

@bogner
Copy link
Contributor

bogner commented Nov 13, 2024

We really should be updating the other users of the isVectorIntrinsicWithOverloadTypeAtArg API to be passing in the TTI, or at least explicitly opting out of it if it makes sense. I think we should not have a default nullptr for the TTI argument here, as that makes it easy to misuse.

As for updating the vectorizer uses:

  • SLPVectorizer should be easy to do, since the pass already uses TTI elsewhere
  • VPlanRecipes is probably also not too hard, as it looks like TTI is used in some places there as well
  • ReplaceWithVeclib would need to add a dependency on TTI. It might be okay to have that one pass in a null TTI though, since a target specific vectorizable function probably isn't going to be replaced with a generic vector library function anyway.

@bogner bogner self-requested a review November 13, 2024 22:58
@farzonl
Copy link
Member

farzonl commented Nov 13, 2024

We really should be updating the other users of the isVectorIntrinsicWithOverloadTypeAtArg API to be passing in the TTI, or at least explicitly opting out of it if it makes sense. I think we should not have a default nullptr for the TTI argument here, as that makes it easy to misuse.

As for updating the vectorizer uses:

  • SLPVectorizer should be easy to do, since the pass already uses TTI elsewhere
  • VPlanRecipes is probably also not too hard, as it looks like TTI is used in some places there as well
  • ReplaceWithVeclib would need to add a dependency on TTI. It might be okay to have that one pass in a null TTI though, since a target specific vectorizable function probably isn't going to be replaced with a generic vector library function anyway.

Does it make sense to make a few issues for this and let this pr go in as is? I started this pattern with some of the other isVectorIntrinsic functions so feels like the cleanup should cover all the functions.

@llvm-beanz
Copy link
Collaborator

Does it make sense to make a few issues for this and let this pr go in as is? I started this pattern with some of the other isVectorIntrinsic functions so feels like the cleanup should cover all the functions.

It seems clear to me that we should file issues to fix the other cases, but I don't see why we would merge this one, then just have to clean it up. This is an NFC change, having the NFC refactoring end up in the correct end state seems better to me.

- this pass is used to replace a vectorizable intrinsic function with a
generic veclib function
- we make the assumption that a target specific intrinisc is not going
to be replaced with a generic function call and so we don't need to
provide the TTI
- use the already defined TTI as the argument
- pass down the TTI from the LoopVectorizationPlanner into the
VPTransformState
- this will allow this information to all VPRecipe::execute functions
when they generate new IR
- use the updated VPTransformState to pass down the TTI
@@ -110,15 +110,17 @@ static bool replaceWithCallToVeclib(const TargetLibraryInfo &TLI,

// OloadTys collects types used in scalar intrinsic overload name.
SmallVector<Type *, 3> OloadTys;
if (!RetTy->isVoidTy() && isVectorIntrinsicWithOverloadTypeAtArg(IID, -1))
if (!RetTy->isVoidTy() &&
isVectorIntrinsicWithOverloadTypeAtArg(IID, -1, /*TTI=*/nullptr))
Copy link
Contributor Author

@inbelic inbelic Nov 15, 2024

Choose a reason for hiding this comment

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

Regarding adding a dependency on the TargetTransformInfo analysis pass to retrieve TTI. There is currently no intrinsic that would execute and use TTI in isVectorIntrinsicWithOverloadTypeAtArg. While I don't expect the pass is expensive to do, it is currently completely unnecessary work. So I think it is okay to defer until there is an actual use case. Which as mentioned, seems unlikely.

Copy link
Contributor

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

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

I have a comment suggestion you might consider, but looks good otherwise.

switch (ID) {
default:
return ScalarOpdIdx == -1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In case anyone else wonders why the switch statement is here, observe the follow-on in #114847

@@ -152,7 +152,8 @@ bool isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID,

/// Identifies if the vector form of the intrinsic is overloaded on the type of
/// the operand at index \p OpdIdx, or on the return type if \p OpdIdx is -1.
Copy link
Contributor

Choose a reason for hiding this comment

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

You may wish to update this comment to mention the new parameter. As many places as this function is implemented at different levels and as confusing as I initially found the name of it, it might be worth copying this to at least a few of the places that it and it's facilitators are declared/defined.

Copy link

github-actions bot commented Nov 20, 2024

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

@inbelic inbelic merged commit 8663b87 into llvm:main Nov 21, 2024
8 checks passed
@inbelic inbelic deleted the inbelic/scalarizer-overload-types branch November 25, 2024 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

6 participants