[llvm] [ConstantInt] Disable implicit truncation in ConstantInt::get() (PR #171456)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 9 07:26:29 PST 2025


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/171456

Disable implicit truncation in the ConstantInt constructor by default. This means that it needs to be passed a signed/unsigned (depending on the IsSigned flag) value matching the bit width.

The intention is to prevent the recurring bug where people write something like `ConstantInt::get(Ty, -1)`, and this "works" until `Ty` is larger than 64-bit and then the value is incorrect due to missing type extension.

This is the continuation of https://github.com/llvm/llvm-project/pull/112670, which originally allowed implicit truncation in this constructor to reduce initial scope of the change.

This PR is WIP. Most parts will be landed separately.

>From c0fcb4d215fd81cbd6978409b5832f2c3c4d22f6 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 12:04:38 +0100
Subject: [PATCH 1/9] [IR] Disable implicit truncation in ConstantInt::get() by
 default

---
 llvm/include/llvm/IR/Constants.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 39a556abe935b..6aa79846f10f5 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -113,9 +113,8 @@ class ConstantInt final : public ConstantData {
   /// If Ty is a vector type, return a Constant with a splat of the given
   /// value. Otherwise return a ConstantInt for the given value.
   /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
-  // TODO: Make ImplicitTrunc default to false.
   LLVM_ABI static Constant *get(Type *Ty, uint64_t V, bool IsSigned = false,
-                                bool ImplicitTrunc = true);
+                                bool ImplicitTrunc = false);
 
   /// Return a ConstantInt with the specified integer value for the specified
   /// type. If the type is wider than 64 bits, the value will be zero-extended
@@ -123,10 +122,9 @@ class ConstantInt final : public ConstantData {
   /// be interpreted as a 64-bit signed integer and sign-extended to fit
   /// the type.
   /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
-  // TODO: Make ImplicitTrunc default to false.
   LLVM_ABI static ConstantInt *get(IntegerType *Ty, uint64_t V,
                                    bool IsSigned = false,
-                                   bool ImplicitTrunc = true);
+                                   bool ImplicitTrunc = false);
 
   /// Return a ConstantInt with the specified value for the specified type. The
   /// value V will be canonicalized to an unsigned APInt. Accessing it with

>From db9c886fa52503b48d2f6ed227b14e90f1998c87 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 12:18:21 +0100
Subject: [PATCH 2/9] [SDAG] Allow implicit trunc in BUILD_VECTOR legalization

---
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 7606bc8f4a5b6..1552b6a1efa1c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -2051,7 +2051,8 @@ SDValue SelectionDAGLegalize::ExpandBUILD_VECTOR(SDNode *Node) {
           // we don't want a v16i8 to become a v16i32 for example.
           const ConstantInt *CI = V->getConstantIntValue();
           CV.push_back(ConstantInt::get(EltVT.getTypeForEVT(*DAG.getContext()),
-                                        CI->getZExtValue()));
+                                        CI->getZExtValue(), /*IsSigned=*/false,
+                                        /*ImplicitTrunc=*/true));
         }
       } else {
         assert(Node->getOperand(i).isUndef());

>From 3c1acdc1e90b2706901e912fab05b522356e4948 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 12:22:32 +0100
Subject: [PATCH 3/9] [SCEV] Allow implicit truncation for now, to reduce scope

---
 llvm/lib/Analysis/ScalarEvolution.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e1f90264be7a2..770de89eccfb9 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -485,7 +485,10 @@ const SCEV *ScalarEvolution::getConstant(const APInt &Val) {
 const SCEV *
 ScalarEvolution::getConstant(Type *Ty, uint64_t V, bool isSigned) {
   IntegerType *ITy = cast<IntegerType>(getEffectiveSCEVType(Ty));
-  return getConstant(ConstantInt::get(ITy, V, isSigned));
+  // TODO: Avoid implicit trunc?
+  // See https://github.com/llvm/llvm-project/issues/112510.
+  return getConstant(
+      ConstantInt::get(ITy, V, isSigned, /*ImplicitTrunc=*/true));
 }
 
 const SCEV *ScalarEvolution::getVScale(Type *Ty) {

>From 85d47a931d17452dda9ff0118d2a2a9e13998552 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 12:43:29 +0100
Subject: [PATCH 4/9] [MachineIRBuilder] Allow implicit trunc for now

To limit scope.
---
 llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 3906b311addf0..f4779d9a122f0 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -363,7 +363,10 @@ MachineInstrBuilder MachineIRBuilder::buildConstant(const DstOp &Res,
                                                     int64_t Val) {
   auto IntN = IntegerType::get(getMF().getFunction().getContext(),
                                Res.getLLTTy(*getMRI()).getScalarSizeInBits());
-  ConstantInt *CI = ConstantInt::get(IntN, Val, true);
+  // TODO: Avoid implicit trunc?
+  // See https://github.com/llvm/llvm-project/issues/112510.
+  ConstantInt *CI =
+      ConstantInt::get(IntN, Val, /*isSigned=*/true, /*implicitTrunc=*/true);
   return buildConstant(Res, *CI);
 }
 

>From edfd05804b1c0cc75cc0fc8d38bf1bb1657fa122 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 13:00:02 +0100
Subject: [PATCH 5/9] [ExpandFp] Adjust ConstantInt construction (NFC)

This makes two changes:
 * In one place, explicitly cast to int before negating, so that
   the value is sign extended, and getSigned() is actually passed
   a value with all the sign bits set.
 * Use getSignMask() to create the 32-bit sign mask.

This avoids issues with a future assertion in the ConstantInt
ctor.
---
 llvm/lib/CodeGen/ExpandFp.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/CodeGen/ExpandFp.cpp b/llvm/lib/CodeGen/ExpandFp.cpp
index 13ed4846d2bf7..5941c41cd743f 100644
--- a/llvm/lib/CodeGen/ExpandFp.cpp
+++ b/llvm/lib/CodeGen/ExpandFp.cpp
@@ -811,7 +811,7 @@ static void expandIToFP(Instruction *IToFP) {
   Value *Sub24 = Builder.CreateAdd(
       FloatWidth == 128 ? Call : Cast,
       ConstantInt::getSigned(Builder.getIntNTy(BitWidthNew),
-                             -(BitWidth - FPMantissaWidth - 1)));
+                             -(int)(BitWidth - FPMantissaWidth - 1)));
   Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy);
   Value *Shl26 = Builder.CreateShl(IsSigned ? Sub : IntVal,
                                    FloatWidth == 128 ? Sub24 : ShProm25);
@@ -853,7 +853,7 @@ static void expandIToFP(Instruction *IToFP) {
   } else {
     Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getInt32Ty());
     And29 = Builder.CreateAnd(
-        Conv28, ConstantInt::getSigned(Builder.getInt32Ty(), 0x80000000));
+        Conv28, ConstantInt::get(Builder.getContext(), APInt::getSignMask(32)));
   }
   unsigned TempMod = FPMantissaWidth % 32;
   Value *And34 = nullptr;

