[llvm] [TTI][RISCV][SLP] Add IdentityConstantValue option to OperandValueKind for use by SLP and RISCV (PR #228630)

Ryan Buchner via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 2 18:28:10 PDT 2026


https://github.com/bababuck created https://github.com/llvm/llvm-project/pull/228630

SLP uses this now when generating `OperandValueInfo` for operands.

RISCV can cost for a `vid_v` instruction rather than a constant pool load for such cases, matching final codegen.

Assisted By: Codex

>From 09e79b7a3a0fcf7cdbf66661e1c47299d2f6c1f4 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Fri, 2 Oct 2026 14:48:13 -0700
Subject: [PATCH] [TTI][RISCV][SLP] Add IdentityConstantValue option to
 OperandValueKind

SLP uses this now when generating OperandValueInfo for operands.

RISCV can cost for a vid_v instruction rather than a constatn pool load for such cases.
---
 .../llvm/Analysis/TargetTransformInfo.h       |  6 ++++-
 .../Target/RISCV/RISCVTargetTransformInfo.cpp | 17 +++++++++++++
 .../Target/RISCV/RISCVTargetTransformInfo.h   |  9 +++++++
 .../Transforms/Vectorize/SLPVectorizer.cpp    |  6 +++++
 .../SLPVectorizer/RISCV/load-store.ll         |  8 +-----
 .../RISCV/reordered-buildvector-scalars.ll    | 25 ++++++++++---------
 6 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index a33e6f62e941ed..ecbb68297f728d 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -1324,6 +1324,7 @@ class TargetTransformInfo {
     OK_AnyValue,               // Operand can have any value.
     OK_UniformValue,           // Operand is uniform (splat of a value).
     OK_UniformConstantValue,   // Operand is uniform constant.
+    OK_IdentityConstantValue,  // Operand is the identity vector (0, 1, ...)
     OK_NonUniformConstantValue // Operand is a non uniform constant value.
   };
 
@@ -1342,11 +1343,14 @@ class TargetTransformInfo {
     OperandValueProperties Properties = OP_None;
 
     bool isConstant() const {
-      return Kind == OK_UniformConstantValue || Kind == OK_NonUniformConstantValue;
+      return Kind == OK_UniformConstantValue ||
+             Kind == OK_NonUniformConstantValue ||
+             Kind == OK_IdentityConstantValue;
     }
     bool isUniform() const {
       return Kind == OK_UniformConstantValue || Kind == OK_UniformValue;
     }
+    bool isIdentityConstant() const { return Kind == OK_IdentityConstantValue; }
     bool isPowerOf2() const {
       return Properties == OP_PowerOf2;
     }
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 69554ca2b81555..f57dc104f68bc5 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -50,6 +50,14 @@ static cl::opt<unsigned>
 static cl::opt<bool> EnableOrLikeSelectOpt("enable-riscv-or-like-select",
                                            cl::init(true), cl::Hidden);
 
+InstructionCost
+RISCVTTIImpl::getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, Type *Tp,
+                                      TTI::TargetCostKind CostKind) const {
+  std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Tp);
+  // Note: Asuming all vdot4a* variants are equal cost
+  return LT.first * getRISCVInstructionCost(OpCodes, LT.second, CostKind);
+}
+
 InstructionCost
 RISCVTTIImpl::getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
                                       TTI::TargetCostKind CostKind) const {
@@ -2517,6 +2525,9 @@ RISCVTTIImpl::getStoreImmCost(Type *Ty, TTI::OperandValueInfo OpInfo,
     // with how we treat scalar constants themselves just above.
     return 1;
 
+  if (OpInfo.isIdentityConstant())
+    return getRISCVInstructionCost(RISCV::VID_V, Ty, CostKind);
+
   return getConstantPoolLoadCost(Ty, CostKind);
 }
 
@@ -2591,6 +2602,9 @@ InstructionCost RISCVTTIImpl::getCmpSelInstrCost(
       // constants in GPRs.
       return 0;
 
+    if (OpInfo.isIdentityConstant())
+      return getRISCVInstructionCost(RISCV::VID_V, ValTy, CostKind);
+
     return getConstantPoolLoadCost(ValTy, CostKind);
   };
 
@@ -3032,6 +3046,9 @@ InstructionCost RISCVTTIImpl::getArithmeticInstrCost(
       // scalar constants in GPRs.
       return 0;
 
+    if (OpInfo.isIdentityConstant())
+      return getRISCVInstructionCost(RISCV::VID_V, Ty, CostKind);
+
     return getConstantPoolLoadCost(Ty, CostKind);
   };
 
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
index 2d179479565b5d..ac90956df3ab83 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
@@ -58,6 +58,15 @@ class RISCVTTIImpl final : public BasicTTIImplBase<RISCVTTIImpl> {
   InstructionCost getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
                                           TTI::TargetCostKind CostKind) const;
 
+  /// This function calculates the costs for one or more RVV opcodes based
+  /// on the type and the cost kind.
+  /// \param Opcodes A list of opcodes of the RVV instruction to evaluate.
+  /// \param Tp The Type associated with the RVV instructions. Will be legalized
+  /// and the result multiplied by the legalization cost;
+  /// \param CostKind The type of cost to compute.
+  InstructionCost getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, Type *Tp,
+                                          TTI::TargetCostKind CostKind) const;
+
   // Return the cost of generating a PC relative address
   InstructionCost
   getStaticDataAddrGenerationCost(const TTI::TargetCostKind CostKind) const;
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 601791da524006..10884ce95cb3e9 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13671,10 +13671,16 @@ TTI::OperandValueInfo BoUpSLP::getOperandInfo(ArrayRef<Value *> Ops) const {
       return CI->getValue().isNegatedPowerOf2();
     return false;
   });
