[llvm] sketch idea of getConstantBuildVector (PR #180074)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 8 10:32:32 PST 2026


https://github.com/fbrv updated https://github.com/llvm/llvm-project/pull/180074

>From fc347b3bb95fb31f5acd6797cc591941817eb143 Mon Sep 17 00:00:00 2001
From: fbrv <fabio.baravalle at gmail.com>
Date: Thu, 5 Feb 2026 23:52:36 +0000
Subject: [PATCH 1/5] sketch idea of getConstantBuildVector

---
 llvm/include/llvm/CodeGen/SelectionDAG.h      |  20 +++
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  21 ++-
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  41 +++++
 .../sve-extract-vector-to-predicate-store.ll  |   1 +
 llvm/test/CodeGen/X86/sext-load.ll            |  10 ++
 llvm/test/CodeGen/X86/sext-ret-val.ll         |  19 ++-
 llvm/test/CodeGen/X86/zext-inreg-0.ll         | 144 ++++++++++++++++++
 7 files changed, 237 insertions(+), 19 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index a208481df0c70..55c88d29da709 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -897,6 +897,26 @@ class SelectionDAG {
     return getNode(ISD::BUILD_VECTOR, DL, VT, Ops);
   }
 
+  /// Return a BUILD_VECTOR of constants from an array of APInt values.
+  ///
+  /// \p VT must be a fixed-width integer vector type. \p Ops contains the
+  /// constant value for each element (sized to VT's scalar size in bits).
+  /// Bits set in \p UndefElts indicate elements that should be UNDEF.
+  ///
+  /// When NewNodesMustHaveLegalTypes is true (i.e., after type legalization),
+  /// the element constants are created using a promoted legal type, relying
+  /// on BUILD_VECTOR's implicit truncation semantics. This avoids creating
+  /// nodes with illegal scalar types that would otherwise trigger assertions.
+  LLVM_ABI SDValue getConstantBuildVector(EVT VT, const SDLoc &DL,
+                                          ArrayRef<APInt> Ops,
+                                          const APInt &UndefElts);
+
+  /// Convenience overload with no undef elements.
+  SDValue getConstantBuildVector(EVT VT, const SDLoc &DL,
+                                 ArrayRef<APInt> Ops) {
+    return getConstantBuildVector(VT, DL, Ops, APInt::getZero(Ops.size()));
+  }
+
   /// Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all
   /// elements. VT must be a vector type. Op's type must be the same as (or,
   /// for integers, a type wider than) VT's element type.
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 838da9206ae17..475959abf563c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14256,37 +14256,36 @@ static SDValue tryToFoldExtendOfConstant(SDNode *N, const SDLoc &DL,
   // fold (zext (build_vector AllConstants) -> (build_vector AllConstants)
   // fold (aext (build_vector AllConstants) -> (build_vector AllConstants)
   EVT SVT = VT.getScalarType();
-  if (!(VT.isVector() && (!LegalTypes || TLI.isTypeLegal(SVT)) &&
-      ISD::isBuildVectorOfConstantSDNodes(N0.getNode())))
+  if (!(VT.isVector() &&
+        ISD::isBuildVectorOfConstantSDNodes(N0.getNode())))
     return SDValue();
 
   // We can fold this node into a build_vector.
   unsigned VTBits = SVT.getSizeInBits();
   unsigned EVTBits = N0->getValueType(0).getScalarSizeInBits();
-  SmallVector<SDValue, 8> Elts;
   unsigned NumElts = VT.getVectorNumElements();
+  SmallVector<APInt, 8> Constants;
+  APInt UndefElts = APInt::getZero(NumElts);
 
   for (unsigned i = 0; i != NumElts; ++i) {
     SDValue Op = N0.getOperand(i);
     if (Op.isUndef()) {
       if (Opcode == ISD::ANY_EXTEND || Opcode == ISD::ANY_EXTEND_VECTOR_INREG)
-        Elts.push_back(DAG.getUNDEF(SVT));
-      else
-        Elts.push_back(DAG.getConstant(0, DL, SVT));
+        UndefElts.setBit(i);
+      // For sext/zext, undef -> 0 (matching previous behavior).
+      Constants.push_back(APInt::getZero(VTBits));
       continue;
     }
-
-    SDLoc DL(Op);
     // Get the constant value and if needed trunc it to the size of the type.
     // Nodes like build_vector might have constants wider than the scalar type.
     APInt C = Op->getAsAPIntVal().zextOrTrunc(EVTBits);
     if (Opcode == ISD::SIGN_EXTEND || Opcode == ISD::SIGN_EXTEND_VECTOR_INREG)
-      Elts.push_back(DAG.getConstant(C.sext(VTBits), DL, SVT));
+      Constants.push_back(C.sext(VTBits));
     else
-      Elts.push_back(DAG.getConstant(C.zext(VTBits), DL, SVT));
+      Constants.push_back(C.zext(VTBits));
   }
 
-  return DAG.getBuildVector(VT, DL, Elts);
+  return DAG.getConstantBuildVector(VT, DL, Constants, UndefElts);
 }
 
 // ExtendUsesToFormExtLoad - Trying to extend uses of a load to enable this:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 16a8c264a42b3..eb28ad3ec7b53 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2179,6 +2179,47 @@ SDValue SelectionDAG::getMaskFromElementCount(const SDLoc &DL, EVT DataVT,
                  getConstant(0, DL, IdxVT), getElementCount(DL, IdxVT, EC));
 }
 
