[llvm] [VectorCombine] Only copy IR flags for newly created instructions (PR #193271)
Jack Huang via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 21:05:48 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 1/7] [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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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
+}
More information about the llvm-commits
mailing list