[llvm-branch-commits] [llvm] release/23.x: [SLP]Fix narrow-tree gate width and extract miscount (PR #217569)
Karthika Devi C via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 26 05:37:40 PDT 2026
https://github.com/kartcq updated https://github.com/llvm/llvm-project/pull/217569
>From 177f0a9dbd154183327c99700a276f81aa18553d Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Tue, 18 Aug 2026 07:50:55 -0400
Subject: [PATCH 1/2] [SLP]Fix narrow-tree gate width and extract miscount
Measure the narrowness of in-loop trees by the actual vectorization
width instead of the feeder-load width, and skip vector-typed scalars
in the instruction count check to match the cost model.
Fixes #216715
Reviewers: efriedma-quic, bababuck, RKSimon, kartcq
Pull Request: https://github.com/llvm/llvm-project/pull/216797
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 19 ++-
.../AArch64/abs-mul-buildvector-in-loop.ll | 111 ++++++++++++++++++
.../AArch64/long-non-power-of-2.ll | 6 +-
.../X86/deleted-instructions-clear.ll | 10 +-
.../multi-parent-instr-copyable-regular.ll | 14 ++-
5 files changed, 145 insertions(+), 15 deletions(-)
create mode 100644 llvm/test/Transforms/SLPVectorizer/AArch64/abs-mul-buildvector-in-loop.ll
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 80091308116f7..9bf48c489d949 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13991,6 +13991,12 @@ unsigned BoUpSLP::getNumVectorInsts() const {
continue;
if (EU.User && EphValues.count(EU.User))
continue;
+ // Vector-typed scalars are consumed as whole vectors, no extract
+ // instruction is emitted for them.
+ if (isVectorizedTy(EU.Scalar->getType()) &&
+ (!SLPReVec ||
+ (EU.E.hasState() && EU.E.getOpcode() == Instruction::InsertElement)))
+ continue;
if (ExternalUsesAsOriginalScalar.contains(EU.Scalar))
continue;
if (!CountedExtracts.insert(EU.Scalar).second)
@@ -19457,8 +19463,17 @@ BoUpSLP::calculateTreeCostAndTrimNonProfitable(ArrayRef<Value *> VectorizedVals,
return Cost;
// The narrow non-profitable tree in loop? Skip, may cause regressions.
constexpr unsigned PartLimit = 2;
- const unsigned Sz =
- getVectorElementSize(VectorizableTree.front()->Scalars.front());
+ // Measure the narrowness by the width the tree is vectorized at.
+ const TreeEntry *RootTE = VectorizableTree.front().get();
+ unsigned Sz;
+ if (auto It = MinBWs.find(RootTE); It != MinBWs.end()) {
+ Sz = It->second.first;
+ } else {
+ Sz = std::max<unsigned>(
+ getVectorElementSize(RootTE->Scalars.front()),
+ DL->getTypeSizeInBits(
+ getValueType(RootTE->Scalars.front())->getScalarType()));
+ }
const unsigned MinVF = getMinVF(Sz);
if (Cost >= -SLPCostThreshold &&
VectorizableTree.front()->Scalars.size() * PartLimit <= MinVF &&
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/abs-mul-buildvector-in-loop.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/abs-mul-buildvector-in-loop.ll
new file mode 100644
index 0000000000000..1d1616698fc17
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/abs-mul-buildvector-in-loop.ll
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S --passes=slp-vectorizer -mtriple=aarch64-linux-gnu -mcpu=cortex-a57 < %s | FileCheck %s
+
+ at lut = external constant [0 x i8]
+
+define void @test(ptr noalias %src, ptr noalias %descriptor, i32 %N) {
+; CHECK-LABEL: define void @test(
+; CHECK-SAME: ptr noalias [[SRC:%.*]], ptr noalias [[DESCRIPTOR:%.*]], i32 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[CMP32:%.*]] = icmp sgt i32 [[N]], 0
+; CHECK-NEXT: br i1 [[CMP32]], label %[[FOR_BODY:.*]], label %[[FOR_COND_CLEANUP:.*]]
+; CHECK: [[FOR_COND_CLEANUP]]:
+; CHECK-NEXT: ret void
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: [[SRC_ADDR_035:%.*]] = phi ptr [ [[ARRAYIDX:%.*]], %[[FOR_BODY]] ], [ [[SRC]], %[[ENTRY]] ]
+; CHECK-NEXT: [[P_034:%.*]] = phi ptr [ [[INCDEC_PTR10:%.*]], %[[FOR_BODY]] ], [ @lut, %[[ENTRY]] ]
+; CHECK-NEXT: [[I_033:%.*]] = phi i32 [ [[INC:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: [[ARRAYIDX]] = getelementptr inbounds nuw i8, ptr [[SRC_ADDR_035]], i64 1
+; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[SRC_ADDR_035]], i64 -1
+; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
+; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC_ADDR_035]], i64 17
+; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ARRAYIDX3]], align 1
+; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds i8, ptr [[SRC_ADDR_035]], i64 -17
+; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX5]], align 1
+; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[P_034]], align 1
+; CHECK-NEXT: [[CONV9:%.*]] = zext i8 [[TMP4]] to i32
+; CHECK-NEXT: [[INCDEC_PTR10]] = getelementptr inbounds nuw i8, ptr [[P_034]], i64 2
+; CHECK-NEXT: [[BIN:%.*]] = getelementptr inbounds nuw i8, ptr [[P_034]], i64 1
+; CHECK-NEXT: [[TMP5:%.*]] = load i8, ptr [[BIN]], align 1
+; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[TMP5]] to i64
+; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw [4 x i8], ptr [[DESCRIPTOR]], i64 [[IDX_EXT]]
+; CHECK-NEXT: [[CONV4:%.*]] = zext i8 [[TMP2]] to i32
+; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32
+; CHECK-NEXT: [[CONV6:%.*]] = zext i8 [[TMP3]] to i32
+; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[TMP1]] to i32
+; CHECK-NEXT: [[SUB7:%.*]] = sub nsw i32 [[CONV4]], [[CONV6]]
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[CONV]], [[CONV2]]
+; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[SUB]], i64 0
+; CHECK-NEXT: [[TMP7:%.*]] = insertelement <2 x i32> [[TMP6]], i32 [[SUB7]], i64 1
+; CHECK-NEXT: [[TMP15:%.*]] = insertelement <2 x i32> poison, i32 [[CONV9]], i64 0
+; CHECK-NEXT: [[TMP9:%.*]] = shufflevector <2 x i32> [[TMP15]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP10:%.*]] = mul nsw <2 x i32> [[TMP7]], [[TMP9]]
+; CHECK-NEXT: [[TMP11:%.*]] = call <2 x i32> @llvm.abs.v2i32(<2 x i32> [[TMP10]], i1 true)
+; CHECK-NEXT: [[TMP8:%.*]] = load <4 x i32>, ptr [[ADD_PTR]], align 4
+; CHECK-NEXT: [[TMP16:%.*]] = shufflevector <2 x i32> [[TMP10]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP14:%.*]] = shufflevector <2 x i32> [[TMP11]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <4 x i32> [[TMP16]], <4 x i32> [[TMP14]], <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+; CHECK-NEXT: [[TMP13:%.*]] = add nsw <4 x i32> [[TMP8]], [[TMP12]]
+; CHECK-NEXT: store <4 x i32> [[TMP13]], ptr [[ADD_PTR]], align 4
+; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_033]], 1
+; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]]
+; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]]
+;
+entry:
+ %cmp32 = icmp sgt i32 %N, 0
+ br i1 %cmp32, label %for.body, label %for.cond.cleanup
+
+for.cond.cleanup:
+ ret void
+
+for.body:
+ %src.addr.035 = phi ptr [ %arrayidx, %for.body ], [ %src, %entry ]
+ %p.034 = phi ptr [ %incdec.ptr10, %for.body ], [ @lut, %entry ]
+ %i.033 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds nuw i8, ptr %src.addr.035, i64 1
+ %0 = load i8, ptr %arrayidx, align 1
+ %conv = zext i8 %0 to i32
+ %arrayidx1 = getelementptr inbounds i8, ptr %src.addr.035, i64 -1
+ %1 = load i8, ptr %arrayidx1, align 1
+ %conv2 = zext i8 %1 to i32
+ %sub = sub nsw i32 %conv, %conv2
+ %arrayidx3 = getelementptr inbounds nuw i8, ptr %src.addr.035, i64 17
+ %2 = load i8, ptr %arrayidx3, align 1
+ %conv4 = zext i8 %2 to i32
+ %arrayidx5 = getelementptr inbounds i8, ptr %src.addr.035, i64 -17
+ %3 = load i8, ptr %arrayidx5, align 1
+ %conv6 = zext i8 %3 to i32
+ %sub7 = sub nsw i32 %conv4, %conv6
+ %4 = load i8, ptr %p.034, align 1
+ %conv9 = zext i8 %4 to i32
+ %incdec.ptr10 = getelementptr inbounds nuw i8, ptr %p.034, i64 2
+ %bin = getelementptr inbounds nuw i8, ptr %p.034, i64 1
+ %5 = load i8, ptr %bin, align 1
+ %idx.ext = zext i8 %5 to i64
+ %add.ptr = getelementptr inbounds nuw [4 x i8], ptr %descriptor, i64 %idx.ext
+ %mul = mul nsw i32 %sub, %conv9
+ %mul12 = mul nsw i32 %sub7, %conv9
+ %6 = load i32, ptr %add.ptr, align 4
+ %add = add nsw i32 %6, %mul
+ store i32 %add, ptr %add.ptr, align 4
+ %arrayidx14 = getelementptr inbounds nuw i8, ptr %add.ptr, i64 4
+ %7 = load i32, ptr %arrayidx14, align 4
+ %add15 = add nsw i32 %7, %mul12
+ store i32 %add15, ptr %arrayidx14, align 4
+ %8 = tail call i32 @llvm.abs.i32(i32 %mul, i1 true)
+ %arrayidx16 = getelementptr inbounds nuw i8, ptr %add.ptr, i64 8
+ %9 = load i32, ptr %arrayidx16, align 4
+ %add17 = add nsw i32 %9, %8
+ store i32 %add17, ptr %arrayidx16, align 4
+ %10 = tail call i32 @llvm.abs.i32(i32 %mul12, i1 true)
+ %arrayidx18 = getelementptr inbounds nuw i8, ptr %add.ptr, i64 12
+ %11 = load i32, ptr %arrayidx18, align 4
+ %add19 = add nsw i32 %11, %10
+ store i32 %add19, ptr %arrayidx18, align 4
+ %inc = add nuw nsw i32 %i.033, 1
+ %exitcond.not = icmp eq i32 %inc, %N
+ br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
+}
+
+declare i32 @llvm.abs.i32(i32, i1 immarg)
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/long-non-power-of-2.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/long-non-power-of-2.ll
index e1ca81edd2b39..c6489c2085000 100644
--- a/llvm/test/Transforms/SLPVectorizer/AArch64/long-non-power-of-2.ll
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/long-non-power-of-2.ll
@@ -7,6 +7,8 @@ define i1 @test(ptr %arg, ptr %arg1, i64 %arg2, ptr %arg3) {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr i8, ptr [[ARG1]], i64 [[ARG2]]
; CHECK-NEXT: [[GETELEMENTPTR4:%.*]] = getelementptr i8, ptr null, i64 0
+; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x ptr> <ptr null, ptr poison>, ptr [[ARG3]], i64 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, <2 x ptr> [[TMP2]], <2 x i64> <i64 -32, i64 -432>
; CHECK-NEXT: [[GETELEMENTPTR5:%.*]] = getelementptr i8, ptr null, i64 -32
; CHECK-NEXT: [[TMP32:%.*]] = getelementptr i8, ptr [[ARG3]], i64 -440
; CHECK-NEXT: [[GETELEMENTPTR7:%.*]] = getelementptr i8, ptr [[ARG1]], i64 0
@@ -28,8 +30,8 @@ define i1 @test(ptr %arg, ptr %arg1, i64 %arg2, ptr %arg3) {
; CHECK-NEXT: [[AND25:%.*]] = and i1 false, [[ICMP24]]
; CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x ptr> <ptr poison, ptr poison, ptr null, ptr null>, ptr [[ARG]], i64 1
; CHECK-NEXT: [[TMP19:%.*]] = insertelement <4 x ptr> [[TMP0]], ptr [[GETELEMENTPTR7]], i64 0
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <4 x ptr> <ptr poison, ptr poison, ptr null, ptr null>, ptr [[GETELEMENTPTR5]], i64 0
-; CHECK-NEXT: [[TMP7:%.*]] = insertelement <4 x ptr> [[TMP2]], ptr [[GETELEMENTPTR8]], i64 1
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x ptr> [[TMP1]], <2 x ptr> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <4 x ptr> <ptr poison, ptr poison, ptr null, ptr null>, <4 x ptr> [[TMP4]], <4 x i32> <i32 4, i32 5, i32 2, i32 3>
; CHECK-NEXT: [[TMP20:%.*]] = icmp ult <4 x ptr> [[TMP19]], [[TMP7]]
; CHECK-NEXT: [[ICMP58:%.*]] = icmp ult ptr [[GETELEMENTPTR]], null
; CHECK-NEXT: [[ICMP62:%.*]] = icmp ult ptr [[GETELEMENTPTR]], null
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/deleted-instructions-clear.ll b/llvm/test/Transforms/SLPVectorizer/X86/deleted-instructions-clear.ll
index ae6da0913cc24..94631869b15fe 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/deleted-instructions-clear.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/deleted-instructions-clear.ll
@@ -7,7 +7,7 @@ define void @test(i32 %arg, i32 %arg1, i64 %arg2) {
; CHECK-NEXT: [[BB:.*]]:
; CHECK-NEXT: [[TMP11:%.*]] = insertelement <4 x i32> <i32 0, i32 0, i32 0, i32 poison>, i32 [[ARG]], i64 3
; CHECK-NEXT: [[TMP27:%.*]] = insertelement <2 x i32> poison, i32 [[ARG1]], i64 0
-; CHECK-NEXT: [[TMP28:%.*]] = shufflevector <2 x i32> [[TMP27]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP29:%.*]] = insertelement <2 x i32> <i32 0, i32 poison>, i32 [[ARG]], i64 1
; CHECK-NEXT: br label %[[BB3:.*]]
; CHECK: [[BB3]]:
; CHECK-NEXT: [[TMP3:%.*]] = phi i64 [ 0, %[[BB3]] ], [ 0, %[[BB]] ]
@@ -28,9 +28,9 @@ define void @test(i32 %arg, i32 %arg1, i64 %arg2) {
; CHECK-NEXT: [[OR11:%.*]] = or i32 [[TRUNC27]], 0
; CHECK-NEXT: [[TMP8:%.*]] = or <4 x i32> zeroinitializer, [[TMP2]]
; CHECK-NEXT: [[TMP9:%.*]] = mul <4 x i32> [[TMP5]], [[TMP8]]
-; CHECK-NEXT: [[XOR38:%.*]] = xor i32 [[ARG]], [[TRUNC28]]
-; CHECK-NEXT: [[TMP29:%.*]] = insertelement <2 x i32> <i32 poison, i32 0>, i32 [[TRUNC19]], i64 0
+; CHECK-NEXT: [[TMP28:%.*]] = insertelement <2 x i32> [[TMP27]], i32 [[TRUNC28]], i64 1
; CHECK-NEXT: [[TMP14:%.*]] = xor <2 x i32> [[TMP28]], [[TMP29]]
+; CHECK-NEXT: [[XOR31:%.*]] = xor i32 [[ARG1]], [[TRUNC19]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 0, 1
; CHECK-NEXT: [[TMP23:%.*]] = insertelement <4 x i32> poison, i32 [[SHL]], i64 0
; CHECK-NEXT: [[TMP31:%.*]] = insertelement <4 x i32> [[TMP23]], i32 [[TRUNC10]], i64 1
@@ -38,9 +38,9 @@ define void @test(i32 %arg, i32 %arg1, i64 %arg2) {
; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <4 x i32> [[TMP13]], <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 3>
; CHECK-NEXT: [[TMP26:%.*]] = xor <4 x i32> [[TMP11]], [[TMP25]]
; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <4 x i32> [[TMP26]], <4 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP32:%.*]] = insertelement <8 x i32> [[TMP24]], i32 [[XOR31]], i64 5
; CHECK-NEXT: [[TMP30:%.*]] = shufflevector <2 x i32> [[TMP14]], <2 x i32> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT: [[TMP15:%.*]] = shufflevector <8 x i32> [[TMP24]], <8 x i32> [[TMP30]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 8, i32 9, i32 7>
-; CHECK-NEXT: [[TMP16:%.*]] = insertelement <8 x i32> [[TMP15]], i32 [[XOR38]], i64 7
+; CHECK-NEXT: [[TMP16:%.*]] = shufflevector <8 x i32> [[TMP32]], <8 x i32> [[TMP30]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 8, i32 9>
; CHECK-NEXT: [[TMP17:%.*]] = shufflevector <8 x i32> [[TMP16]], <8 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 5, i32 6, i32 7>
; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <8 x i32> [[TMP17]], <8 x i32> poison, <12 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <4 x i32> [[TMP9]], <4 x i32> poison, <12 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/multi-parent-instr-copyable-regular.ll b/llvm/test/Transforms/SLPVectorizer/X86/multi-parent-instr-copyable-regular.ll
index d7ba46ff439a6..239bc9ed64dc1 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/multi-parent-instr-copyable-regular.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/multi-parent-instr-copyable-regular.ll
@@ -9,21 +9,23 @@ define void @test(ptr %0, ptr %1, ptr %2, ptr %3, double %4, double %5) {
; CHECK-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP1]], align 8
; CHECK-NEXT: [[TMP8:%.*]] = load double, ptr [[TMP0]], align 8
; CHECK-NEXT: [[TMP9:%.*]] = load double, ptr [[TMP2]], align 8
-; CHECK-NEXT: [[TMP15:%.*]] = fmul double [[TMP9]], 0.000000e+00
-; CHECK-NEXT: [[TMP16:%.*]] = fmul double [[TMP4]], 0.000000e+00
; CHECK-NEXT: [[TMP19:%.*]] = insertelement <4 x double> poison, double [[TMP4]], i64 0
; CHECK-NEXT: [[TMP11:%.*]] = insertelement <4 x double> [[TMP19]], double [[TMP5]], i64 1
; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <4 x double> [[TMP11]], <4 x double> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
; CHECK-NEXT: [[TMP13:%.*]] = insertelement <4 x double> <double 0.000000e+00, double 0.000000e+00, double 1.000000e+00, double poison>, double [[TMP4]], i64 3
; CHECK-NEXT: [[TMP14:%.*]] = fmul <4 x double> [[TMP12]], [[TMP13]]
-; CHECK-NEXT: [[TMP17:%.*]] = fmul double [[TMP15]], [[TMP8]]
-; CHECK-NEXT: [[TMP18:%.*]] = fmul double [[TMP9]], [[TMP16]]
+; CHECK-NEXT: [[TMP15:%.*]] = insertelement <2 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[TMP16:%.*]] = insertelement <2 x double> [[TMP15]], double [[TMP9]], i64 1
+; CHECK-NEXT: [[TMP17:%.*]] = fmul <2 x double> [[TMP16]], zeroinitializer
+; CHECK-NEXT: [[TMP18:%.*]] = insertelement <2 x double> poison, double [[TMP9]], i64 0
+; CHECK-NEXT: [[TMP35:%.*]] = insertelement <2 x double> [[TMP18]], double [[TMP8]], i64 1
+; CHECK-NEXT: [[TMP20:%.*]] = fmul <2 x double> [[TMP35]], [[TMP17]]
; CHECK-NEXT: [[TMP21:%.*]] = shufflevector <4 x double> [[TMP12]], <4 x double> <double 1.000000e+00, double 1.000000e+00, double poison, double poison>, <4 x i32> <i32 4, i32 5, i32 0, i32 0>
; CHECK-NEXT: [[TMP22:%.*]] = fmul <4 x double> [[TMP12]], [[TMP21]]
; CHECK-NEXT: [[TMP23:%.*]] = insertelement <4 x double> <double 0.000000e+00, double poison, double 1.000000e+00, double 0.000000e+00>, double [[TMP7]], i64 1
; CHECK-NEXT: [[TMP24:%.*]] = fmul <4 x double> [[TMP23]], [[TMP14]]
-; CHECK-NEXT: [[TMP25:%.*]] = insertelement <4 x double> [[TMP24]], double [[TMP18]], i64 0
-; CHECK-NEXT: [[TMP26:%.*]] = insertelement <4 x double> [[TMP25]], double [[TMP17]], i64 2
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP20]], <2 x double> poison, <4 x i32> <i32 0, i32 poison, i32 1, i32 poison>
+; CHECK-NEXT: [[TMP26:%.*]] = shufflevector <4 x double> [[TMP24]], <4 x double> [[TMP25]], <4 x i32> <i32 4, i32 1, i32 6, i32 3>
; CHECK-NEXT: [[TMP27:%.*]] = shufflevector <4 x double> [[TMP26]], <4 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
; CHECK-NEXT: [[TMP28:%.*]] = fmul <4 x double> [[TMP27]], zeroinitializer
; CHECK-NEXT: [[TMP29:%.*]] = fmul <4 x double> [[TMP22]], <double 1.000000e+00, double 1.000000e+00, double 0.000000e+00, double 0.000000e+00>
>From 7038f8cc314341ca3e174ee86e069a6bc85545ee Mon Sep 17 00:00:00 2001
From: Karthika Devi C <kartc at qti.qualcomm.com>
Date: Wed, 26 Aug 2026 05:32:29 -0700
Subject: [PATCH 2/2] [SLP]Extend GEP pointer-chain cost to casts and non-root
external uses
Cherry-pick of 084c5507ee0146a7506f3117868082162760b689 to release/23.x.
Fixes AArch64 regression introduced by 376311097a27a6eb99ec2614e7c39c97ce33172f.
Original Pull Request: #216520
Recommit after perf regression fixes: #217683
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 75 +++---
.../reduction-vals-used-as-load-indices.ll | 219 ++++++++++++++++++
2 files changed, 252 insertions(+), 42 deletions(-)
create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/reduction-vals-used-as-load-indices.ll
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 9bf48c489d949..3cba5769e0047 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19960,32 +19960,35 @@ InstructionCost BoUpSLP::getTreeCost(InstructionCost TreeCost,
// On AArch64, this helps in fusing a mov instruction, associated with
// extractelement, with fmul in the backend so that extractelement is free.
SmallVector<std::tuple<Value *, User *, int>, 4> ScalarUserAndIdx;
+ // Record every external use: a missing entry is indistinguishable from
+ // lane 0 and is priced as a free extract by the extract-fusion cost model.
+ for (ExternalUser &EU : ExternalUses)
+ ScalarUserAndIdx.emplace_back(EU.Scalar, EU.User, EU.Lane);
+ // Detect external uses that drive address computations: the scalar (through
+ // an optional single-use index-promotion cast) is used as a GEP index.
bool AllUsersGEPSWithStoresLoads = true;
- SmallBitVector UsedLanes(VectorizableTree.front()->getVectorFactor());
SmallVector<const Value *> Pointers;
Type *UserScalarTy = nullptr;
for (ExternalUser &EU : ExternalUses) {
- ScalarUserAndIdx.emplace_back(EU.Scalar, EU.User, EU.Lane);
- if (EU.E.Idx == 0) {
- UsedLanes.set(EU.Lane);
- auto *User = dyn_cast_if_present<GetElementPtrInst>(EU.User);
- if (User && User->hasOneUse() &&
- isa<LoadInst, StoreInst>(User->user_back())) {
- Type *LocalTy = getValueType(User->user_back());
- if (!UserScalarTy && !isa<ScalableVectorType>(LocalTy)) {
- UserScalarTy = LocalTy;
- } else if (UserScalarTy != LocalTy) {
- AllUsersGEPSWithStoresLoads = false;
- break;
- }
- Pointers.push_back(User);
- } else {
- AllUsersGEPSWithStoresLoads = false;
- break;
- }
+ Value *Usr = EU.User;
+ if (Usr && match(Usr, m_OneUse(m_ZExtOrSExt(m_Value()))))
+ Usr = cast<Instruction>(Usr)->user_back();
+ auto *User = dyn_cast_if_present<GetElementPtrInst>(Usr);
+ // Only a GEP that feeds a single load/store of a fixed access type drives
+ // a real memory address computation.
+ Type *AccessTy = nullptr;
+ if (User && User->hasOneUse() &&
+ isa<LoadInst, StoreInst>(User->user_back()))
+ AccessTy = getValueType(User->user_back());
+ if (AccessTy && !isa<ScalableVectorType>(AccessTy) &&
+ (!UserScalarTy || UserScalarTy == AccessTy)) {
+ UserScalarTy = AccessTy;
+ Pointers.push_back(User);
+ } else {
+ AllUsersGEPSWithStoresLoads = false;
+ break;
}
}
- AllUsersGEPSWithStoresLoads &= UsedLanes.all();
// Pre-pass: for each externally-used scalar, find the basic block at which
// the extractelement will be placed by codegen. This mirrors what
@@ -20362,30 +20365,18 @@ InstructionCost BoUpSLP::getTreeCost(InstructionCost TreeCost,
ExtractCost += ExtraCost;
}
- // Charge the pointer-chain cost difference once for the root entry when
- // every external use of its scalars is a GEP feeding a single load/store
- // (see the detection loop above). Vectorizing the root in this pattern
- // forces lane extracts (or a vector GEP with unknown stride) to drive the
- // address computation, which is typically more expensive than keeping the
- // indices scalar in a unit-stride address chain. Add the delta once rather
- // than per external use.
+ // Charge the pointer-chain cost difference once when every escaped scalar
+ // is used only to drive an address computation (see the detection loop
+ // above). Vectorizing the tree in this pattern forces lane extracts (or a
+ // vector GEP with unknown stride) to drive the address computation, which is
+ // typically more expensive than keeping the indices scalar in a unit-stride
+ // address chain. Add the delta once rather than per external use.
if (AllUsersGEPSWithStoresLoads && !Pointers.empty()) {
const TreeEntry &RootEntry = *VectorizableTree.front();
- const bool AnyRootKeptAsScalar = any_of(RootEntry.Scalars, [&](Value *V) {
- return ExternalUsesAsOriginalScalar.contains(V);
- });
- const Value *CommonBase = nullptr;
- bool HaveCommonBase = true;
- for (const Value *P : Pointers) {
- const Value *Op = getUnderlyingObject(P);
- if (!CommonBase)
- CommonBase = Op;
- else if (CommonBase != Op) {
- HaveCommonBase = false;
- break;
- }
- }
- if (!AnyRootKeptAsScalar && HaveCommonBase) {
+ const Value *CommonBase = getUnderlyingObject(Pointers.front());
+ if (all_of(Pointers, [CommonBase](const Value *P) {
+ return getUnderlyingObject(P) == CommonBase;
+ })) {
TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
auto *VecTy = getWidenedType(UserScalarTy, RootEntry.Scalars.size());
InstructionCost ScalarGEPCost = TTI->getPointersChainCost(
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/reduction-vals-used-as-load-indices.ll b/llvm/test/Transforms/SLPVectorizer/X86/reduction-vals-used-as-load-indices.ll
new file mode 100644
index 0000000000000..c39be0ed960ce
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/reduction-vals-used-as-load-indices.ll
@@ -0,0 +1,219 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=slp-vectorizer -mcpu=znver2 -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define i32 @test(ptr %this, i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @test(
+; CHECK-SAME: ptr [[THIS:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[ARRAY_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[THIS]], i64 24
+; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAY_PTR]], align 8
+; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[TMP0]], null
+; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: tail call void @deopt()
+; CHECK-NEXT: unreachable
+; CHECK: [[IF_END]]:
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[B]], [[A]]
+; CHECK-NEXT: [[LENGTH:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 8
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[LENGTH]], align 8
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 15
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[ADD]], 4
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[SHR]], 15
+; CHECK-NEXT: [[TMP14:%.*]] = or disjoint i32 [[AND1]], 16
+; CHECK-NEXT: [[SHR2:%.*]] = lshr i32 [[ADD]], 8
+; CHECK-NEXT: [[AND3:%.*]] = and i32 [[SHR2]], 15
+; CHECK-NEXT: [[TMP16:%.*]] = or disjoint i32 [[AND3]], 32
+; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[ADD]], 12
+; CHECK-NEXT: [[AND6:%.*]] = and i32 [[SHR5]], 15
+; CHECK-NEXT: [[TMP18:%.*]] = or disjoint i32 [[AND6]], 48
+; CHECK-NEXT: [[SHR8:%.*]] = lshr i32 [[ADD]], 16
+; CHECK-NEXT: [[AND9:%.*]] = and i32 [[SHR8]], 15
+; CHECK-NEXT: [[TMP20:%.*]] = or disjoint i32 [[AND9]], 64
+; CHECK-NEXT: [[SHR11:%.*]] = lshr i32 [[ADD]], 20
+; CHECK-NEXT: [[AND12:%.*]] = and i32 [[SHR11]], 15
+; CHECK-NEXT: [[TMP22:%.*]] = or disjoint i32 [[AND12]], 80
+; CHECK-NEXT: [[SHR14:%.*]] = lshr i32 [[ADD]], 24
+; CHECK-NEXT: [[AND15:%.*]] = and i32 [[SHR14]], 15
+; CHECK-NEXT: [[TMP24:%.*]] = or disjoint i32 [[AND15]], 96
+; CHECK-NEXT: [[SHR17:%.*]] = lshr i32 [[ADD]], 28
+; CHECK-NEXT: [[TMP26:%.*]] = or disjoint i32 [[SHR17]], 112
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[AND]], [[TMP1]]
+; CHECK-NEXT: [[CMP19:%.*]] = icmp ult i32 [[TMP14]], [[TMP1]]
+; CHECK-NEXT: [[AND23167:%.*]] = and i1 [[CMP]], [[CMP19]]
+; CHECK-NEXT: [[CMP26:%.*]] = icmp ult i32 [[TMP16]], [[TMP1]]
+; CHECK-NEXT: [[AND33168:%.*]] = and i1 [[CMP26]], [[AND23167]]
+; CHECK-NEXT: [[CMP36:%.*]] = icmp ult i32 [[TMP18]], [[TMP1]]
+; CHECK-NEXT: [[AND43169:%.*]] = and i1 [[CMP36]], [[AND33168]]
+; CHECK-NEXT: [[CMP46:%.*]] = icmp ult i32 [[TMP20]], [[TMP1]]
+; CHECK-NEXT: [[AND53170:%.*]] = and i1 [[CMP46]], [[AND43169]]
+; CHECK-NEXT: [[CMP56:%.*]] = icmp ult i32 [[TMP22]], [[TMP1]]
+; CHECK-NEXT: [[AND63171:%.*]] = and i1 [[CMP56]], [[AND53170]]
+; CHECK-NEXT: [[CMP66:%.*]] = icmp ult i32 [[TMP24]], [[TMP1]]
+; CHECK-NEXT: [[AND73172:%.*]] = and i1 [[CMP66]], [[AND63171]]
+; CHECK-NEXT: [[CMP76:%.*]] = icmp ult i32 [[TMP26]], [[TMP1]]
+; CHECK-NEXT: [[TMP12:%.*]] = and i1 [[CMP76]], [[AND73172]]
+; CHECK-NEXT: br i1 [[TMP12]], label %[[IF_END88:.*]], label %[[IF_THEN87:.*]]
+; CHECK: [[IF_THEN87]]:
+; CHECK-NEXT: tail call void @deopt()
+; CHECK-NEXT: unreachable
+; CHECK: [[IF_END88]]:
+; CHECK-NEXT: [[DATA:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
+; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[AND]] to i64
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM]]
+; CHECK-NEXT: [[TMP13:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT: [[CONV89:%.*]] = sext i8 [[TMP13]] to i32
+; CHECK-NEXT: [[IDXPROM90:%.*]] = zext nneg i32 [[TMP14]] to i64
+; CHECK-NEXT: [[ARRAYIDX91:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM90]]
+; CHECK-NEXT: [[TMP15:%.*]] = load i8, ptr [[ARRAYIDX91]], align 1
+; CHECK-NEXT: [[CONV92:%.*]] = sext i8 [[TMP15]] to i32
+; CHECK-NEXT: [[SHL93:%.*]] = shl nsw i32 [[CONV92]], 4
+; CHECK-NEXT: [[ADD94:%.*]] = add nsw i32 [[SHL93]], [[CONV89]]
+; CHECK-NEXT: [[IDXPROM95:%.*]] = zext nneg i32 [[TMP16]] to i64
+; CHECK-NEXT: [[ARRAYIDX96:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM95]]
+; CHECK-NEXT: [[TMP17:%.*]] = load i8, ptr [[ARRAYIDX96]], align 1
+; CHECK-NEXT: [[CONV97:%.*]] = sext i8 [[TMP17]] to i32
+; CHECK-NEXT: [[SHL98:%.*]] = shl nsw i32 [[CONV97]], 8
+; CHECK-NEXT: [[ADD99:%.*]] = add nsw i32 [[ADD94]], [[SHL98]]
+; CHECK-NEXT: [[IDXPROM100:%.*]] = zext nneg i32 [[TMP18]] to i64
+; CHECK-NEXT: [[ARRAYIDX101:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM100]]
+; CHECK-NEXT: [[TMP19:%.*]] = load i8, ptr [[ARRAYIDX101]], align 1
+; CHECK-NEXT: [[CONV102:%.*]] = sext i8 [[TMP19]] to i32
+; CHECK-NEXT: [[SHL103:%.*]] = shl nsw i32 [[CONV102]], 12
+; CHECK-NEXT: [[ADD104:%.*]] = add nsw i32 [[ADD99]], [[SHL103]]
+; CHECK-NEXT: [[IDXPROM105:%.*]] = zext nneg i32 [[TMP20]] to i64
+; CHECK-NEXT: [[ARRAYIDX106:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM105]]
+; CHECK-NEXT: [[TMP21:%.*]] = load i8, ptr [[ARRAYIDX106]], align 1
+; CHECK-NEXT: [[CONV107:%.*]] = sext i8 [[TMP21]] to i32
+; CHECK-NEXT: [[SHL108:%.*]] = shl nsw i32 [[CONV107]], 16
+; CHECK-NEXT: [[ADD109:%.*]] = add nsw i32 [[ADD104]], [[SHL108]]
+; CHECK-NEXT: [[IDXPROM110:%.*]] = zext nneg i32 [[TMP22]] to i64
+; CHECK-NEXT: [[ARRAYIDX111:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM110]]
+; CHECK-NEXT: [[TMP23:%.*]] = load i8, ptr [[ARRAYIDX111]], align 1
+; CHECK-NEXT: [[CONV112:%.*]] = sext i8 [[TMP23]] to i32
+; CHECK-NEXT: [[SHL113:%.*]] = shl nsw i32 [[CONV112]], 20
+; CHECK-NEXT: [[ADD114:%.*]] = add nsw i32 [[ADD109]], [[SHL113]]
+; CHECK-NEXT: [[IDXPROM115:%.*]] = zext nneg i32 [[TMP24]] to i64
+; CHECK-NEXT: [[ARRAYIDX116:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM115]]
+; CHECK-NEXT: [[TMP25:%.*]] = load i8, ptr [[ARRAYIDX116]], align 1
+; CHECK-NEXT: [[CONV117:%.*]] = sext i8 [[TMP25]] to i32
+; CHECK-NEXT: [[SHL118:%.*]] = shl nsw i32 [[CONV117]], 24
+; CHECK-NEXT: [[ADD119:%.*]] = add nsw i32 [[ADD114]], [[SHL118]]
+; CHECK-NEXT: [[IDXPROM120:%.*]] = zext nneg i32 [[TMP26]] to i64
+; CHECK-NEXT: [[ARRAYIDX121:%.*]] = getelementptr inbounds nuw i8, ptr [[DATA]], i64 [[IDXPROM120]]
+; CHECK-NEXT: [[TMP27:%.*]] = load i8, ptr [[ARRAYIDX121]], align 1
+; CHECK-NEXT: [[CONV122:%.*]] = zext i8 [[TMP27]] to i32
+; CHECK-NEXT: [[SHL123:%.*]] = shl i32 [[CONV122]], 28
+; CHECK-NEXT: [[ADD124:%.*]] = add nsw i32 [[ADD119]], [[SHL123]]
+; CHECK-NEXT: [[OR127:%.*]] = tail call i32 @llvm.fshl.i32(i32 [[ADD124]], i32 [[ADD124]], i32 11)
+; CHECK-NEXT: ret i32 [[OR127]]
+;
+entry:
+ %array_ptr = getelementptr inbounds nuw i8, ptr %this, i64 24
+ %0 = load ptr, ptr %array_ptr, align 8
+ %tobool.not = icmp eq ptr %0, null
+ br i1 %tobool.not, label %if.then, label %if.end
+
+if.then:
+ tail call void @deopt()
+ unreachable
+
+if.end:
+ %add = add nsw i32 %b, %a
+ %length = getelementptr inbounds nuw i8, ptr %0, i64 8
+ %1 = load i32, ptr %length, align 8
+ %and = and i32 %add, 15
+ %shr = lshr i32 %add, 4
+ %and1 = and i32 %shr, 15
+ %or = or disjoint i32 %and1, 16
+ %shr2 = lshr i32 %add, 8
+ %and3 = and i32 %shr2, 15
+ %or4 = or disjoint i32 %and3, 32
+ %shr5 = lshr i32 %add, 12
+ %and6 = and i32 %shr5, 15
+ %or7 = or disjoint i32 %and6, 48
+ %shr8 = lshr i32 %add, 16
+ %and9 = and i32 %shr8, 15
+ %or10 = or disjoint i32 %and9, 64
+ %shr11 = lshr i32 %add, 20
+ %and12 = and i32 %shr11, 15
+ %or13 = or disjoint i32 %and12, 80
+ %shr14 = lshr i32 %add, 24
+ %and15 = and i32 %shr14, 15
+ %or16 = or disjoint i32 %and15, 96
+ %shr17 = lshr i32 %add, 28
+ %or18 = or disjoint i32 %shr17, 112
+ %cmp = icmp ult i32 %and, %1
+ %cmp19 = icmp ult i32 %or, %1
+ %and23167 = and i1 %cmp, %cmp19
+ %cmp26 = icmp ult i32 %or4, %1
+ %and33168 = and i1 %cmp26, %and23167
+ %cmp36 = icmp ult i32 %or7, %1
+ %and43169 = and i1 %cmp36, %and33168
+ %cmp46 = icmp ult i32 %or10, %1
+ %and53170 = and i1 %cmp46, %and43169
+ %cmp56 = icmp ult i32 %or13, %1
+ %and63171 = and i1 %cmp56, %and53170
+ %cmp66 = icmp ult i32 %or16, %1
+ %and73172 = and i1 %cmp66, %and63171
+ %cmp76 = icmp ult i32 %or18, %1
+ %and83173 = and i1 %cmp76, %and73172
+ br i1 %and83173, label %if.end88, label %if.then87
+
+if.then87:
+ tail call void @deopt()
+ unreachable
+
+if.end88:
+ %data = getelementptr inbounds nuw i8, ptr %0, i64 16
+ %idxprom = zext nneg i32 %and to i64
+ %arrayidx = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom
+ %2 = load i8, ptr %arrayidx, align 1
+ %conv89 = sext i8 %2 to i32
+ %idxprom90 = zext nneg i32 %or to i64
+ %arrayidx91 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom90
+ %3 = load i8, ptr %arrayidx91, align 1
+ %conv92 = sext i8 %3 to i32
+ %shl93 = shl nsw i32 %conv92, 4
+ %add94 = add nsw i32 %shl93, %conv89
+ %idxprom95 = zext nneg i32 %or4 to i64
+ %arrayidx96 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom95
+ %4 = load i8, ptr %arrayidx96, align 1
+ %conv97 = sext i8 %4 to i32
+ %shl98 = shl nsw i32 %conv97, 8
+ %add99 = add nsw i32 %add94, %shl98
+ %idxprom100 = zext nneg i32 %or7 to i64
+ %arrayidx101 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom100
+ %5 = load i8, ptr %arrayidx101, align 1
+ %conv102 = sext i8 %5 to i32
+ %shl103 = shl nsw i32 %conv102, 12
+ %add104 = add nsw i32 %add99, %shl103
+ %idxprom105 = zext nneg i32 %or10 to i64
+ %arrayidx106 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom105
+ %6 = load i8, ptr %arrayidx106, align 1
+ %conv107 = sext i8 %6 to i32
+ %shl108 = shl nsw i32 %conv107, 16
+ %add109 = add nsw i32 %add104, %shl108
+ %idxprom110 = zext nneg i32 %or13 to i64
+ %arrayidx111 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom110
+ %7 = load i8, ptr %arrayidx111, align 1
+ %conv112 = sext i8 %7 to i32
+ %shl113 = shl nsw i32 %conv112, 20
+ %add114 = add nsw i32 %add109, %shl113
+ %idxprom115 = zext nneg i32 %or16 to i64
+ %arrayidx116 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom115
+ %8 = load i8, ptr %arrayidx116, align 1
+ %conv117 = sext i8 %8 to i32
+ %shl118 = shl nsw i32 %conv117, 24
+ %add119 = add nsw i32 %add114, %shl118
+ %idxprom120 = zext nneg i32 %or18 to i64
+ %arrayidx121 = getelementptr inbounds nuw i8, ptr %data, i64 %idxprom120
+ %9 = load i8, ptr %arrayidx121, align 1
+ %conv122 = zext i8 %9 to i32
+ %shl123 = shl i32 %conv122, 28
+ %add124 = add nsw i32 %add119, %shl123
+ %or127 = tail call i32 @llvm.fshl.i32(i32 %add124, i32 %add124, i32 11)
+ ret i32 %or127
+}
+
+declare void @deopt()
+declare i32 @llvm.fshl.i32(i32, i32, i32)
More information about the llvm-branch-commits
mailing list