>From 17f283fdf98e3f33ea1e6eec5d52ceb16d44a098 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 14:51:18 +0100
Subject: [PATCH 6/9] [FastISel] Allow implicit trunc in FastISel for now

To reduce scope.
---
 llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
index 5c84059da273b..fa84f3615aacf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
@@ -1951,7 +1951,10 @@ Register FastISel::fastEmit_ri_(MVT VT, unsigned Opcode, Register Op0,
     // fast-isel, which would be very slow.
     IntegerType *ITy =
         IntegerType::get(FuncInfo.Fn->getContext(), VT.getSizeInBits());
-    MaterialReg = getRegForValue(ConstantInt::get(ITy, Imm));
+    // TODO: Avoid implicit trunc?
+    // See https://github.com/llvm/llvm-project/issues/112510.
+    MaterialReg = getRegForValue(
+        ConstantInt::get(ITy, Imm, /*IsSigned=*/false, /*ImplicitTrunc=*/true));
     if (!MaterialReg)
       return Register();
   }

>From cd569104837288a5f356d1d343db3422d914bfee Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 15:08:30 +0100
Subject: [PATCH 7/9] [LSR] WRITE DESCRIPTION

---
 llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
index 68cffd4c18688..10d6c73796b2a 100644
--- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
@@ -3984,10 +3984,10 @@ void LSRInstance::GenerateReassociationsImpl(LSRUse &LU, unsigned LUIdx,
     const SCEVConstant *InnerSumSC = dyn_cast<SCEVConstant>(InnerSum);
     if (InnerSumSC && SE.getTypeSizeInBits(InnerSumSC->getType()) <= 64 &&
         TTI.isLegalAddImmediate((uint64_t)F.UnfoldedOffset.getFixedValue() +
-                                InnerSumSC->getValue()->getZExtValue())) {
+                                InnerSumSC->getValue()->getSExtValue())) {
       F.UnfoldedOffset =
           Immediate::getFixed((uint64_t)F.UnfoldedOffset.getFixedValue() +
-                              InnerSumSC->getValue()->getZExtValue());
+                              InnerSumSC->getValue()->getSExtValue());
       if (IsScaledReg) {
         F.ScaledReg = nullptr;
         F.Scale = 0;
@@ -4002,10 +4002,10 @@ void LSRInstance::GenerateReassociationsImpl(LSRUse &LU, unsigned LUIdx,
     const SCEVConstant *SC = dyn_cast<SCEVConstant>(*J);
     if (SC && SE.getTypeSizeInBits(SC->getType()) <= 64 &&
         TTI.isLegalAddImmediate((uint64_t)F.UnfoldedOffset.getFixedValue() +
-                                SC->getValue()->getZExtValue()))
+                                SC->getValue()->getSExtValue()))
       F.UnfoldedOffset =
           Immediate::getFixed((uint64_t)F.UnfoldedOffset.getFixedValue() +
-                              SC->getValue()->getZExtValue());
+                              SC->getValue()->getSExtValue());
     else
       F.BaseRegs.push_back(*J);
     // We may have changed the number of register in base regs, adjust the

