[llvm] 5c2565b - [InstCombine] Fix assertion in GEP exact div/shr index canonicalization (#201431)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 4 03:24:57 PDT 2026


Author: lijinpei-amd
Date: 2026-06-04T12:24:51+02:00
New Revision: 5c2565b67d086a3f56ce837424402084c37c7895

URL: https://github.com/llvm/llvm-project/commit/5c2565b67d086a3f56ce837424402084c37c7895
DIFF: https://github.com/llvm/llvm-project/commit/5c2565b67d086a3f56ce837424402084c37c7895.diff

LOG: [InstCombine] Fix assertion in GEP exact div/shr index canonicalization (#201431)

When canonicalizing the index of `(gep ptr, (div/shr exact X, C))`,
visitGetElementPtrInst builds the new index with Builder.CreateBinOp and
then sets the exact flag via
`cast<BinaryOperator>(NewOp)->setIsExact()`. If X is a constant (as can
be proved during InstCombine), the folding builder constant-folds NewOp
to a non-BinaryOperator, so the cast asserts.

Fix this by adding a CreateExactBinOp API, so the exact flag is set on creation.

Fixes #190324.

Added: 
    llvm/test/Transforms/InstCombine/gep-canonicalize-index-constfold.ll

Modified: 
    llvm/include/llvm/IR/IRBuilder.h
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 2e2fadef5cc49..99e4b748425c0 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1779,6 +1779,16 @@ class IRBuilderBase {
     return Insert(BinOp, Name);
   }
 
+  Value *CreateExactBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
+                          bool IsExact, const Twine &Name = "") {
+    if (Value *V = Folder.FoldExactBinOp(Opc, LHS, RHS, IsExact))
+      return V;
+    Instruction *BinOp = BinaryOperator::Create(Opc, LHS, RHS);
+    if (IsExact)
+      BinOp->setIsExact(IsExact);
+    return Insert(BinOp, Name);
+  }
+
   Value *CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name = "",
                           Instruction *MDFrom = nullptr) {
     assert(Cond2->getType()->isIntOrIntVectorTy(1));

diff  --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 348dd162501a0..e1ff11b8cf7c8 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3568,10 +3568,9 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
           }
 
           if (NewC.has_value()) {
-            Value *NewOp = Builder.CreateBinOp(
+            Value *NewOp = Builder.CreateExactBinOp(
                 static_cast<Instruction::BinaryOps>(ExactIns->getOpcode()), V,
-                ConstantInt::get(V->getType(), *NewC));
-            cast<BinaryOperator>(NewOp)->setIsExact();
+                ConstantInt::get(V->getType(), *NewC), /*IsExact=*/true);
             return GetElementPtrInst::Create(Builder.getInt8Ty(),
                                              GEP.getPointerOperand(), NewOp,
                                              GEP.getNoWrapFlags());

diff  --git a/llvm/test/Transforms/InstCombine/gep-canonicalize-index-constfold.ll b/llvm/test/Transforms/InstCombine/gep-canonicalize-index-constfold.ll
new file mode 100644
index 0000000000000..e44fbbf5396db
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/gep-canonicalize-index-constfold.ll
@@ -0,0 +1,70 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; The assume(false) proves %iv is 0, so canonicalizing the i64 GEP index to i8
+; folds `sdiv exact i64 0, 8` to a constant; setting the exact flag on it used
+; to assert. See https://github.com/llvm/llvm-project/issues/190324.
+define ptr @gep_exact_sdiv_index_constfolds(i1 %cond, ptr %p, i64 %next.iv) {
+; CHECK-LABEL: @gep_exact_sdiv_index_constfolds(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[OUTER:%.*]]
+; CHECK:       outer:
+; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    br label [[INNER:%.*]]
+; CHECK:       inner:
+; CHECK-NEXT:    br i1 true, label [[NESTED:%.*]], label [[OUTER]]
+; CHECK:       nested:
+; CHECK-NEXT:    br i1 true, label [[ASSUME:%.*]], label [[SIDE:%.*]]
+; CHECK:       assume:
+; CHECK-NEXT:    store i1 true, ptr poison, align 1
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[DEAD1:%.*]], label [[NESTED]]
+; CHECK:       dead1:
+; CHECK-NEXT:    ret ptr poison
+; CHECK:       side:
+; CHECK-NEXT:    br i1 [[COND]], label [[DEAD2:%.*]], label [[INNER]]
+; CHECK:       dead2:
+; CHECK-NEXT:    ret ptr null
+;
+entry:
+  br label %outer
+
+outer:
+  %iv = phi i64 [ 0, %entry ], [ %next.iv, %inner ]
+  %idx = sdiv exact i64 %iv, 64
+  %gep = getelementptr i64, ptr %p, i64 %idx
+  store i64 0, ptr %gep, align 8
+  br label %inner
+
+inner:
+  %j = phi i8 [ 0, %outer ], [ %next.j, %side ]
+  %j32 = sext i8 %j to i32
+  %j.is.zero = icmp eq i32 %j32, 0
+  br i1 %j.is.zero, label %nested, label %outer
+
+nested:
+  %k = phi i8 [ 0, %inner ], [ %next.k, %assume ]
+  %k32 = sext i8 %k to i32
+  %k.is.zero = icmp eq i32 %k32, 0
+  br i1 %k.is.zero, label %assume, label %side
+
+assume:
+  call void @llvm.assume(i1 false)
+  %k.add = add i32 %k32, 0
+  %next.k = trunc i32 %k.add to i8
+  br i1 %cond, label %dead1, label %nested
+
+dead1:
+  %dead.ptr1 = inttoptr i64 %idx to ptr
+  ret ptr %dead.ptr1
+
+side:
+  %j.add = add i32 %j32, 0
+  %next.j = trunc i32 %j.add to i8
+  br i1 %cond, label %dead2, label %inner
+
+dead2:
+  %dead.ptr2 = inttoptr i64 %idx to ptr
+  ret ptr %dead.ptr2
+}
+
+declare void @llvm.assume(i1 noundef)


        


More information about the llvm-commits mailing list