[llvm] [InstCombine] Fix assertion in GEP exact div/shr index canonicalization (PR #201431)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 4 02:48:10 PDT 2026
https://github.com/lijinpei-amd updated https://github.com/llvm/llvm-project/pull/201431
>From 1415725e277014c252442db53baab01b5307dae7 Mon Sep 17 00:00:00 2001
From: Li Jinpei <jinpli at amd.com>
Date: Wed, 3 Jun 2026 22:52:23 +0800
Subject: [PATCH] [InstCombine] Fix assertion in GEP exact div/shr index
canonicalization
When canonicalizing the index of `(gep ptr, (div/shr exact X, C))`,
visitGetElementPtrInst built the new index with Builder.CreateBinOp and then
set 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.
Add a CreateExactBinOp helper to IRBuilder. Use it in visitGetElementPtrInst.
The output is unchanged for non-constant indices.
Fixes #190324.
---
llvm/include/llvm/IR/IRBuilder.h | 10 +++
.../InstCombine/InstructionCombining.cpp | 5 +-
.../gep-canonicalize-index-constfold.ll | 70 +++++++++++++++++++
3 files changed, 82 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/gep-canonicalize-index-constfold.ll
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 7c3eb46cb1cbb..20c4344e19c3c 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