+  const bool IsIdentity = all_of(enumerate(Ops), [&](const auto &Data) {
+    auto *CI = llvm::dyn_cast<llvm::ConstantInt>(Data.value());
+    return CI && CI->getLimitedValue() == Data.index();
+  });
 
   TTI::OperandValueKind VK = TTI::OK_AnyValue;
   if (IsConstant && IsUniform)
     VK = TTI::OK_UniformConstantValue;
+  else if (IsIdentity)
+    VK = TTI::OK_IdentityConstantValue;
   else if (IsConstant)
     VK = TTI::OK_NonUniformConstantValue;
   else if (IsUniform)
diff --git a/llvm/test/Transforms/SLPVectorizer/RISCV/load-store.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/load-store.ll
index 604695cb05b3a5..5b4622dc051508 100644
--- a/llvm/test/Transforms/SLPVectorizer/RISCV/load-store.ll
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/load-store.ll
@@ -148,13 +148,7 @@ entry:
 define void @store_stepvector_i32(ptr %dest) {
 ; CHECK-LABEL: @store_stepvector_i32(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    store i32 0, ptr [[DEST:%.*]], align 4
-; CHECK-NEXT:    [[INC1:%.*]] = getelementptr inbounds i32, ptr [[DEST]], i64 1
-; CHECK-NEXT:    store i32 1, ptr [[INC1]], align 2
-; CHECK-NEXT:    [[INC2:%.*]] = getelementptr inbounds i32, ptr [[DEST]], i64 2
-; CHECK-NEXT:    store i32 2, ptr [[INC2]], align 2
-; CHECK-NEXT:    [[INC3:%.*]] = getelementptr inbounds i32, ptr [[DEST]], i64 3
-; CHECK-NEXT:    store i32 3, ptr [[INC3]], align 2
+; CHECK-NEXT:    store <4 x i32> <i32 0, i32 1, i32 2, i32 3>, ptr [[DEST:%.*]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
diff --git a/llvm/test/Transforms/SLPVectorizer/RISCV/reordered-buildvector-scalars.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/reordered-buildvector-scalars.ll
index 2d6ef587f764ff..91881a816463a5 100644
--- a/llvm/test/Transforms/SLPVectorizer/RISCV/reordered-buildvector-scalars.ll
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/reordered-buildvector-scalars.ll
@@ -12,22 +12,27 @@ define fastcc i32 @test(i32 %0, i32 %add111.i.i, <4 x i32> %PredPel.i.sroa.86.72
 ; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[ADD111_I_I:%.*]], <4 x i32> [[PREDPEL_I_SROA_86_72_VEC_EXTRACT:%.*]], <4 x i32> [[TMP1:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[MUL1445_I:%.*]] = shl i32 [[TMP0]], 1
+; CHECK-NEXT:    [[PREDPEL_I_SROA_7_4_VEC_EXTRACT446:%.*]] = extractelement <4 x i32> [[TMP1]], i64 0
 ; CHECK-NEXT:    [[ADD2235_I17:%.*]] = or i32 [[TMP0]], 1
 ; CHECK-NEXT:    [[ADD1392_I:%.*]] = add i32 [[TMP0]], 1
-; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <3 x i32> poison, i32 [[ADD111_I_I]], i64 0
-; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <3 x i32> poison, i32 [[TMP0]], i64 0
-; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <3 x i32> [[TMP3]], <3 x i32> poison, <3 x i32> zeroinitializer
-; CHECK-NEXT:    [[LOOPARRAY_SROA_24_0_I_I3:%.*]] = ashr i32 [[TMP0]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x i32> poison, i32 [[TMP0]], i64 0
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP4:%.*]] = add <2 x i32> [[TMP3]], <i32 0, i32 1>
+; CHECK-NEXT:    [[TMP20:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 0>
 ; CHECK-NEXT:    [[SHR143_5_I_I9:%.*]] = ashr i32 [[TMP0]], 1
-; CHECK-NEXT:    [[ADD1392_I1:%.*]] = add i32 [[TMP0]], 1
-; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <3 x i32> [[TMP2]], i32 [[LOOPARRAY_SROA_24_0_I_I3]], i64 1
+; CHECK-NEXT:    [[TMP32:%.*]] = ashr <4 x i32> [[TMP20]], <i32 1, i32 0, i32 0, i32 1>
+; CHECK-NEXT:    [[TMP21:%.*]] = insertelement <3 x i32> poison, i32 [[ADD111_I_I]], i64 0
+; CHECK-NEXT:    [[TMP31:%.*]] = shufflevector <4 x i32> [[TMP32]], <4 x i32> poison, <3 x i32> <i32 0, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP33:%.*]] = shufflevector <3 x i32> [[TMP21]], <3 x i32> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 poison>
+; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP33]], <4 x i32> [[TMP32]], <3 x i32> <i32 0, i32 4, i32 poison>
 ; CHECK-NEXT:    [[TMP30:%.*]] = insertelement <3 x i32> [[TMP5]], i32 [[ADD1392_I]], i64 2
+; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> poison, <3 x i32> zeroinitializer
 ; CHECK-NEXT:    [[TMP7:%.*]] = or <3 x i32> [[TMP30]], [[TMP6]]
-; CHECK-NEXT:    [[TMP8:%.*]] = shufflevector <4 x i32> [[PREDPEL_I_SROA_86_72_VEC_EXTRACT]], <4 x i32> [[TMP1]], <8 x i32> <i32 0, i32 poison, i32 poison, i32 4, i32 poison, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP8:%.*]] = shufflevector <4 x i32> [[PREDPEL_I_SROA_86_72_VEC_EXTRACT]], <4 x i32> [[TMP32]], <8 x i32> <i32 0, i32 poison, i32 4, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
 ; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <8 x i32> [[TMP8]], i32 [[TMP0]], i64 4
 ; CHECK-NEXT:    [[TMP10:%.*]] = insertelement <8 x i32> [[TMP9]], i32 [[ADD111_I_I]], i64 6
 ; CHECK-NEXT:    [[TMP11:%.*]] = insertelement <8 x i32> [[TMP10]], i32 [[ADD2235_I17]], i64 1
-; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <8 x i32> [[TMP11]], i32 [[LOOPARRAY_SROA_24_0_I_I3]], i64 2
+; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <8 x i32> [[TMP11]], i32 [[PREDPEL_I_SROA_7_4_VEC_EXTRACT446]], i64 3
 ; CHECK-NEXT:    [[TMP13:%.*]] = insertelement <8 x i32> [[TMP12]], i32 [[MUL1445_I]], i64 5
 ; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <8 x i32> [[TMP13]], i32 [[SHR143_5_I_I9]], i64 7
 ; CHECK-NEXT:    [[TMP15:%.*]] = add <8 x i32> [[TMP14]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 2, i32 1, i32 1>
@@ -35,10 +40,6 @@ define fastcc i32 @test(i32 %0, i32 %add111.i.i, <4 x i32> %PredPel.i.sroa.86.72
 ; CHECK-NEXT:    [[TMP17:%.*]] = shufflevector <3 x i32> [[TMP7]], <3 x i32> poison, <11 x i32> <i32 0, i32 1, i32 2, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
 ; CHECK-NEXT:    [[TMP18:%.*]] = shufflevector <11 x i32> [[TMP16]], <11 x i32> [[TMP17]], <11 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 11, i32 12, i32 13>
 ; CHECK-NEXT:    [[TMP19:%.*]] = lshr <11 x i32> [[TMP18]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 2, i32 1, i32 1, i32 1, i32 1, i32 1>
-; CHECK-NEXT:    [[TMP20:%.*]] = insertelement <4 x i32> poison, i32 [[TMP0]], i64 2
-; CHECK-NEXT:    [[TMP21:%.*]] = insertelement <4 x i32> [[TMP20]], i32 [[LOOPARRAY_SROA_24_0_I_I3]], i64 0
-; CHECK-NEXT:    [[TMP31:%.*]] = insertelement <4 x i32> [[TMP21]], i32 [[ADD1392_I1]], i64 1
-; CHECK-NEXT:    [[TMP32:%.*]] = insertelement <4 x i32> [[TMP31]], i32 [[SHR143_5_I_I9]], i64 3
 ; CHECK-NEXT:    [[TMP22:%.*]] = or <4 x i32> [[TMP32]], splat (i32 1)
 ; CHECK-NEXT:    [[TMP23:%.*]] = shufflevector <3 x i32> [[TMP6]], <3 x i32> poison, <4 x i32> zeroinitializer
 ; CHECK-NEXT:    [[TMP24:%.*]] = add <4 x i32> [[TMP22]], [[TMP23]]



More information about the llvm-commits mailing list