[llvm] [SCEV] Fix sign bits of pointers wider than their index type. (PR #225786)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 07:05:35 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/225786

ComputeNumSignBits counts bits over the full pointer width. If all sign bits are in the high bits, the code previously did not adjust the number of signed bits. For narrow index types, this could result in the number of sign bits > than the narrow bitwidth triggering an assert in APInt (test example has 64 bit pointer with 16 bit index width.

If all sign bits are in the high bits outside the index width, they do not add any information for the index, just use 1 in that case.

Fixes a crash in the added tests.

>From 2e5e3385d9a6dba444c06ab9d4cc37c014ecb2e7 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 23 Sep 2026 13:45:56 +0100
Subject: [PATCH] [SCEV] Fix sign bits of pointers wider than their index type.

ComputeNumSignBits counts bits over the full pointer width. If all sign
bits are in the high bits, the code previously did not adjust the number
of signed bits. For narrow index types, this could result in the number
of sign bits > than the narrow bitwidth triggering an assert in APInt
(test example has 64 bit pointer with 16 bit index width.

If all sign bits are in the high bits outside the index width, they do
not add any information for the index, just use 1 in that case.

Fixes a crash in the added tests.
---
 llvm/lib/Analysis/ScalarEvolution.cpp         | 11 ++-
 .../ptrtoaddr-i32-index-width.ll              | 68 ++++++++++++++++++-
 2 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 8886186440658b..b822b7a5d39277 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6942,12 +6942,11 @@ const ConstantRange &ScalarEvolution::getRangeRef(
     // sign bits than for the value of those sign bits.
     unsigned NS = ComputeNumSignBits(V, DL, &AC, nullptr, &DT);
     if (U->getType()->isPointerTy()) {
-      // If the pointer size is larger than the index size type, this can cause
-      // NS to be larger than BitWidth. So compensate for this.
-      unsigned ptrSize = DL.getPointerTypeSizeInBits(U->getType());
-      int ptrIdxDiff = ptrSize - BitWidth;
-      if (ptrIdxDiff > 0 && ptrSize > BitWidth && NS > (unsigned)ptrIdxDiff)
-        NS -= ptrIdxDiff;
+      // NS counts the sign bits of the whole pointer; drop those above the
+      // index bits.
+      unsigned PtrIdxDiff =
+          DL.getPointerTypeSizeInBits(U->getType()) - BitWidth;
+      NS = NS > PtrIdxDiff ? NS - PtrIdxDiff : 1;
     }
 
     if (NS > 1) {
diff --git a/llvm/test/Analysis/ScalarEvolution/ptrtoaddr-i32-index-width.ll b/llvm/test/Analysis/ScalarEvolution/ptrtoaddr-i32-index-width.ll
index a60705e341dcfd..d65e90c1f85f6c 100644
--- a/llvm/test/Analysis/ScalarEvolution/ptrtoaddr-i32-index-width.ll
+++ b/llvm/test/Analysis/ScalarEvolution/ptrtoaddr-i32-index-width.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
 ; RUN: opt -passes='print<scalar-evolution>' -disable-output %s 2>&1 | FileCheck %s
 
-target datalayout="p:64:64:64:32"
+target datalayout="p:64:64:64:32-p2:64:64:64:16"
 
 define void @ptrtoaddr(ptr %in, ptr %out0) {
 ; CHECK-LABEL: 'ptrtoaddr'
@@ -68,3 +68,69 @@ define void @ptrtoaddr_of_gep(ptr %in, ptr %out0) {
   store i32  %p0, ptr  %out0
   ret void
 }
+
+; The high 32 bits are zero, which says nothing about the index bits.
+define void @ptrtoaddr_of_inttoptr_high_bits_zero(i64 %x, ptr %out0) {
+; CHECK-LABEL: 'ptrtoaddr_of_inttoptr_high_bits_zero'
+; CHECK-NEXT:  Classifying expressions for: @ptrtoaddr_of_inttoptr_high_bits_zero
+; CHECK-NEXT:    %m = and i64 %x, 4294967295
+; CHECK-NEXT:    --> (zext i32 (trunc i64 %x to i32) to i64) U: [0,4294967296) S: [0,4294967296)
+; CHECK-NEXT:    %p = inttoptr i64 %m to ptr
+; CHECK-NEXT:    --> %p U: full-set S: full-set
+; CHECK-NEXT:    %p0 = ptrtoaddr ptr %p to i32
+; CHECK-NEXT:    --> (ptrtoaddr ptr %p to i32) U: full-set S: full-set
+; CHECK-NEXT:  Determining loop execution counts for: @ptrtoaddr_of_inttoptr_high_bits_zero
+;
+  %m = and i64 %x, 4294967295
+  %p = inttoptr i64 %m to ptr
+  %p0 = ptrtoaddr ptr %p to i32
+  store i32 %p0, ptr %out0
+  ret void
+}
+
+; The index is less than half the pointer width.
+define void @ptrtoaddr_of_inttoptr_high_bits_zero_i16_index(i64 %x, ptr %out0) {
+; CHECK-LABEL: 'ptrtoaddr_of_inttoptr_high_bits_zero_i16_index'
+; CHECK-NEXT:  Classifying expressions for: @ptrtoaddr_of_inttoptr_high_bits_zero_i16_index
+; CHECK-NEXT:    %m = and i64 %x, 4294967295
+; CHECK-NEXT:    --> (zext i32 (trunc i64 %x to i32) to i64) U: [0,4294967296) S: [0,4294967296)
+; CHECK-NEXT:    %p = inttoptr i64 %m to ptr addrspace(2)
+; CHECK-NEXT:    --> %p U: full-set S: full-set
+; CHECK-NEXT:    %p0 = ptrtoaddr ptr addrspace(2) %p to i16
+; CHECK-NEXT:    --> (ptrtoaddr ptr addrspace(2) %p to i16) U: full-set S: full-set
+; CHECK-NEXT:  Determining loop execution counts for: @ptrtoaddr_of_inttoptr_high_bits_zero_i16_index
+;
+  %m = and i64 %x, 4294967295
+  %p = inttoptr i64 %m to ptr addrspace(2)
+  %p0 = ptrtoaddr ptr addrspace(2) %p to i16
+  store i16 %p0, ptr %out0
+  ret void
+}
+
+; The pointer has 49 sign bits, leaving 17 in the index.
+define void @ptrtoaddr_of_select_sign_bits(i1 %c, i64 %x, i64 %y, ptr %out0) {
+; CHECK-LABEL: 'ptrtoaddr_of_select_sign_bits'
+; CHECK-NEXT:  Classifying expressions for: @ptrtoaddr_of_select_sign_bits
+; CHECK-NEXT:    %a = and i64 %x, 32767
+; CHECK-NEXT:    --> (zext i15 (trunc i64 %x to i15) to i64) U: [0,32768) S: [0,32768)
+; CHECK-NEXT:    %b = or i64 %y, -32768
+; CHECK-NEXT:    --> %b U: [-32768,0) S: [-32768,0)
+; CHECK-NEXT:    %pa = inttoptr i64 %a to ptr
+; CHECK-NEXT:    --> %pa U: [0,32768) S: [0,32768)
+; CHECK-NEXT:    %pb = inttoptr i64 %b to ptr
+; CHECK-NEXT:    --> %pb U: [-32768,0) S: [-32768,0)
+; CHECK-NEXT:    %p = select i1 %c, ptr %pa, ptr %pb
+; CHECK-NEXT:    --> %p U: [-32768,32768) S: [-32768,32768)
+; CHECK-NEXT:    %p0 = ptrtoaddr ptr %p to i32
+; CHECK-NEXT:    --> (ptrtoaddr ptr %p to i32) U: [-32768,32768) S: [-32768,32768)
+; CHECK-NEXT:  Determining loop execution counts for: @ptrtoaddr_of_select_sign_bits
+;
+  %a = and i64 %x, 32767
+  %b = or i64 %y, -32768
+  %pa = inttoptr i64 %a to ptr
+  %pb = inttoptr i64 %b to ptr
+  %p = select i1 %c, ptr %pa, ptr %pb
+  %p0 = ptrtoaddr ptr %p to i32
+  store i32 %p0, ptr %out0
+  ret void
+}



More information about the llvm-commits mailing list