[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 10:56:33 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/6] [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/6] 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/6] 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/6] 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/6] 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/6] 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;



More information about the llvm-commits mailing list