[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