[llvm] [SeparateConstOffsetFromGEP] Fix incorrect inbounds flag in case of non-negative index but negative offset (PR #190192)
Sergey Kachkov via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 2 09:47:12 PDT 2026
https://github.com/skachkov-sc updated https://github.com/llvm/llvm-project/pull/190192
>From 500db441681f997a736d98ee87ab392a1c6db433 Mon Sep 17 00:00:00 2001
From: Sergey Kachkov <sergey.kachkov at syntacore.com>
Date: Wed, 1 Apr 2026 19:01:00 +0300
Subject: [PATCH 1/3] [NFC][SeparateConstOffsetFromGEP] Add pre-commit test
---
.../RISCV/split-gep.ll | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
index deaffc88117dd..8cdd453f25903 100644
--- a/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
+++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
@@ -289,3 +289,24 @@ entry:
store i32 %i, ptr %gep8
ret i32 undef
}
+
+define i64 @test_inbounds(ptr %arr, i64 %x) {
+; CHECK-LABEL: @test_inbounds(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[MIN:%.*]] = tail call i64 @llvm.umin.i64(i64 [[X:%.*]], i64 4)
+; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[MIN]], -1
+; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[XOR]], 1
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [6 x i64], ptr [[ARR:%.*]], i64 0, i64 [[SHR]]
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 40
+; CHECK-NEXT: [[RES:%.*]] = load i64, ptr [[GEP2]], align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+entry:
+ %min = tail call i64 @llvm.umin.i64(i64 %x, i64 4)
+ %xor = xor i64 %min, -1
+ %shr = lshr i64 %xor, 1
+ %sub = add nsw i64 %shr, -9223372036854775803
+ %gep = getelementptr inbounds nuw [6 x i64], ptr %arr, i64 0, i64 %sub
+ %res = load i64, ptr %gep, align 8
+ ret i64 %res
+}
>From 312beb0a7e844f90eb4c61372c797fb4dd3864e9 Mon Sep 17 00:00:00 2001
From: Sergey Kachkov <sergey.kachkov at syntacore.com>
Date: Wed, 1 Apr 2026 19:23:30 +0300
Subject: [PATCH 2/3] [SeparateConstOffsetFromGEP] Fix incorrect inbounds flag
in case of non-negative index but negative offset
---
.../lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp | 9 +++++++--
.../SeparateConstOffsetFromGEP/RISCV/split-gep.ll | 4 ++--
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
index 5a38f11314b13..84ad792f44a7b 100644
--- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
+++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
@@ -1178,8 +1178,13 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
Idx = NewIdx;
AllNUWPreserved &= PreservesNUW;
}
- AllOffsetsNonNegative =
- AllOffsetsNonNegative && isKnownNonNegative(Idx, *DL);
+ // Ensure that index offset in bytes (Idx * SequentialElementStride) is
+ // non-negative. If Idx value has at least log2(Stride) + 1 zeros, it
+ // guarantees that (Idx * Stride) will have zeroed sign bit.
+ bool OffsetNonNegative =
+ computeKnownBits(Idx, *DL).countMinLeadingZeros() >=
+ Log2_64_Ceil(GTI.getSequentialElementStride(*DL)) + 1;
+ AllOffsetsNonNegative = AllOffsetsNonNegative && OffsetNonNegative;
}
}
if (ExtractBase) {
diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
index 8cdd453f25903..f696f89e2f45c 100644
--- a/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
+++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll
@@ -296,8 +296,8 @@ define i64 @test_inbounds(ptr %arr, i64 %x) {
; CHECK-NEXT: [[MIN:%.*]] = tail call i64 @llvm.umin.i64(i64 [[X:%.*]], i64 4)
; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[MIN]], -1
; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[XOR]], 1
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [6 x i64], ptr [[ARR:%.*]], i64 0, i64 [[SHR]]
-; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 40
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr [6 x i64], ptr [[ARR:%.*]], i64 0, i64 [[SHR]]
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[TMP0]], i64 40
; CHECK-NEXT: [[RES:%.*]] = load i64, ptr [[GEP2]], align 8
; CHECK-NEXT: ret i64 [[RES]]
;
>From 2d9f5845d9c688dd4bd7956381e71b6e5a0ccf3d Mon Sep 17 00:00:00 2001
From: Sergey Kachkov <sergey.kachkov at syntacore.com>
Date: Thu, 2 Apr 2026 19:46:43 +0300
Subject: [PATCH 3/3] Update AMDGPU tests
---
.../AMDGPU/preserve-inbounds.ll | 4 ++--
.../AMDGPU/reorder-gep-inbounds.ll | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/preserve-inbounds.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/preserve-inbounds.ll
index 0d21a99153ea0..000d8a55d74eb 100644
--- a/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/preserve-inbounds.ll
+++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/preserve-inbounds.ll
@@ -41,8 +41,8 @@ define ptr @sign_bit_clear(ptr %p, i64 %i) {
; CHECK-LABEL: @sign_bit_clear(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[IDX:%.*]] = and i64 [[I:%.*]], 9223372036854775807
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDX]]
-; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 4
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[IDX]]
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i8, ptr [[TMP0]], i64 4
; CHECK-NEXT: ret ptr [[ARRAYIDX]]
;
entry:
diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/reorder-gep-inbounds.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/reorder-gep-inbounds.ll
index f7c019bba5d1f..7fddf97097fc6 100644
--- a/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/reorder-gep-inbounds.ll
+++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/AMDGPU/reorder-gep-inbounds.ll
@@ -85,8 +85,8 @@ define void @inboundsNonNegative_i8i16(ptr %in.ptr, i64 %in.idx1) {
; CHECK-SAME: ptr [[IN_PTR:%.*]], i64 [[IN_IDX1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[IDXPROM:%.*]] = and i64 [[IN_IDX1]], 9223372036854775807
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i16, ptr [[IN_PTR]], i64 [[IDXPROM]]
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 1024
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i16, ptr [[IN_PTR]], i64 [[IDXPROM]]
+; CHECK-NEXT: [[IDX11:%.*]] = getelementptr i8, ptr [[TMP0]], i64 1024
; CHECK-NEXT: ret void
;
entry:
@@ -262,8 +262,8 @@ define void @addrspace1(ptr addrspace(1) %in.ptr, i64 %in.idx1) {
; CHECK-SAME: ptr addrspace(1) [[IN_PTR:%.*]], i64 [[IN_IDX1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[IN_IDX1_NNEG:%.*]] = and i64 [[IN_IDX1]], 9223372036854775807
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i128, ptr addrspace(1) [[IN_PTR]], i64 [[IN_IDX1_NNEG]]
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP0]], i64 1024
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i128, ptr addrspace(1) [[IN_PTR]], i64 [[IN_IDX1_NNEG]]
+; CHECK-NEXT: [[IDX11:%.*]] = getelementptr i8, ptr addrspace(1) [[TMP0]], i64 1024
; CHECK-NEXT: ret void
;
entry:
More information about the llvm-commits
mailing list