>From 73871d07914d5c0b89a6d13234e9ea6ee8d4384e Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 15:11:05 +0100
Subject: [PATCH 8/9] [SLSR] Allow implicit truncation for element size

For now, we should implicitly truncate overflowing allocation
sizes when expanding GEPs, like we do in other places.
---
 llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
index 2ad6f7e2e27cd..9591cd983df15 100644
--- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
@@ -1104,7 +1104,9 @@ void StraightLineStrengthReduce::allocateCandidatesAndFindBasisForGEP(
     Value *ArrayIdx = GEP->getOperand(I);
     uint64_t ElementSize = GTI.getSequentialElementStride(*DL);
     IntegerType *PtrIdxTy = cast<IntegerType>(DL->getIndexType(GEP->getType()));
-    ConstantInt *ElementSizeIdx = ConstantInt::get(PtrIdxTy, ElementSize, true);
+    // If the element size overflow the type, truncate.
+    ConstantInt *ElementSizeIdx =
+        ConstantInt::get(PtrIdxTy, ElementSize, true, /*ImplicitTrunc=*/true);
     if (ArrayIdx->getType()->getIntegerBitWidth() <=
         DL->getIndexSizeInBits(GEP->getAddressSpace())) {
       // Skip factoring if ArrayIdx is wider than the index size, because

>From 0eb2003e87a3870fbf702532ab99148cfe0719f9 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 9 Dec 2025 15:29:51 +0100
Subject: [PATCH 9/9] [Hexagon] WIP

---
 llvm/lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp b/llvm/lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp
index 297410b3ad828..c15c2b4add778 100644
--- a/llvm/lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp
@@ -493,8 +493,7 @@ void HexagonGenWideningVecInstr::updateMPYConst(Intrinsic::ID IntId,
       OP->getType()->isVectorTy()) {
     // Create a vector with all elements equal to SplatVal
     Type *VecTy = OP->getType();
-    Value *splatVector =
-        ConstantInt::get(VecTy, static_cast<uint32_t>(SplatVal));
+    Value *splatVector = ConstantInt::get(VecTy, SplatVal, !IsOPZExt);
     OP = IsOPZExt ? IRB.CreateZExt(splatVector, VecTy)
                   : IRB.CreateSExt(splatVector, VecTy);
   } else {



More information about the llvm-commits mailing list