[llvm] [VectorCombine] Pass flags during IR creation (PR #193271)
Jack Huang via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 13 07:44:10 PDT 2026
https://github.com/jackhong12 updated https://github.com/llvm/llvm-project/pull/193271
>From 629a9ebcba89319f9f47b7ca47ac289a33452f14 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 22 Apr 2026 01:09:26 +0800
Subject: [PATCH 01/12] [VectorCombine] Only copy IR flags for newly created
instructions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Since commit 777d6b5, VectorCombine has been using InstSimplifyFolder to
simplify vector instructions during IR construction. When creating a new
instruction, InstSimplifyFolder may fold the operation and return an
existing operand instead of emitting a new instruction.
In such cases, copying IR flags to the returned value is incorrect and
may unintentionally propagate flags to pre‑existing instructions,
polluting the original IR. Restrict IR flag propagation to newly created
instructions only and fix #192607.
---
.../Transforms/Vectorize/VectorCombine.cpp | 20 +++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 29eced7ee9de1..47eeca8f866e2 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1443,10 +1443,22 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
Scalar->setName(I.getName() + ".scalar");
- // All IR flags are safe to back-propagate. There is no potential for extra
- // poison to be created by the scalar instruction.
- if (auto *ScalarInst = dyn_cast<Instruction>(Scalar))
- ScalarInst->copyIRFlags(&I);
+ if (auto *ScalarInst = dyn_cast<Instruction>(Scalar)) {
+ bool IsFoldOp = false;
+ for (auto Op: ScalarOps) {
+ if (Op == Scalar) {
+ IsFoldOp = true;
+ break;
+ }
+ }
+
+ // If the scalar operand is not the result of folding the original vector
+ // operation, then it must be an original operand of the vector operation.
+ // In that case, we can safely copy IR flags from the original vector
+ // operation to the new scalar.
+ if (!IsFoldOp)
+ ScalarInst->copyIRFlags(&I);
+ }
Value *Insert = Builder.CreateInsertElement(NewVecC, Scalar, *Index);
replaceValue(I, *Insert);
>From 16e87d775d93ac6eeaf559613c974e81ffbafef8 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 22 Apr 2026 07:31:06 +0800
Subject: [PATCH 02/12] Format the change
---
llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 47eeca8f866e2..a155ca68aec9b 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1445,7 +1445,7 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
if (auto *ScalarInst = dyn_cast<Instruction>(Scalar)) {
bool IsFoldOp = false;
- for (auto Op: ScalarOps) {
+ for (auto Op : ScalarOps) {
if (Op == Scalar) {
IsFoldOp = true;
break;
>From bc522dd684e9a19c2fe5007daa6122369d2257dc Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 22 Apr 2026 10:18:47 +0800
Subject: [PATCH 03/12] Add lit test
---
llvm/test/Transforms/VectorCombine/binop-scalarize.ll | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
index bc07f8b086496..12963c872d364 100644
--- a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
@@ -39,3 +39,14 @@ entry:
%b = or disjoint <2 x i64> splat (i64 2), %a
ret <2 x i64> %b
}
+
+define i32 @pr193271(i32 %0) {
+; CHECK-LABEL: define i32 @pr193271(
+; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-NEXT: [[SCALAR:%.*]] = add i32 [[ARG]], 1
+; CHECK-NEXT: ret i32 [[SCALAR]]
+ %2 = add i32 %0, 1
+ %4 = insertelement <2 x i32> zeroinitializer, i32 %2, i64 0
+ %5 = add nuw <2 x i32> %4, zeroinitializer
+ ret i32 %2
+}
>From 8ef5fa278adb6b07183b633e3d430b4c36701455 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 22 Apr 2026 11:04:17 +0800
Subject: [PATCH 04/12] Simplify the comment
---
llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index a155ca68aec9b..7b473c785503f 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1446,16 +1446,15 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
if (auto *ScalarInst = dyn_cast<Instruction>(Scalar)) {
bool IsFoldOp = false;
for (auto Op : ScalarOps) {
- if (Op == Scalar) {
+ if (Op == ScalarInst) {
IsFoldOp = true;
break;
}
}
- // If the scalar operand is not the result of folding the original vector
- // operation, then it must be an original operand of the vector operation.
- // In that case, we can safely copy IR flags from the original vector
- // operation to the new scalar.
+ // If ScalarInst is not one of the existing operands, it must be newly
+ // created. In that case, it is safe to propagate the IR flags from the
+ // original instruction to ScalarInst.
if (!IsFoldOp)
ScalarInst->copyIRFlags(&I);
}
>From 9892a9047d024e49558567392763308de941d7f9 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Thu, 23 Apr 2026 01:53:33 +0800
Subject: [PATCH 05/12] Pass IR flags when creating a new operation
---
.../Transforms/Vectorize/VectorCombine.cpp | 76 ++++++++++++++++++-
.../VectorCombine/binop-scalarize.ll | 10 +--
2 files changed, 79 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 7b473c785503f..e957c1155a836 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -156,6 +156,10 @@ class VectorCombine {
bool shrinkType(Instruction &I);
bool shrinkLoadForShuffles(Instruction &I);
bool shrinkPhiOfShuffles(Instruction &I);
+ Value *createBinaryOp(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
+ BinaryOperator *OldI);
+ Value *createUnaryOp(Instruction::UnaryOps Opcode, Value *Operand,
+ Instruction &OldI);
void replaceValue(Instruction &Old, Value &New, bool Erase = true) {
LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');
@@ -1282,6 +1286,72 @@ bool VectorCombine::scalarizeVPIntrinsic(Instruction &I) {
return true;
}
+Value *VectorCombine::createUnaryOp(Instruction::UnaryOps Opcode,
+ Value *Operand, Instruction &OldI) {
+ switch (Opcode) {
+ case Instruction::FNeg:
+ return Builder.CreateFNegFMF(Operand, &OldI,
+ OldI.getName() + ".scalar.fneg");
+ case Instruction::UnaryOpsEnd:
+ llvm_unreachable("Invalid unary opcode");
+ }
+ llvm_unreachable("Invalid unary opcode");
+}
+
+Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
+ Value *RHS, BinaryOperator *OldI) {
+ Twine Prefix = OldI->getName() + ".scalar.";
+ switch (Opcode) {
+ case Instruction::Add:
+ return Builder.CreateAdd(LHS, RHS, Prefix + "add",
+ OldI->hasNoUnsignedWrap(),
+ OldI->hasNoSignedWrap());
+ case Instruction::Sub:
+ return Builder.CreateSub(LHS, RHS, Prefix + "sub",
+ OldI->hasNoUnsignedWrap(),
+ OldI->hasNoSignedWrap());
+ case Instruction::Mul:
+ return Builder.CreateMul(LHS, RHS, Prefix + "mul",
+ OldI->hasNoUnsignedWrap(),
+ OldI->hasNoSignedWrap());
+ case Instruction::UDiv:
+ return Builder.CreateUDiv(LHS, RHS, Prefix + "udiv", OldI->isExact());
+ case Instruction::SDiv:
+ return Builder.CreateSDiv(LHS, RHS, Prefix + "sdiv", OldI->isExact());
+ case Instruction::URem:
+ return Builder.CreateURem(LHS, RHS, Prefix + "urem");
+ case Instruction::SRem:
+ return Builder.CreateSRem(LHS, RHS, Prefix + "srem");
+ case Instruction::Shl:
+ return Builder.CreateShl(LHS, RHS, Prefix + "shl",
+ OldI->hasNoUnsignedWrap(),
+ OldI->hasNoSignedWrap());
+ case Instruction::LShr:
+ return Builder.CreateLShr(LHS, RHS, Prefix + "lshr", OldI->isExact());
+ case Instruction::AShr:
+ return Builder.CreateAShr(LHS, RHS, Prefix + "ashr", OldI->isExact());
+ case Instruction::And:
+ return Builder.CreateAnd(LHS, RHS, Prefix + "and");
+ case Instruction::Or:
+ return Builder.CreateOr(LHS, RHS, Prefix + "or");
+ case Instruction::Xor:
+ return Builder.CreateXor(LHS, RHS, Prefix + "xor");
+ case Instruction::FAdd:
+ return Builder.CreateFAddFMF(LHS, RHS, OldI, Prefix + "fadd");
+ case Instruction::FSub:
+ return Builder.CreateFSubFMF(LHS, RHS, OldI, Prefix + "fsub");
+ case Instruction::FMul:
+ return Builder.CreateFMulFMF(LHS, RHS, OldI, Prefix + "fmul");
+ case Instruction::FDiv:
+ return Builder.CreateFDivFMF(LHS, RHS, OldI, Prefix + "fdiv");
+ case Instruction::FRem:
+ return Builder.CreateFRemFMF(LHS, RHS, OldI, Prefix + "frem");
+ case Instruction::BinaryOpsEnd:
+ llvm_unreachable("Invalid binary opcode");
+ }
+ llvm_unreachable("Invalid binary opcode");
+}
+
/// Match a vector op/compare/intrinsic with at least one
/// inserted scalar operand and convert to scalar op/cmp/intrinsic followed
/// by insertelement.
@@ -1436,8 +1506,10 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
Value *Scalar;
if (CI)
Scalar = Builder.CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);
- else if (UO || BO)
- Scalar = Builder.CreateNAryOp(Opcode, ScalarOps);
+ else if (UO)
+ Scalar = createUnaryOp(UO->getOpcode(), ScalarOps[0], I);
+ else if (BO)
+ Scalar = createBinaryOp(BO->getOpcode(), ScalarOps[0], ScalarOps[1], BO);
else
Scalar = Builder.CreateIntrinsic(ScalarTy, II->getIntrinsicID(), ScalarOps);
diff --git a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
index 12963c872d364..623fa1b7d7d45 100644
--- a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
@@ -40,13 +40,13 @@ entry:
ret <2 x i64> %b
}
-define i32 @pr193271(i32 %0) {
+define i32 @pr193271(i32 %arg) {
; CHECK-LABEL: define i32 @pr193271(
; CHECK-SAME: i32 [[ARG:%.*]]) {
; CHECK-NEXT: [[SCALAR:%.*]] = add i32 [[ARG]], 1
; CHECK-NEXT: ret i32 [[SCALAR]]
- %2 = add i32 %0, 1
- %4 = insertelement <2 x i32> zeroinitializer, i32 %2, i64 0
- %5 = add nuw <2 x i32> %4, zeroinitializer
- ret i32 %2
+ %ret = add i32 %arg, 1
+ %insert = insertelement <2 x i32> zeroinitializer, i32 %ret, i64 0
+ %vec.add = add nuw <2 x i32> %insert, zeroinitializer
+ ret i32 %ret
}
>From 45d830f34b95791fb56f25bd5596c20106d98422 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Thu, 23 Apr 2026 01:56:17 +0800
Subject: [PATCH 06/12] Remove unused code
---
.../lib/Transforms/Vectorize/VectorCombine.cpp | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index e957c1155a836..eaeea8d47b9e7 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1513,24 +1513,6 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
else
Scalar = Builder.CreateIntrinsic(ScalarTy, II->getIntrinsicID(), ScalarOps);
- Scalar->setName(I.getName() + ".scalar");
-
- if (auto *ScalarInst = dyn_cast<Instruction>(Scalar)) {
- bool IsFoldOp = false;
- for (auto Op : ScalarOps) {
- if (Op == ScalarInst) {
- IsFoldOp = true;
- break;
- }
- }
-
- // If ScalarInst is not one of the existing operands, it must be newly
- // created. In that case, it is safe to propagate the IR flags from the
- // original instruction to ScalarInst.
- if (!IsFoldOp)
- ScalarInst->copyIRFlags(&I);
- }
-
Value *Insert = Builder.CreateInsertElement(NewVecC, Scalar, *Index);
replaceValue(I, *Insert);
return true;
>From 8d9691131c72be15dd337b162f05540feabbc130 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Thu, 23 Apr 2026 12:04:20 +0800
Subject: [PATCH 07/12] Handle fcmp flags and add more lit cases
---
.../Transforms/Vectorize/VectorCombine.cpp | 22 +-
.../VectorCombine/binop-scalarize.ll | 218 +++++++++++++++++-
.../Transforms/VectorCombine/cmp-scalarize.ll | 50 ++++
.../VectorCombine/unary-op-scalarize.ll | 12 +
4 files changed, 295 insertions(+), 7 deletions(-)
create mode 100644 llvm/test/Transforms/VectorCombine/cmp-scalarize.ll
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index eaeea8d47b9e7..e901bcd92da1f 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -159,7 +159,9 @@ class VectorCombine {
Value *createBinaryOp(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
BinaryOperator *OldI);
Value *createUnaryOp(Instruction::UnaryOps Opcode, Value *Operand,
- Instruction &OldI);
+ UnaryOperator *OldI);
+ Value *createCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
+ CmpInst *OldI);
void replaceValue(Instruction &Old, Value &New, bool Erase = true) {
LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');
@@ -1287,11 +1289,11 @@ bool VectorCombine::scalarizeVPIntrinsic(Instruction &I) {
}
Value *VectorCombine::createUnaryOp(Instruction::UnaryOps Opcode,
- Value *Operand, Instruction &OldI) {
+ Value *Operand, UnaryOperator *OldI) {
switch (Opcode) {
case Instruction::FNeg:
- return Builder.CreateFNegFMF(Operand, &OldI,
- OldI.getName() + ".scalar.fneg");
+ return Builder.CreateFNegFMF(Operand, OldI,
+ OldI->getName() + ".scalar.fneg");
case Instruction::UnaryOpsEnd:
llvm_unreachable("Invalid unary opcode");
}
@@ -1352,6 +1354,14 @@ Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
llvm_unreachable("Invalid binary opcode");
}
+Value *VectorCombine::createCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
+ CmpInst *OldI) {
+ if (FCmpInst *FC = dyn_cast<FCmpInst>(OldI))
+ return Builder.CreateFCmpFMF(Pred, LHS, RHS, FC);
+
+ return Builder.CreateCmp(Pred, LHS, RHS);
+}
+
/// Match a vector op/compare/intrinsic with at least one
/// inserted scalar operand and convert to scalar op/cmp/intrinsic followed
/// by insertelement.
@@ -1505,9 +1515,9 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
Value *Scalar;
if (CI)
- Scalar = Builder.CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);
+ Scalar = createCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1], CI);
else if (UO)
- Scalar = createUnaryOp(UO->getOpcode(), ScalarOps[0], I);
+ Scalar = createUnaryOp(UO->getOpcode(), ScalarOps[0], UO);
else if (BO)
Scalar = createBinaryOp(BO->getOpcode(), ScalarOps[0], ScalarOps[1], BO);
else
diff --git a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
index 623fa1b7d7d45..bb191c6ff8850 100644
--- a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
@@ -47,6 +47,222 @@ define i32 @pr193271(i32 %arg) {
; CHECK-NEXT: ret i32 [[SCALAR]]
%ret = add i32 %arg, 1
%insert = insertelement <2 x i32> zeroinitializer, i32 %ret, i64 0
- %vec.add = add nuw <2 x i32> %insert, zeroinitializer
+ %vecAdd = add nuw <2 x i32> %insert, zeroinitializer
ret i32 %ret
}
+
+define <2 x i32> @test_add(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_add(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarAdd:%.*]] = add nuw nsw i32 1, [[Arg]]
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarAdd]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 1, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vecAdd = add nuw nsw <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecAdd
+}
+
+define <2 x i32> @test_sub(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_sub(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarSub:%.*]] = sub nuw nsw i32 [[Arg]], 1
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarSub]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 1, i64 0
+ %vecSub = sub nuw nsw <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecSub
+}
+
+define <2 x i32> @test_mul(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_mul(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarMul:%.*]] = mul nuw nsw i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarMul]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecMul = mul nuw nsw <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecMul
+}
+
+define <2 x i32> @test_udiv(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_udiv(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarUdiv:%.*]] = udiv i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> poison, i32 [[ScalarUdiv]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecUdiv = udiv <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecUdiv
+}
+
+define <2 x i32> @test_sdiv(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_sdiv(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarSdiv:%.*]] = sdiv i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> poison, i32 [[ScalarSdiv]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecSdiv = sdiv <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecSdiv
+}
+
+define <2 x i32> @test_urem(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_urem(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarUrem:%.*]] = urem i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> poison, i32 [[ScalarUrem]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecUrem = urem <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecUrem
+}
+
+define <2 x i32> @test_srem(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_srem(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarSrem:%.*]] = srem i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> poison, i32 [[ScalarSrem]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecSrem = srem <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecSrem
+}
+
+define <2 x i32> @test_shl(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_shl(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarShl:%.*]] = shl nuw nsw i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarShl]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecShl = shl nuw nsw <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecShl
+}
+
+define <2 x i32> @test_lshr(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_lshr(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarLshr:%.*]] = lshr exact i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarLshr]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecLshr = lshr exact <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecLshr
+}
+
+define <2 x i32> @test_ashr(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_ashr(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarAshr:%.*]] = ashr exact i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarAshr]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecAshr = ashr exact <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecAshr
+}
+
+define <2 x i32> @test_and(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_and(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarAnd:%.*]] = and i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarAnd]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecAnd = and <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecAnd
+}
+
+define <2 x i32> @test_or(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_or(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarOr:%.*]] = or i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarOr]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecOr = or disjoint <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecOr
+}
+
+define <2 x i32> @test_xor(i32 %arg) {
+; CHECK-LABEL: define <2 x i32> @test_xor(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarXor:%.*]] = xor i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarXor]], i64 0
+; CHECK-NEXT: ret <2 x i32> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecXor = xor <2 x i32> %vec0, %vec1
+ ret <2 x i32> %vecXor
+}
+
+define <2 x float> @test_fadd(float %arg) {
+; CHECK-LABEL: define <2 x float> @test_fadd(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarFAdd:%.*]] = fadd fast float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> zeroinitializer, float [[ScalarFAdd]], i64 0
+; CHECK-NEXT: ret <2 x float> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecFAdd = fadd fast <2 x float> %vec0, %vec1
+ ret <2 x float> %vecFAdd
+}
+
+define <2 x float> @test_fsub(float %arg) {
+; CHECK-LABEL: define <2 x float> @test_fsub(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarFSub:%.*]] = fsub fast float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> zeroinitializer, float [[ScalarFSub]], i64 0
+; CHECK-NEXT: ret <2 x float> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecFSub = fsub fast <2 x float> %vec0, %vec1
+ ret <2 x float> %vecFSub
+}
+
+define <2 x float> @test_fmul(float %arg) {
+; CHECK-LABEL: define <2 x float> @test_fmul(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarFMul:%.*]] = fmul fast float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> zeroinitializer, float [[ScalarFMul]], i64 0
+; CHECK-NEXT: ret <2 x float> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecFMul = fmul fast <2 x float> %vec0, %vec1
+ ret <2 x float> %vecFMul
+}
+
+define <2 x float> @test_fdiv(float %arg) {
+; CHECK-LABEL: define <2 x float> @test_fdiv(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarFDiv:%.*]] = fdiv fast float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float 0x7FF8000000000000), float [[ScalarFDiv]], i64 0
+; CHECK-NEXT: ret <2 x float> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecFDiv = fdiv fast <2 x float> %vec0, %vec1
+ ret <2 x float> %vecFDiv
+}
+
+define <2 x float> @test_frem(float %arg) {
+; CHECK-LABEL: define <2 x float> @test_frem(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarFRem:%.*]] = frem fast float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float 0x7FF8000000000000), float [[ScalarFRem]], i64 0
+; CHECK-NEXT: ret <2 x float> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecFRem = frem fast <2 x float> %vec0, %vec1
+ ret <2 x float> %vecFRem
+}
diff --git a/llvm/test/Transforms/VectorCombine/cmp-scalarize.ll b/llvm/test/Transforms/VectorCombine/cmp-scalarize.ll
new file mode 100644
index 0000000000000..5957e759873b8
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/cmp-scalarize.ll
@@ -0,0 +1,50 @@
+; RUN: opt < %s -S -p vector-combine | FileCheck %s
+
+define <2 x i1> @test_icmp_eq(i32 %arg) {
+; CHECK-LABEL: define <2 x i1> @test_icmp_eq(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarCmp:%.*]] = icmp eq i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i1> splat (i1 true), i1 [[ScalarCmp]], i64 0
+; CHECK-NEXT: ret <2 x i1> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecCmp = icmp eq <2 x i32> %vec0, %vec1
+ ret <2 x i1> %vecCmp
+}
+
+define <2 x i1> @test_icmp_slt(i32 %arg) {
+; CHECK-LABEL: define <2 x i1> @test_icmp_slt(
+; CHECK-SAME: i32 [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarCmp:%.*]] = icmp slt i32 [[Arg]], 3
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i1> zeroinitializer, i1 [[ScalarCmp]], i64 0
+; CHECK-NEXT: ret <2 x i1> [[Insert]]
+ %vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
+ %vec1 = insertelement <2 x i32> zeroinitializer, i32 3, i64 0
+ %vecCmp = icmp slt <2 x i32> %vec0, %vec1
+ ret <2 x i1> %vecCmp
+}
+
+define <2 x i1> @test_fcmp_oeq(float %arg) {
+; CHECK-LABEL: define <2 x i1> @test_fcmp_oeq(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarCmp:%.*]] = fcmp oeq float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i1> splat (i1 true), i1 [[ScalarCmp]], i64 0
+; CHECK-NEXT: ret <2 x i1> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecCmp = fcmp oeq <2 x float> %vec0, %vec1
+ ret <2 x i1> %vecCmp
+}
+
+define <2 x i1> @test_fcmp_ult(float %arg) {
+; CHECK-LABEL: define <2 x i1> @test_fcmp_ult(
+; CHECK-SAME: float [[Arg:%.*]]) {
+; CHECK-NEXT: [[ScalarCmp:%.*]] = fcmp fast ult float [[Arg]], 3.000000e+00
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i1> zeroinitializer, i1 [[ScalarCmp]], i64 0
+; CHECK-NEXT: ret <2 x i1> [[Insert]]
+ %vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
+ %vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
+ %vecCmp = fcmp fast ult <2 x float> %vec0, %vec1
+ ret <2 x i1> %vecCmp
+}
+
diff --git a/llvm/test/Transforms/VectorCombine/unary-op-scalarize.ll b/llvm/test/Transforms/VectorCombine/unary-op-scalarize.ll
index 45d53c84c870d..f5159c0d34918 100644
--- a/llvm/test/Transforms/VectorCombine/unary-op-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/unary-op-scalarize.ll
@@ -24,3 +24,15 @@ define <vscale x 4 x float> @fneg_scalable(float %x) {
%v = fneg <vscale x 4 x float> %x.insert
ret <vscale x 4 x float> %v
}
+
+define <vscale x 4 x float> @fneg_scalable_fast(float %x) {
+; CHECK-LABEL: define <vscale x 4 x float> @fneg_scalable_fast(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT: [[V_SCALAR:%.*]] = fneg fast float [[X]]
+; CHECK-NEXT: [[V:%.*]] = insertelement <vscale x 4 x float> poison, float [[V_SCALAR]], i64 0
+; CHECK-NEXT: ret <vscale x 4 x float> [[V]]
+;
+ %x.insert = insertelement <vscale x 4 x float> poison, float %x, i32 0
+ %v = fneg fast <vscale x 4 x float> %x.insert
+ ret <vscale x 4 x float> %v
+}
>From db771624d7c53a83a47759a9d9f73490942ba546 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Thu, 4 Jun 2026 00:20:33 +0800
Subject: [PATCH 08/12] Handle disjoint flag in or instruction
---
llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 7 +++++--
llvm/test/Transforms/VectorCombine/binop-scalarize.ll | 2 +-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index e901bcd92da1f..a7be84ba07164 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1334,8 +1334,11 @@ Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
return Builder.CreateAShr(LHS, RHS, Prefix + "ashr", OldI->isExact());
case Instruction::And:
return Builder.CreateAnd(LHS, RHS, Prefix + "and");
- case Instruction::Or:
- return Builder.CreateOr(LHS, RHS, Prefix + "or");
+ case Instruction::Or: {
+ PossiblyDisjointInst *PDI = dyn_cast<PossiblyDisjointInst>(OldI);
+ bool IsDisjoint = PDI ? PDI->isDisjoint() : false;
+ return Builder.CreateOr(LHS, RHS, Prefix + "or", IsDisjoint);
+ }
case Instruction::Xor:
return Builder.CreateXor(LHS, RHS, Prefix + "xor");
case Instruction::FAdd:
diff --git a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
index bb191c6ff8850..ab2716d9e4604 100644
--- a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
@@ -186,7 +186,7 @@ define <2 x i32> @test_and(i32 %arg) {
define <2 x i32> @test_or(i32 %arg) {
; CHECK-LABEL: define <2 x i32> @test_or(
; CHECK-SAME: i32 [[Arg:%.*]]) {
-; CHECK-NEXT: [[ScalarOr:%.*]] = or i32 [[Arg]], 3
+; CHECK-NEXT: [[ScalarOr:%.*]] = or disjoint i32 [[Arg]], 3
; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x i32> zeroinitializer, i32 [[ScalarOr]], i64 0
; CHECK-NEXT: ret <2 x i32> [[Insert]]
%vec0 = insertelement <2 x i32> zeroinitializer, i32 %arg, i64 0
>From 395ab413628c1fc1e99ce34a2aac29292df970fd Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Thu, 4 Jun 2026 11:17:54 +0800
Subject: [PATCH 09/12] Use +qnan instead of 0x7FF8000000000000 in the lit test
---
llvm/test/Transforms/VectorCombine/binop-scalarize.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
index ab2716d9e4604..e305eacc3fafa 100644
--- a/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
+++ b/llvm/test/Transforms/VectorCombine/binop-scalarize.ll
@@ -247,7 +247,7 @@ define <2 x float> @test_fdiv(float %arg) {
; CHECK-LABEL: define <2 x float> @test_fdiv(
; CHECK-SAME: float [[Arg:%.*]]) {
; CHECK-NEXT: [[ScalarFDiv:%.*]] = fdiv fast float [[Arg]], 3.000000e+00
-; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float 0x7FF8000000000000), float [[ScalarFDiv]], i64 0
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float +qnan), float [[ScalarFDiv]], i64 0
; CHECK-NEXT: ret <2 x float> [[Insert]]
%vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
%vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
@@ -259,7 +259,7 @@ define <2 x float> @test_frem(float %arg) {
; CHECK-LABEL: define <2 x float> @test_frem(
; CHECK-SAME: float [[Arg:%.*]]) {
; CHECK-NEXT: [[ScalarFRem:%.*]] = frem fast float [[Arg]], 3.000000e+00
-; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float 0x7FF8000000000000), float [[ScalarFRem]], i64 0
+; CHECK-NEXT: [[Insert:%.*]] = insertelement <2 x float> splat (float +qnan), float [[ScalarFRem]], i64 0
; CHECK-NEXT: ret <2 x float> [[Insert]]
%vec0 = insertelement <2 x float> zeroinitializer, float %arg, i64 0
%vec1 = insertelement <2 x float> zeroinitializer, float 3.000000e+00, i64 0
>From ab1c41e376ebd3a88ce5bbbaad6454fd559e2083 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 10 Jun 2026 11:50:41 +0800
Subject: [PATCH 10/12] Avoid using Twine
---
.../Transforms/Vectorize/VectorCombine.cpp | 47 +++++++++++--------
1 file changed, 28 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4919a0a5b1e90..4d4302c36d2b2 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1313,55 +1313,64 @@ Value *VectorCombine::createUnaryOp(Instruction::UnaryOps Opcode,
Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
Value *RHS, BinaryOperator *OldI) {
- Twine Prefix = OldI->getName() + ".scalar.";
switch (Opcode) {
case Instruction::Add:
- return Builder.CreateAdd(LHS, RHS, Prefix + "add",
+ return Builder.CreateAdd(LHS, RHS, OldI->getName() + ".scalar.add",
OldI->hasNoUnsignedWrap(),
OldI->hasNoSignedWrap());
case Instruction::Sub:
- return Builder.CreateSub(LHS, RHS, Prefix + "sub",
+ return Builder.CreateSub(LHS, RHS, OldI->getName() + ".scalar.sub",
OldI->hasNoUnsignedWrap(),
OldI->hasNoSignedWrap());
case Instruction::Mul:
- return Builder.CreateMul(LHS, RHS, Prefix + "mul",
+ return Builder.CreateMul(LHS, RHS, OldI->getName() + ".scalar.mul",
OldI->hasNoUnsignedWrap(),
OldI->hasNoSignedWrap());
case Instruction::UDiv:
- return Builder.CreateUDiv(LHS, RHS, Prefix + "udiv", OldI->isExact());
+ return Builder.CreateUDiv(LHS, RHS, OldI->getName() + ".scalar.udiv",
+ OldI->isExact());
case Instruction::SDiv:
- return Builder.CreateSDiv(LHS, RHS, Prefix + "sdiv", OldI->isExact());
+ return Builder.CreateSDiv(LHS, RHS, OldI->getName() + ".scalar.sdiv",
+ OldI->isExact());
case Instruction::URem:
- return Builder.CreateURem(LHS, RHS, Prefix + "urem");
+ return Builder.CreateURem(LHS, RHS, OldI->getName() + ".scalar.urem");
case Instruction::SRem:
- return Builder.CreateSRem(LHS, RHS, Prefix + "srem");
+ return Builder.CreateSRem(LHS, RHS, OldI->getName() + ".scalar.srem");
case Instruction::Shl:
- return Builder.CreateShl(LHS, RHS, Prefix + "shl",
+ return Builder.CreateShl(LHS, RHS, OldI->getName() + ".scalar.shl",
OldI->hasNoUnsignedWrap(),
OldI->hasNoSignedWrap());
case Instruction::LShr:
- return Builder.CreateLShr(LHS, RHS, Prefix + "lshr", OldI->isExact());
+ return Builder.CreateLShr(LHS, RHS, OldI->getName() + ".scalar.lshr",
+ OldI->isExact());
case Instruction::AShr:
- return Builder.CreateAShr(LHS, RHS, Prefix + "ashr", OldI->isExact());
+ return Builder.CreateAShr(LHS, RHS, OldI->getName() + ".scalar.ashr",
+ OldI->isExact());
case Instruction::And:
- return Builder.CreateAnd(LHS, RHS, Prefix + "and");
+ return Builder.CreateAnd(LHS, RHS, OldI->getName() + ".scalar.and");
case Instruction::Or: {
PossiblyDisjointInst *PDI = dyn_cast<PossiblyDisjointInst>(OldI);
bool IsDisjoint = PDI ? PDI->isDisjoint() : false;
- return Builder.CreateOr(LHS, RHS, Prefix + "or", IsDisjoint);
+ return Builder.CreateOr(LHS, RHS, OldI->getName() + ".scalar.or",
+ IsDisjoint);
}
case Instruction::Xor:
- return Builder.CreateXor(LHS, RHS, Prefix + "xor");
+ return Builder.CreateXor(LHS, RHS, OldI->getName() + ".scalar.xor");
case Instruction::FAdd:
- return Builder.CreateFAddFMF(LHS, RHS, OldI, Prefix + "fadd");
+ return Builder.CreateFAddFMF(LHS, RHS, OldI,
+ OldI->getName() + ".scalar.fadd");
case Instruction::FSub:
- return Builder.CreateFSubFMF(LHS, RHS, OldI, Prefix + "fsub");
+ return Builder.CreateFSubFMF(LHS, RHS, OldI,
+ OldI->getName() + ".scalar.fsub");
case Instruction::FMul:
- return Builder.CreateFMulFMF(LHS, RHS, OldI, Prefix + "fmul");
+ return Builder.CreateFMulFMF(LHS, RHS, OldI,
+ OldI->getName() + ".scalar.fmul");
case Instruction::FDiv:
- return Builder.CreateFDivFMF(LHS, RHS, OldI, Prefix + "fdiv");
+ return Builder.CreateFDivFMF(LHS, RHS, OldI,
+ OldI->getName() + ".scalar.fdiv");
case Instruction::FRem:
- return Builder.CreateFRemFMF(LHS, RHS, OldI, Prefix + "frem");
+ return Builder.CreateFRemFMF(LHS, RHS, OldI,
+ OldI->getName() + ".scalar.frem");
case Instruction::BinaryOpsEnd:
llvm_unreachable("Invalid binary opcode");
}
>From e6fdad5e8904b71e1e9ee532d608c1964b27a913 Mon Sep 17 00:00:00 2001
From: jack <jackhuang1205 at gmail.com>
Date: Wed, 10 Jun 2026 23:21:58 +0800
Subject: [PATCH 11/12] Directly cast PossiblyDisjointInst without checking
pointer
---
llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4d4302c36d2b2..89dc7283d3935 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1348,12 +1348,9 @@ Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
OldI->isExact());
case Instruction::And:
return Builder.CreateAnd(LHS, RHS, OldI->getName() + ".scalar.and");
- case Instruction::Or: {
- PossiblyDisjointInst *PDI = dyn_cast<PossiblyDisjointInst>(OldI);
- bool IsDisjoint = PDI ? PDI->isDisjoint() : false;
+ case Instruction::Or:
return Builder.CreateOr(LHS, RHS, OldI->getName() + ".scalar.or",
- IsDisjoint);
- }
+ cast<PossiblyDisjointInst>(OldI)->isDisjoint());
case Instruction::Xor:
return Builder.CreateXor(LHS, RHS, OldI->getName() + ".scalar.xor");
case Instruction::FAdd:
>From b60e5521132135b5759426dfe28ebf0b6e6cbff0 Mon Sep 17 00:00:00 2001
From: Jack Huang <jackhuang1205 at gmail.com>
Date: Sat, 13 Jun 2026 21:55:48 +0800
Subject: [PATCH 12/12] Move implementation to IRBuilder and add functions
CreateFlaggedBinOp and CreateFlaggedCmp
---
llvm/include/llvm/IR/IRBuilder.h | 55 ++++++++
.../Transforms/Vectorize/VectorCombine.cpp | 125 ++++--------------
2 files changed, 84 insertions(+), 96 deletions(-)
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 7c3eb46cb1cbb..86234bfacbe3f 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1767,6 +1767,53 @@ class IRBuilderBase {
return Insert(BinOp, Name);
}
+ Value *CreateFlaggedBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
+ const Twine &Name = "", bool HasNUW = false,
+ bool HasNSW = false, bool IsExact = false,
+ bool IsDisjoint = false, FMFSource FMFSource = {}) {
+ switch (Opc) {
+ case Instruction::Add:
+ return CreateAdd(LHS, RHS, Name, HasNUW, HasNSW);
+ case Instruction::Sub:
+ return CreateSub(LHS, RHS, Name, HasNUW, HasNSW);
+ case Instruction::Mul:
+ return CreateMul(LHS, RHS, Name, HasNUW, HasNSW);
+ case Instruction::Shl:
+ return CreateShl(LHS, RHS, Name, HasNUW, HasNSW);
+ case Instruction::UDiv:
+ return CreateUDiv(LHS, RHS, Name, IsExact);
+ case Instruction::SDiv:
+ return CreateSDiv(LHS, RHS, Name, IsExact);
+ case Instruction::LShr:
+ return CreateLShr(LHS, RHS, Name, IsExact);
+ case Instruction::AShr:
+ return CreateAShr(LHS, RHS, Name, IsExact);
+ case Instruction::Or:
+ return CreateOr(LHS, RHS, Name, IsDisjoint);
+ case Instruction::URem:
+ return CreateURem(LHS, RHS, Name);
+ case Instruction::SRem:
+ return CreateSRem(LHS, RHS, Name);
+ case Instruction::And:
+ return CreateAnd(LHS, RHS, Name);
+ case Instruction::Xor:
+ return CreateBinOpFMF(Opc, LHS, RHS, FMFSource, Name);
+ case Instruction::FAdd:
+ return CreateFAddFMF(LHS, RHS, FMFSource, Name);
+ case Instruction::FSub:
+ return CreateFSubFMF(LHS, RHS, FMFSource, Name);
+ case Instruction::FMul:
+ return CreateFMulFMF(LHS, RHS, FMFSource, Name);
+ case Instruction::FDiv:
+ return CreateFDivFMF(LHS, RHS, FMFSource, Name);
+ case Instruction::FRem:
+ return CreateFRemFMF(LHS, RHS, FMFSource, Name);
+ default:
+ llvm_unreachable("Invalid binary opcode");
+ }
+ llvm_unreachable("Invalid binary opcode");
+ }
+
Value *CreateNoWrapBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
bool IsNUW, bool IsNSW, const Twine &Name = "") {
if (Value *V = Folder.FoldNoWrapBinOp(Opc, LHS, RHS, IsNUW, IsNSW))
@@ -2512,6 +2559,14 @@ class IRBuilderBase {
: CreateICmp(Pred, LHS, RHS, Name);
}
+ Value *CreateFlaggedCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
+ FMFSource FMFSource, const Twine &Name = "",
+ MDNode *FPMathTag = nullptr) {
+ return CmpInst::isFPPredicate(Pred)
+ ? CreateFCmpFMF(Pred, LHS, RHS, FMFSource, Name, FPMathTag)
+ : CreateICmp(Pred, LHS, RHS, Name);
+ }
+
// Create a signaling floating-point comparison (i.e. one that raises an FP
// exception whenever an input is any NaN, signaling or quiet).
// Note that this differs from CreateFCmp only if IsFPConstrained is true.
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 89dc7283d3935..752e3246a8933 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -160,12 +160,6 @@ class VectorCombine {
bool shrinkType(Instruction &I);
bool shrinkLoadForShuffles(Instruction &I);
bool shrinkPhiOfShuffles(Instruction &I);
- Value *createBinaryOp(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
- BinaryOperator *OldI);
- Value *createUnaryOp(Instruction::UnaryOps Opcode, Value *Operand,
- UnaryOperator *OldI);
- Value *createCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
- CmpInst *OldI);
void replaceValue(Instruction &Old, Value &New, bool Erase = true) {
LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');
@@ -1299,89 +1293,6 @@ bool VectorCombine::scalarizeVPIntrinsic(Instruction &I) {
return true;
}
-Value *VectorCombine::createUnaryOp(Instruction::UnaryOps Opcode,
- Value *Operand, UnaryOperator *OldI) {
- switch (Opcode) {
- case Instruction::FNeg:
- return Builder.CreateFNegFMF(Operand, OldI,
- OldI->getName() + ".scalar.fneg");
- case Instruction::UnaryOpsEnd:
- llvm_unreachable("Invalid unary opcode");
- }
- llvm_unreachable("Invalid unary opcode");
-}
-
-Value *VectorCombine::createBinaryOp(Instruction::BinaryOps Opcode, Value *LHS,
- Value *RHS, BinaryOperator *OldI) {
- switch (Opcode) {
- case Instruction::Add:
- return Builder.CreateAdd(LHS, RHS, OldI->getName() + ".scalar.add",
- OldI->hasNoUnsignedWrap(),
- OldI->hasNoSignedWrap());
- case Instruction::Sub:
- return Builder.CreateSub(LHS, RHS, OldI->getName() + ".scalar.sub",
- OldI->hasNoUnsignedWrap(),
- OldI->hasNoSignedWrap());
- case Instruction::Mul:
- return Builder.CreateMul(LHS, RHS, OldI->getName() + ".scalar.mul",
- OldI->hasNoUnsignedWrap(),
- OldI->hasNoSignedWrap());
- case Instruction::UDiv:
- return Builder.CreateUDiv(LHS, RHS, OldI->getName() + ".scalar.udiv",
- OldI->isExact());
- case Instruction::SDiv:
- return Builder.CreateSDiv(LHS, RHS, OldI->getName() + ".scalar.sdiv",
- OldI->isExact());
- case Instruction::URem:
- return Builder.CreateURem(LHS, RHS, OldI->getName() + ".scalar.urem");
- case Instruction::SRem:
- return Builder.CreateSRem(LHS, RHS, OldI->getName() + ".scalar.srem");
- case Instruction::Shl:
- return Builder.CreateShl(LHS, RHS, OldI->getName() + ".scalar.shl",
- OldI->hasNoUnsignedWrap(),
- OldI->hasNoSignedWrap());
- case Instruction::LShr:
- return Builder.CreateLShr(LHS, RHS, OldI->getName() + ".scalar.lshr",
- OldI->isExact());
- case Instruction::AShr:
- return Builder.CreateAShr(LHS, RHS, OldI->getName() + ".scalar.ashr",
- OldI->isExact());
- case Instruction::And:
- return Builder.CreateAnd(LHS, RHS, OldI->getName() + ".scalar.and");
- case Instruction::Or:
- return Builder.CreateOr(LHS, RHS, OldI->getName() + ".scalar.or",
- cast<PossiblyDisjointInst>(OldI)->isDisjoint());
- case Instruction::Xor:
- return Builder.CreateXor(LHS, RHS, OldI->getName() + ".scalar.xor");
- case Instruction::FAdd:
- return Builder.CreateFAddFMF(LHS, RHS, OldI,
- OldI->getName() + ".scalar.fadd");
- case Instruction::FSub:
- return Builder.CreateFSubFMF(LHS, RHS, OldI,
- OldI->getName() + ".scalar.fsub");
- case Instruction::FMul:
- return Builder.CreateFMulFMF(LHS, RHS, OldI,
- OldI->getName() + ".scalar.fmul");
- case Instruction::FDiv:
- return Builder.CreateFDivFMF(LHS, RHS, OldI,
- OldI->getName() + ".scalar.fdiv");
- case Instruction::FRem:
- return Builder.CreateFRemFMF(LHS, RHS, OldI,
- OldI->getName() + ".scalar.frem");
- case Instruction::BinaryOpsEnd:
- llvm_unreachable("Invalid binary opcode");
- }
- llvm_unreachable("Invalid binary opcode");
-}
-
-Value *VectorCombine::createCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
- CmpInst *OldI) {
- if (FCmpInst *FC = dyn_cast<FCmpInst>(OldI))
- return Builder.CreateFCmpFMF(Pred, LHS, RHS, FC);
-
- return Builder.CreateCmp(Pred, LHS, RHS);
-}
-
/// Match a vector op/compare/intrinsic with at least one
/// inserted scalar operand and convert to scalar op/cmp/intrinsic followed
/// by insertelement.
@@ -1534,14 +1445,36 @@ bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {
cast<Constant>(VecC), Builder.getInt64(*Index));
Value *Scalar;
- if (CI)
- Scalar = createCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1], CI);
- else if (UO)
- Scalar = createUnaryOp(UO->getOpcode(), ScalarOps[0], UO);
- else if (BO)
- Scalar = createBinaryOp(BO->getOpcode(), ScalarOps[0], ScalarOps[1], BO);
- else
+ if (CI) {
+ FPMathOperator *FPMO = dyn_cast<FPMathOperator>(&I);
+ FMFSource FMF;
+ if (FPMO)
+ FMF = FPMO->getFastMathFlags();
+ Scalar =
+ Builder.CreateFlaggedCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1],
+ FMF, CI->getName() + ".scalar");
+ } else if (UO) {
+ // FNeg is the only unary operator.
+ Scalar = Builder.CreateFNegFMF(ScalarOps[0], UO, UO->getName() + ".scalar");
+ } else if (BO) {
+ OverflowingBinaryOperator *OBO = dyn_cast<OverflowingBinaryOperator>(&I);
+ bool HasNUW = OBO ? OBO->hasNoUnsignedWrap() : false;
+ bool HasNSW = OBO ? OBO->hasNoSignedWrap() : false;
+ PossiblyDisjointInst *PDI = dyn_cast<PossiblyDisjointInst>(&I);
+ bool IsDisjoint = PDI ? PDI->isDisjoint() : false;
+ PossiblyExactOperator *PEO = dyn_cast<PossiblyExactOperator>(&I);
+ bool IsExact = PEO ? PEO->isExact() : false;
+ FPMathOperator *FPMO = dyn_cast<FPMathOperator>(&I);
+ FMFSource FMF;
+ if (FPMO)
+ FMF = FPMO->getFastMathFlags();
+
+ Scalar = Builder.CreateFlaggedBinOp(
+ BO->getOpcode(), ScalarOps[0], ScalarOps[1], BO->getName() + ".scalar",
+ HasNUW, HasNSW, IsExact, IsDisjoint, FMF);
+ } else {
Scalar = Builder.CreateIntrinsic(ScalarTy, II->getIntrinsicID(), ScalarOps);
+ }
Value *Insert = Builder.CreateInsertElement(NewVecC, Scalar, *Index);
replaceValue(I, *Insert);
More information about the llvm-commits
mailing list