+SDValue SelectionDAG::getConstantBuildVector(EVT VT, const SDLoc &DL,
+                                             ArrayRef<APInt> Ops,
+                                             const APInt &UndefElts) {
+  assert(VT.isFixedLengthVector() && "Expected fixed-length vector type");
+  assert(VT.getVectorNumElements() == Ops.size() &&
+         "Mismatch between VT element count and Ops size");
+  assert(UndefElts.getBitWidth() == Ops.size() &&
+         "Mismatch between UndefElts width and Ops size");
+
+  unsigned NumElts = VT.getVectorNumElements();
+  EVT EltVT = VT.getVectorElementType();
+  assert(EltVT.isInteger() && "Expected integer element type");
+
+  // Determine the type to use for the constant elements. After type
+  // legalization, the original scalar element type may be illegal (e.g., i32
+  // on LoongArch64 where only i64 is legal). In that case, we promote to a
+  // legal type and rely on BUILD_VECTOR's implicit truncation.
+  EVT ConstantVT = EltVT;
+  if (NewNodesMustHaveLegalTypes) {
+    auto Action = TLI->getTypeAction(*getContext(), EltVT);
+    if (Action == TargetLowering::TypePromoteInteger)
+      ConstantVT = TLI->getTypeToTransformTo(*getContext(), EltVT);
+  }
+
+  SmallVector<SDValue, 16> BVOps(NumElts);
+  for (unsigned i = 0; i < NumElts; ++i) {
+    if (UndefElts[i]) {
+      BVOps[i] = getUNDEF(ConstantVT);
+    } else {
+      // Zero-extend the APInt to the promoted width if needed, preserving
+      // the original value (BUILD_VECTOR will implicitly truncate).
+      APInt Val = Ops[i];
+      if (ConstantVT.getSizeInBits() > EltVT.getSizeInBits())
+        Val = Val.zextOrTrunc(ConstantVT.getSizeInBits());
+      BVOps[i] = getConstant(Val, DL, ConstantVT);
+    }
+  }
+
+  return getBuildVector(VT, DL, BVOps);
+}
+
 SDValue SelectionDAG::getStepVector(const SDLoc &DL, EVT ResVT) {
   APInt One(ResVT.getScalarSizeInBits(), 1);
   return getStepVector(DL, ResVT, One);
diff --git a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
index e3d368b7b85c6..33b929e6a0d43 100644
--- a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
+++ b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -aarch64-sve-intrinsic-opts < %s | FileCheck %s
 
 target triple = "aarch64-unknown-linux-gnu"
diff --git a/llvm/test/CodeGen/X86/sext-load.ll b/llvm/test/CodeGen/X86/sext-load.ll
index 3e51fc2fc6af3..163171afad18e 100644
--- a/llvm/test/CodeGen/X86/sext-load.ll
+++ b/llvm/test/CodeGen/X86/sext-load.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-- | FileCheck %s
 
 ; When doing sign extension, use the sext-load lowering to take advantage of
@@ -7,6 +8,10 @@
 ; CHECK:      movsbl {{.*}}, %eax
 ; CHECK-NEXT: ret
 define i32 @test1(i32 %X) nounwind  {
+; CHECK-LABEL: test1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movsbl {{[0-9]+}}(%esp), %eax
+; CHECK-NEXT:    retl
 entry:
 	%tmp12 = trunc i32 %X to i8		; <i8> [#uses=1]
 	%tmp123 = sext i8 %tmp12 to i32		; <i32> [#uses=1]
@@ -20,6 +25,11 @@ entry:
 ; CHECK:      movswl {{.*}}, %eax
 ; CHECK-NEXT: ret
 define i32 @test2(ptr %this) {
+; CHECK-LABEL: test2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; CHECK-NEXT:    movswl 6(%eax), %eax
+; CHECK-NEXT:    retl
 entry:
   %b48 = getelementptr inbounds { i16, [6 x i8] }, ptr %this, i32 0, i32 1
   %bf.load = load i48, ptr %b48, align 2
diff --git a/llvm/test/CodeGen/X86/sext-ret-val.ll b/llvm/test/CodeGen/X86/sext-ret-val.ll
index 250d310ebb143..aac4fddd0b6ea 100644
--- a/llvm/test/CodeGen/X86/sext-ret-val.ll
+++ b/llvm/test/CodeGen/X86/sext-ret-val.ll
@@ -1,26 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-unknown-linux-gnu | FileCheck %s
 ; rdar://6699246
 
 define signext i8 @t1(ptr %A) nounwind readnone ssp {
+; CHECK-LABEL: t1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; CHECK-NEXT:    setne %al
+; CHECK-NEXT:    retl
 entry:
         %0 = icmp ne ptr %A, null
         %1 = zext i1 %0 to i8
         ret i8 %1
 
-; CHECK-LABEL: t1:
-; CHECK: cmpl
-; CHECK-NEXT: setne
-; CHECK-NEXT: retl
 }
 
 define i8 @t2(ptr %A) nounwind readnone ssp {
+; CHECK-LABEL: t2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; CHECK-NEXT:    setne %al
+; CHECK-NEXT:    retl
 entry:
         %0 = icmp ne ptr %A, null
         %1 = zext i1 %0 to i8
         ret i8 %1
 
-; CHECK-LABEL: t2:
-; CHECK: cmpl
-; CHECK-NEXT: setne
-; CHECK-NEXT: retl
 }
diff --git a/llvm/test/CodeGen/X86/zext-inreg-0.ll b/llvm/test/CodeGen/X86/zext-inreg-0.ll
index 72fd6885dcdec..d551a91a9be36 100644
--- a/llvm/test/CodeGen/X86/zext-inreg-0.ll
+++ b/llvm/test/CodeGen/X86/zext-inreg-0.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-- | FileCheck -check-prefix=X86 %s
 ; RUN: llc < %s -mtriple=x86_64-- | FileCheck -check-prefix=X64 %s
 
@@ -12,57 +13,200 @@
 ; This related to not having a ZERO_EXTEND_REG opcode.
 
 define i32 @a(i32 %d) nounwind  {
+; X86-LABEL: a:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzbl %al, %eax
+; X86-NEXT:    retl
+;
+; X64-LABEL: a:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzbl %dil, %eax
+; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = and i32 %e, 255
         ret i32 %retval
 }
 define i32 @b(float %d) nounwind  {
+; X86-LABEL: b:
+; X86:       # %bb.0:
+; X86-NEXT:    subl $8, %esp
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fnstcw {{[0-9]+}}(%esp)
+; X86-NEXT:    movzwl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    orl $3072, %eax # imm = 0xC00
+; X86-NEXT:    movw %ax, {{[0-9]+}}(%esp)
+; X86-NEXT:    fldcw {{[0-9]+}}(%esp)
+; X86-NEXT:    fistps {{[0-9]+}}(%esp)
+; X86-NEXT:    fldcw {{[0-9]+}}(%esp)
+; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    addl $8, %esp
+; X86-NEXT:    retl
+;
+; X64-LABEL: b:
+; X64:       # %bb.0:
+; X64-NEXT:    cvttss2si %xmm0, %eax
+; X64-NEXT:    movzbl %al, %eax
+; X64-NEXT:    retq
         %tmp12 = fptoui float %d to i8
         %retval = zext i8 %tmp12 to i32
         ret i32 %retval
 }
 define i32 @c(i32 %d) nounwind  {
+; X86-LABEL: c:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzwl %ax, %eax
+; X86-NEXT:    retl
+;
+; X64-LABEL: c:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzwl %di, %eax
+; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = and i32 %e, 65535
         ret i32 %retval
 }
 define i64 @d(i64 %d) nounwind  {
+; X86-LABEL: d:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzbl %al, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: d:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzbl %dil, %eax
+; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 255
         ret i64 %retval
 }
 define i64 @e(i64 %d) nounwind  {
+; X86-LABEL: e:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzwl %ax, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: e:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzwl %di, %eax
+; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 65535
         ret i64 %retval
 }
 define i64 @f(i64 %d) nounwind  {
+; X86-LABEL: f:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: f:
+; X64:       # %bb.0:
+; X64-NEXT:    leal 1(%rdi), %eax
+; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 4294967295
         ret i64 %retval
 }
 
 define i32 @g(i8 %d) nounwind  {
+; X86-LABEL: g:
+; X86:       # %bb.0:
+; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incb %al
+; X86-NEXT:    movzbl %al, %eax
+; X86-NEXT:    retl
+;
+; X64-LABEL: g:
+; X64:       # %bb.0:
+; X64-NEXT:    incb %dil
+; X64-NEXT:    movzbl %dil, %eax
+; X64-NEXT:    retq
         %e = add i8 %d, 1
         %retval = zext i8 %e to i32
         ret i32 %retval
 }
 define i32 @h(i16 %d) nounwind  {
+; X86-LABEL: h:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzwl %ax, %eax
+; X86-NEXT:    retl
+;
+; X64-LABEL: h:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzwl %di, %eax
+; X64-NEXT:    retq
         %e = add i16 %d, 1
         %retval = zext i16 %e to i32
         ret i32 %retval
 }
 define i64 @i(i8 %d) nounwind  {
+; X86-LABEL: i:
+; X86:       # %bb.0:
+; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incb %al
+; X86-NEXT:    movzbl %al, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: i:
+; X64:       # %bb.0:
+; X64-NEXT:    incb %dil
+; X64-NEXT:    movzbl %dil, %eax
+; X64-NEXT:    retq
         %e = add i8 %d, 1
         %retval = zext i8 %e to i64
         ret i64 %retval
 }
 define i64 @j(i16 %d) nounwind  {
+; X86-LABEL: j:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    movzwl %ax, %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: j:
+; X64:       # %bb.0:
+; X64-NEXT:    incl %edi
+; X64-NEXT:    movzwl %di, %eax
+; X64-NEXT:    retq
         %e = add i16 %d, 1
         %retval = zext i16 %e to i64
         ret i64 %retval
 }
 define i64 @k(i32 %d) nounwind  {
+; X86-LABEL: k:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    incl %eax
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    retl
+;
+; X64-LABEL: k:
+; X64:       # %bb.0:
+; X64-NEXT:    # kill: def $edi killed $edi def $rdi
+; X64-NEXT:    leal 1(%rdi), %eax
+; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = zext i32 %e to i64
         ret i64 %retval

>From 36e184cdc9aef96fac91d6b28e67b48df298178c Mon Sep 17 00:00:00 2001
From: fbrv <fabio.baravalle at gmail.com>
Date: Fri, 6 Feb 2026 10:01:21 +0000
Subject: [PATCH 2/5] fmt

---
 llvm/include/llvm/CodeGen/SelectionDAG.h      | 3 +--
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 55c88d29da709..44b105af0b4d7 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -912,8 +912,7 @@ class SelectionDAG {
                                           const APInt &UndefElts);
 
   /// Convenience overload with no undef elements.
-  SDValue getConstantBuildVector(EVT VT, const SDLoc &DL,
-                                 ArrayRef<APInt> Ops) {
+  SDValue getConstantBuildVector(EVT VT, const SDLoc &DL, ArrayRef<APInt> Ops) {
     return getConstantBuildVector(VT, DL, Ops, APInt::getZero(Ops.size()));
   }
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 475959abf563c..46cb2c64927da 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14256,8 +14256,7 @@ static SDValue tryToFoldExtendOfConstant(SDNode *N, const SDLoc &DL,
   // fold (zext (build_vector AllConstants) -> (build_vector AllConstants)
   // fold (aext (build_vector AllConstants) -> (build_vector AllConstants)
   EVT SVT = VT.getScalarType();
-  if (!(VT.isVector() &&
-        ISD::isBuildVectorOfConstantSDNodes(N0.getNode())))
+  if (!(VT.isVector() && ISD::isBuildVectorOfConstantSDNodes(N0.getNode())))
     return SDValue();
 
   // We can fold this node into a build_vector.

>From fa438c9ef8b1423ffc63f8b3c177fdfbfee422db Mon Sep 17 00:00:00 2001
From: fbrv <fabio.baravalle at gmail.com>
Date: Sun, 8 Feb 2026 18:20:17 +0000
Subject: [PATCH 3/5] use isSExtCheaperThanZExt

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index eb28ad3ec7b53..72a6c3b33e1a6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2187,11 +2187,9 @@ SDValue SelectionDAG::getConstantBuildVector(EVT VT, const SDLoc &DL,
          "Mismatch between VT element count and Ops size");
   assert(UndefElts.getBitWidth() == Ops.size() &&
          "Mismatch between UndefElts width and Ops size");
-
   unsigned NumElts = VT.getVectorNumElements();
   EVT EltVT = VT.getVectorElementType();
   assert(EltVT.isInteger() && "Expected integer element type");
-
   // Determine the type to use for the constant elements. After type
   // legalization, the original scalar element type may be illegal (e.g., i32
   // on LoongArch64 where only i64 is legal). In that case, we promote to a
@@ -2202,21 +2200,22 @@ SDValue SelectionDAG::getConstantBuildVector(EVT VT, const SDLoc &DL,
     if (Action == TargetLowering::TypePromoteInteger)
       ConstantVT = TLI->getTypeToTransformTo(*getContext(), EltVT);
   }
-
   SmallVector<SDValue, 16> BVOps(NumElts);
   for (unsigned i = 0; i < NumElts; ++i) {
     if (UndefElts[i]) {
       BVOps[i] = getUNDEF(ConstantVT);
     } else {
-      // Zero-extend the APInt to the promoted width if needed, preserving
-      // the original value (BUILD_VECTOR will implicitly truncate).
+
       APInt Val = Ops[i];
-      if (ConstantVT.getSizeInBits() > EltVT.getSizeInBits())
-        Val = Val.zextOrTrunc(ConstantVT.getSizeInBits());
+      if (ConstantVT.getSizeInBits() > EltVT.getSizeInBits()) {
+        if (TLI->isSExtCheaperThanZExt(EltVT, ConstantVT))
+          Val = Val.sextOrTrunc(ConstantVT.getSizeInBits());
+        else
+          Val = Val.zextOrTrunc(ConstantVT.getSizeInBits());
+      }
       BVOps[i] = getConstant(Val, DL, ConstantVT);
     }
   }
-
   return getBuildVector(VT, DL, BVOps);
 }
 

>From 3295b29eeb8832e4eef4b145c62eb288b23c14d5 Mon Sep 17 00:00:00 2001
From: fbrv <fabio.baravalle at gmail.com>
Date: Sun, 8 Feb 2026 18:28:10 +0000
Subject: [PATCH 4/5] revert test changes

---
 .../sve-extract-vector-to-predicate-store.ll  |  1 -
 llvm/test/CodeGen/X86/sext-load.ll            | 10 ----------
 llvm/test/CodeGen/X86/sext-ret-val.ll         | 19 ++++++++-----------
 3 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
index 33b929e6a0d43..e3d368b7b85c6 100644
--- a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
+++ b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
@@ -1,4 +1,3 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -aarch64-sve-intrinsic-opts < %s | FileCheck %s
 
 target triple = "aarch64-unknown-linux-gnu"
diff --git a/llvm/test/CodeGen/X86/sext-load.ll b/llvm/test/CodeGen/X86/sext-load.ll
index 163171afad18e..3e51fc2fc6af3 100644
--- a/llvm/test/CodeGen/X86/sext-load.ll
+++ b/llvm/test/CodeGen/X86/sext-load.ll
@@ -1,4 +1,3 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-- | FileCheck %s
 
 ; When doing sign extension, use the sext-load lowering to take advantage of
@@ -8,10 +7,6 @@
 ; CHECK:      movsbl {{.*}}, %eax
 ; CHECK-NEXT: ret
 define i32 @test1(i32 %X) nounwind  {
-; CHECK-LABEL: test1:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    movsbl {{[0-9]+}}(%esp), %eax
-; CHECK-NEXT:    retl
 entry:
 	%tmp12 = trunc i32 %X to i8		; <i8> [#uses=1]
 	%tmp123 = sext i8 %tmp12 to i32		; <i32> [#uses=1]
@@ -25,11 +20,6 @@ entry:
 ; CHECK:      movswl {{.*}}, %eax
 ; CHECK-NEXT: ret
 define i32 @test2(ptr %this) {
-; CHECK-LABEL: test2:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; CHECK-NEXT:    movswl 6(%eax), %eax
-; CHECK-NEXT:    retl
 entry:
   %b48 = getelementptr inbounds { i16, [6 x i8] }, ptr %this, i32 0, i32 1
   %bf.load = load i48, ptr %b48, align 2
diff --git a/llvm/test/CodeGen/X86/sext-ret-val.ll b/llvm/test/CodeGen/X86/sext-ret-val.ll
index aac4fddd0b6ea..250d310ebb143 100644
--- a/llvm/test/CodeGen/X86/sext-ret-val.ll
+++ b/llvm/test/CodeGen/X86/sext-ret-val.ll
@@ -1,29 +1,26 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-unknown-linux-gnu | FileCheck %s
 ; rdar://6699246
 
 define signext i8 @t1(ptr %A) nounwind readnone ssp {
-; CHECK-LABEL: t1:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
-; CHECK-NEXT:    setne %al
-; CHECK-NEXT:    retl
 entry:
         %0 = icmp ne ptr %A, null
         %1 = zext i1 %0 to i8
         ret i8 %1
 
+; CHECK-LABEL: t1:
+; CHECK: cmpl
+; CHECK-NEXT: setne
+; CHECK-NEXT: retl
 }
 
 define i8 @t2(ptr %A) nounwind readnone ssp {
-; CHECK-LABEL: t2:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
-; CHECK-NEXT:    setne %al
-; CHECK-NEXT:    retl
 entry:
         %0 = icmp ne ptr %A, null
         %1 = zext i1 %0 to i8
         ret i8 %1
 
+; CHECK-LABEL: t2:
+; CHECK: cmpl
+; CHECK-NEXT: setne
+; CHECK-NEXT: retl
 }

>From 5124c6aad08d20a0ac5ebe59b085bfe29b6caf23 Mon Sep 17 00:00:00 2001
From: fbrv <fabio.baravalle at gmail.com>
Date: Sun, 8 Feb 2026 18:32:19 +0000
Subject: [PATCH 5/5] revert zext-inreg-0.ll changes

---
 llvm/test/CodeGen/X86/zext-inreg-0.ll | 144 --------------------------
 1 file changed, 144 deletions(-)

diff --git a/llvm/test/CodeGen/X86/zext-inreg-0.ll b/llvm/test/CodeGen/X86/zext-inreg-0.ll
index d551a91a9be36..72fd6885dcdec 100644
--- a/llvm/test/CodeGen/X86/zext-inreg-0.ll
+++ b/llvm/test/CodeGen/X86/zext-inreg-0.ll
@@ -1,4 +1,3 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=i686-- | FileCheck -check-prefix=X86 %s
 ; RUN: llc < %s -mtriple=x86_64-- | FileCheck -check-prefix=X64 %s
 
@@ -13,200 +12,57 @@
 ; This related to not having a ZERO_EXTEND_REG opcode.
 
 define i32 @a(i32 %d) nounwind  {
-; X86-LABEL: a:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzbl %al, %eax
-; X86-NEXT:    retl
-;
-; X64-LABEL: a:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzbl %dil, %eax
-; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = and i32 %e, 255
         ret i32 %retval
 }
 define i32 @b(float %d) nounwind  {
-; X86-LABEL: b:
-; X86:       # %bb.0:
-; X86-NEXT:    subl $8, %esp
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fnstcw {{[0-9]+}}(%esp)
-; X86-NEXT:    movzwl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    orl $3072, %eax # imm = 0xC00
-; X86-NEXT:    movw %ax, {{[0-9]+}}(%esp)
-; X86-NEXT:    fldcw {{[0-9]+}}(%esp)
-; X86-NEXT:    fistps {{[0-9]+}}(%esp)
-; X86-NEXT:    fldcw {{[0-9]+}}(%esp)
-; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    addl $8, %esp
-; X86-NEXT:    retl
-;
-; X64-LABEL: b:
-; X64:       # %bb.0:
-; X64-NEXT:    cvttss2si %xmm0, %eax
-; X64-NEXT:    movzbl %al, %eax
-; X64-NEXT:    retq
         %tmp12 = fptoui float %d to i8
         %retval = zext i8 %tmp12 to i32
         ret i32 %retval
 }
 define i32 @c(i32 %d) nounwind  {
-; X86-LABEL: c:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzwl %ax, %eax
-; X86-NEXT:    retl
-;
-; X64-LABEL: c:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzwl %di, %eax
-; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = and i32 %e, 65535
         ret i32 %retval
 }
 define i64 @d(i64 %d) nounwind  {
-; X86-LABEL: d:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzbl %al, %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: d:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzbl %dil, %eax
-; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 255
         ret i64 %retval
 }
 define i64 @e(i64 %d) nounwind  {
-; X86-LABEL: e:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzwl %ax, %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: e:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzwl %di, %eax
-; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 65535
         ret i64 %retval
 }
 define i64 @f(i64 %d) nounwind  {
-; X86-LABEL: f:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: f:
-; X64:       # %bb.0:
-; X64-NEXT:    leal 1(%rdi), %eax
-; X64-NEXT:    retq
         %e = add i64 %d, 1
         %retval = and i64 %e, 4294967295
         ret i64 %retval
 }
 
 define i32 @g(i8 %d) nounwind  {
-; X86-LABEL: g:
-; X86:       # %bb.0:
-; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incb %al
-; X86-NEXT:    movzbl %al, %eax
-; X86-NEXT:    retl
-;
-; X64-LABEL: g:
-; X64:       # %bb.0:
-; X64-NEXT:    incb %dil
-; X64-NEXT:    movzbl %dil, %eax
-; X64-NEXT:    retq
         %e = add i8 %d, 1
         %retval = zext i8 %e to i32
         ret i32 %retval
 }
 define i32 @h(i16 %d) nounwind  {
-; X86-LABEL: h:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzwl %ax, %eax
-; X86-NEXT:    retl
-;
-; X64-LABEL: h:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzwl %di, %eax
-; X64-NEXT:    retq
         %e = add i16 %d, 1
         %retval = zext i16 %e to i32
         ret i32 %retval
 }
 define i64 @i(i8 %d) nounwind  {
-; X86-LABEL: i:
-; X86:       # %bb.0:
-; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incb %al
-; X86-NEXT:    movzbl %al, %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: i:
-; X64:       # %bb.0:
-; X64-NEXT:    incb %dil
-; X64-NEXT:    movzbl %dil, %eax
-; X64-NEXT:    retq
         %e = add i8 %d, 1
         %retval = zext i8 %e to i64
         ret i64 %retval
 }
 define i64 @j(i16 %d) nounwind  {
-; X86-LABEL: j:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    movzwl %ax, %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: j:
-; X64:       # %bb.0:
-; X64-NEXT:    incl %edi
-; X64-NEXT:    movzwl %di, %eax
-; X64-NEXT:    retq
         %e = add i16 %d, 1
         %retval = zext i16 %e to i64
         ret i64 %retval
 }
 define i64 @k(i32 %d) nounwind  {
-; X86-LABEL: k:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    incl %eax
-; X86-NEXT:    xorl %edx, %edx
-; X86-NEXT:    retl
-;
-; X64-LABEL: k:
-; X64:       # %bb.0:
-; X64-NEXT:    # kill: def $edi killed $edi def $rdi
-; X64-NEXT:    leal 1(%rdi), %eax
-; X64-NEXT:    retq
         %e = add i32 %d, 1
         %retval = zext i32 %e to i64
         ret i64 %retval



More information about the llvm-commits mailing list