Skip to content

Conversation

@dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Feb 22, 2025

@dtcxzyw dtcxzyw marked this pull request as ready for review February 23, 2025 06:30
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Feb 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 23, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

Alive2: https://alive2.llvm.org/ce/z/2KE8zG


Full diff: https://github.com/llvm/llvm-project/pull/128365.diff

8 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+6-2)
  • (modified) llvm/lib/Transforms/InstCombine/InstCombineInternal.h (+4-1)
  • (modified) llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp (+22-4)
  • (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+4-2)
  • (modified) llvm/test/Transforms/InstCombine/load.ll (+12)
  • (modified) llvm/test/Transforms/InstCombine/nonnull-select.ll (+98)
  • (modified) llvm/test/Transforms/InstCombine/store.ll (+12)
  • (modified) llvm/test/Transforms/PhaseOrdering/memset-combine.ll (+2-4)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 54f777ab20a7a..63f2fd0a733ce 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3996,8 +3996,12 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
     if (V->getType()->isPointerTy()) {
       // Simplify the nonnull operand if the parameter is known to be nonnull.
       // Otherwise, try to infer nonnull for it.
-      if (Call.paramHasNonNullAttr(ArgNo, /*AllowUndefOrPoison=*/true)) {
-        if (Value *Res = simplifyNonNullOperand(V)) {
+      bool HasDereferenceable = Call.getParamDereferenceableBytes(ArgNo) > 0;
+      if (Call.paramHasAttr(ArgNo, Attribute::NonNull) ||
+          (HasDereferenceable &&
+           !NullPointerIsDefined(Call.getFunction(),
+                                 V->getType()->getPointerAddressSpace()))) {
+        if (Value *Res = simplifyNonNullOperand(V, HasDereferenceable)) {
           replaceOperand(Call, ArgNo, Res);
           Changed = true;
         }
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 71c80d4c401f8..5b2af39e69f2c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -457,7 +457,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
 
   /// Simplify \p V given that it is known to be non-null.
   /// Returns the simplified value if possible, otherwise returns nullptr.
-  Value *simplifyNonNullOperand(Value *V);
+  /// If \p HasDereferenceable is true, the simplification will not perform
+  /// same object checks.
+  Value *simplifyNonNullOperand(Value *V, bool HasDereferenceable,
+                                unsigned Depth = 0);
 
 public:
   /// Create and insert the idiom we use to indicate a block is unreachable
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index 89fc1051b18dc..622884ea1eb46 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -982,8 +982,9 @@ static bool canSimplifyNullLoadOrGEP(LoadInst &LI, Value *Op) {
   return false;
 }
 
-/// TODO: Recursively simplify nonnull value to handle one-use inbounds GEPs.
-Value *InstCombinerImpl::simplifyNonNullOperand(Value *V) {
+Value *InstCombinerImpl::simplifyNonNullOperand(Value *V,
+                                                bool HasDereferenceable,
+                                                unsigned Depth) {
   if (auto *Sel = dyn_cast<SelectInst>(V)) {
     if (isa<ConstantPointerNull>(Sel->getOperand(1)))
       return Sel->getOperand(2);
@@ -992,6 +993,23 @@ Value *InstCombinerImpl::simplifyNonNullOperand(Value *V) {
       return Sel->getOperand(1);
   }
 
+  if (!V->hasOneUse())
+    return nullptr;
+
+  if (Depth == 1)
+    return nullptr;
+
+  if (auto *GEP = dyn_cast<GetElementPtrInst>(V)) {
+    if (HasDereferenceable || GEP->isInBounds()) {
+      if (auto *Res = simplifyNonNullOperand(GEP->getPointerOperand(),
+                                             HasDereferenceable, Depth + 1)) {
+        replaceOperand(*GEP, 0, Res);
+        addToWorklist(GEP);
+        return nullptr;
+      }
+    }
+  }
+
   return nullptr;
 }
 
@@ -1076,7 +1094,7 @@ Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) {
   }
 
   if (!NullPointerIsDefined(LI.getFunction(), LI.getPointerAddressSpace()))
-    if (Value *V = simplifyNonNullOperand(Op))
+    if (Value *V = simplifyNonNullOperand(Op, /*HasDereferenceable=*/true))
       return replaceOperand(LI, 0, V);
 
   return nullptr;
@@ -1444,7 +1462,7 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) {
     return eraseInstFromFunction(SI);
 
   if (!NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace()))
-    if (Value *V = simplifyNonNullOperand(Ptr))
+    if (Value *V = simplifyNonNullOperand(Ptr, /*HasDereferenceable=*/true))
       return replaceOperand(SI, 1, V);
 
   return nullptr;
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index b7748f59a0cfc..81b057c10b484 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3593,10 +3593,12 @@ Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
   Function *F = RI.getFunction();
   Type *RetTy = RetVal->getType();
   if (RetTy->isPointerTy()) {
+    bool HasDereferenceable =
+        F->getAttributes().getRetDereferenceableBytes() > 0;
     if (F->hasRetAttribute(Attribute::NonNull) ||
-        (F->getAttributes().getRetDereferenceableBytes() > 0 &&
+        (HasDereferenceable &&
          !NullPointerIsDefined(F, RetTy->getPointerAddressSpace()))) {
-      if (Value *V = simplifyNonNullOperand(RetVal))
+      if (Value *V = simplifyNonNullOperand(RetVal, HasDereferenceable))
         return replaceOperand(RI, 0, V);
     }
   }
diff --git a/llvm/test/Transforms/InstCombine/load.ll b/llvm/test/Transforms/InstCombine/load.ll
index 6c087aa87845f..a5ad1e0c21526 100644
--- a/llvm/test/Transforms/InstCombine/load.ll
+++ b/llvm/test/Transforms/InstCombine/load.ll
@@ -439,3 +439,15 @@ define i4 @test_vector_load_i4_non_byte_sized() {
   %res0 = load i4, ptr %ptr0, align 1
   ret i4 %res0
 }
+
+define i32 @load_select_with_null_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @load_select_with_null_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[SEL:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP]], align 4
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %sel = select i1 %cond, ptr %p, ptr null
+  %gep = getelementptr i8, ptr %sel, i64 %off
+  %res = load i32, ptr %gep, align 4
+  ret i32 %res
+}
diff --git a/llvm/test/Transforms/InstCombine/nonnull-select.ll b/llvm/test/Transforms/InstCombine/nonnull-select.ll
index cc000b4c88164..929919f9c42c7 100644
--- a/llvm/test/Transforms/InstCombine/nonnull-select.ll
+++ b/llvm/test/Transforms/InstCombine/nonnull-select.ll
@@ -86,4 +86,102 @@ define void @nonnull_noundef_call2(i1 %cond, ptr %p) {
   ret void
 }
 
+define void @nonnull_call_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_call_gep(
+; CHECK-NEXT:    [[PTR:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    call void @f(ptr nonnull [[GEP]])
+; CHECK-NEXT:    ret void
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr i8, ptr %ptr, i64 %off
+  call void @f(ptr nonnull %gep)
+  ret void
+}
+
+define void @nonnull_call_gep_multiuse(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_call_gep_multiuse(
+; CHECK-NEXT:    [[PTR:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    call void @f(ptr nonnull [[GEP]])
+; CHECK-NEXT:    call void @f(ptr [[GEP]])
+; CHECK-NEXT:    ret void
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr inbounds i8, ptr %ptr, i64 %off
+  call void @f(ptr nonnull %gep)
+  call void @f(ptr %gep)
+  ret void
+}
+
+define void @all_nonnull_call_gep_multiuse(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @all_nonnull_call_gep_multiuse(
+; CHECK-NEXT:    [[PTR:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    call void @f(ptr nonnull [[GEP]])
+; CHECK-NEXT:    call void @f(ptr nonnull [[GEP]])
+; CHECK-NEXT:    ret void
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr inbounds i8, ptr %ptr, i64 %off
+  call void @f(ptr nonnull %gep)
+  call void @f(ptr nonnull %gep)
+  ret void
+}
+
+define void @nonnull_call_gep_inbounds(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_call_gep_inbounds(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    call void @f(ptr nonnull [[GEP]])
+; CHECK-NEXT:    ret void
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr inbounds i8, ptr %ptr, i64 %off
+  call void @f(ptr nonnull %gep)
+  ret void
+}
+
+define void @nonnull_dereferenceable_call_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_dereferenceable_call_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    call void @f(ptr dereferenceable(1) [[GEP]])
+; CHECK-NEXT:    ret void
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr i8, ptr %ptr, i64 %off
+  call void @f(ptr dereferenceable(1) %gep)
+  ret void
+}
+
+define nonnull ptr @nonnull_ret_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_ret_gep(
+; CHECK-NEXT:    [[PTR:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    ret ptr [[GEP]]
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr i8, ptr %ptr, i64 %off
+  ret ptr %gep
+}
+
+define nonnull ptr @nonnull_ret_gep_inbounds(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_ret_gep_inbounds(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    ret ptr [[GEP]]
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr inbounds i8, ptr %ptr, i64 %off
+  ret ptr %gep
+}
+
+define dereferenceable(1) ptr @nonnull_dereferenceable_ret_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @nonnull_dereferenceable_ret_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    ret ptr [[GEP]]
+;
+  %ptr = select i1 %cond, ptr null, ptr %p
+  %gep = getelementptr i8, ptr %ptr, i64 %off
+  ret ptr %gep
+}
+
 declare void @f(ptr)
diff --git a/llvm/test/Transforms/InstCombine/store.ll b/llvm/test/Transforms/InstCombine/store.ll
index 0a2b0a5ee7987..daa40da1828b5 100644
--- a/llvm/test/Transforms/InstCombine/store.ll
+++ b/llvm/test/Transforms/InstCombine/store.ll
@@ -387,6 +387,18 @@ define void @store_select_with_unknown(i1 %cond, ptr %p, ptr %p2) {
   ret void
 }
 
+define void @store_select_with_null_gep(i1 %cond, ptr %p, i64 %off) {
+; CHECK-LABEL: @store_select_with_null_gep(
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[SEL:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 4
+; CHECK-NEXT:    ret void
+;
+  %sel = select i1 %cond, ptr %p, ptr null
+  %gep = getelementptr i8, ptr %sel, i64 %off
+  store i32 0, ptr %gep, align 4
+  ret void
+}
+
 !0 = !{!4, !4, i64 0}
 !1 = !{!"omnipotent char", !2}
 !2 = !{!"Simple C/C++ TBAA"}
diff --git a/llvm/test/Transforms/PhaseOrdering/memset-combine.ll b/llvm/test/Transforms/PhaseOrdering/memset-combine.ll
index d1de11258ed91..b1a5881bcaa9c 100644
--- a/llvm/test/Transforms/PhaseOrdering/memset-combine.ll
+++ b/llvm/test/Transforms/PhaseOrdering/memset-combine.ll
@@ -6,10 +6,8 @@
 define void @merge_memset(ptr %p, i1 %cond) {
 ; CHECK-LABEL: define void @merge_memset(
 ; CHECK-SAME: ptr [[P:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], ptr null, ptr [[P]]
-; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(4096) [[P]], i8 0, i64 4096, i1 false)
-; CHECK-NEXT:    [[OFF:%.*]] = getelementptr inbounds nuw i8, ptr [[SEL]], i64 4096
-; CHECK-NEXT:    tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(768) [[OFF]], i8 0, i64 768, i1 false)
+; CHECK-NEXT:    [[OFF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 4096
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 1 [[P]], i8 0, i64 4864, i1 false)
 ; CHECK-NEXT:    ret void
 ;
   %sel = select i1 %cond, ptr null, ptr %p

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

// Otherwise, try to infer nonnull for it.
if (Call.paramHasNonNullAttr(ArgNo, /*AllowUndefOrPoison=*/true)) {
if (Value *Res = simplifyNonNullOperand(V)) {
bool HasDereferenceable = Call.getParamDereferenceableBytes(ArgNo) > 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, could add a HasDereferenceable out parameter to paramHasNonNullAttr.

@dtcxzyw dtcxzyw merged commit 2ebc69a into llvm:main Feb 23, 2025
15 checks passed
@dtcxzyw dtcxzyw deleted the perf/simplify-nonnull-gep branch February 23, 2025 09:19
@Sterling-Augustine
Copy link
Contributor

Google is seeing some miscompiles that track back to this PR. I'm working on a sharable test case, but just wanted to put that out there in case someone else sees something similar.

@alexfh
Copy link
Contributor

alexfh commented Feb 27, 2025

Google is seeing some miscompiles that track back to this PR. I'm working on a sharable test case, but just wanted to put that out there in case someone else sees something similar.

I got an automatically reduced version of the code @Sterling-Augustine is talking about here. I'm not quite sure the interesting bits weren't distorted during reduction, but maybe this will help figuring out where the problem is: https://gcc.godbolt.org/z/YYcvG69Tf

$ cat reduced.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%"S1" = type { %"S2", ptr, ptr, ptr, ptr, ptr }
%"S2" = type { ptr, ptr, ptr, ptr, ptr, %"S3", i32, i8, i8, ptr, ptr, ptr }
%"S3" = type { i32, i8, i8, %union.anon.55 }
%union.anon.55 = type { ptr }

@_f1 = external global %"S1"

define void @_g1() {
  %1 = call { ptr, i8 } @_h4()
  ret void
}

define { ptr, i8 } @_h4() {
  %1 = load volatile ptr, ptr null, align 8
  %2 = call ptr @_h3(ptr %1)
  %3 = call i1 @_h1(ptr %2)
  ret { ptr, i8 } zeroinitializer
}

define ptr @_h3(ptr %0) {
  %2 = call ptr @_f3()
  %3 = load volatile ptr, ptr null, align 8
  %4 = call i1 @_f4(ptr %2, ptr %3)
  %. = select i1 %4, ptr null, ptr %0
  ret ptr %.
}

define i1 @_h1(ptr %0) {
  %2 = getelementptr inbounds i8, ptr %0, i64 16
  %3 = call ptr @_h2(ptr %2)
  ret i1 false
}

define i1 @_f4(ptr %0, ptr %1) {
  %3 = call i1 @_f5(ptr %0, ptr %1)
  %4 = xor i1 %3, true
  ret i1 %4
}

define ptr @_f3() {
  %1 = call ptr @_f2()
  ret ptr %1
}

define i1 @_f5(ptr %0, ptr %1) {
  %3 = icmp eq ptr %0, %1
  ret i1 %3
}

define ptr @_f2() {
  ret ptr @_f1
}

declare ptr @_h2(ptr)

$ diff -u <(./clang-good -O3 -g0 -emit-llvm -S -o - reduced.ll) <(./clang-bad -O3 -g0 -emit-llvm -S -o - reduced.ll)
--- /dev/fd/63  2025-02-27 15:04:35.706601363 +0100
+++ /dev/fd/62  2025-02-27 15:04:35.710601401 +0100
@@ -13,9 +13,7 @@
 define void @_g1() local_unnamed_addr {
   %1 = load volatile ptr, ptr null, align 4294967296
   %2 = load volatile ptr, ptr null, align 4294967296
-  %.not.i.i = icmp eq ptr %2, @_f1
-  %..i.i = select i1 %.not.i.i, ptr %1, ptr null
-  %3 = getelementptr inbounds nuw i8, ptr %..i.i, i64 16
+  %3 = getelementptr inbounds nuw i8, ptr %1, i64 16
   %4 = tail call ptr @_h2(ptr nonnull %3)
   ret void
 }
@@ -23,9 +21,7 @@
 define { ptr, i8 } @_h4() local_unnamed_addr {
   %1 = load volatile ptr, ptr null, align 4294967296
   %2 = load volatile ptr, ptr null, align 4294967296
-  %.not.i = icmp eq ptr %2, @_f1
-  %..i = select i1 %.not.i, ptr %1, ptr null
-  %3 = getelementptr inbounds nuw i8, ptr %..i, i64 16
+  %3 = getelementptr inbounds nuw i8, ptr %1, i64 16
   %4 = tail call ptr @_h2(ptr nonnull %3)
   ret { ptr, i8 } zeroinitializer
 }

@alexfh
Copy link
Contributor

alexfh commented Feb 27, 2025

Google is seeing some miscompiles that track back to this PR. I'm working on a sharable test case, but just wanted to put that out there in case someone else sees something similar.

I got an automatically reduced version of the code @Sterling-Augustine is talking about here. I'm not quite sure the interesting bits weren't distorted during reduction, but maybe this will help figuring out where the problem is: https://gcc.godbolt.org/z/YYcvG69Tf

I found a UB in the original C++ code, so maybe there's no miscompilation, just wrong user code. Nevertheless, please double-check if the input I provided is handled as intended.

@alexfh
Copy link
Contributor

alexfh commented Feb 27, 2025

Google is seeing some miscompiles that track back to this PR. I'm working on a sharable test case, but just wanted to put that out there in case someone else sees something similar.

I got an automatically reduced version of the code @Sterling-Augustine is talking about here. I'm not quite sure the interesting bits weren't distorted during reduction, but maybe this will help figuring out where the problem is: https://gcc.godbolt.org/z/YYcvG69Tf

I found a UB in the original C++ code, so maybe there's no miscompilation, just wrong user code. Nevertheless, please double-check if the input I provided is handled as intended.

On a second thought, the original code may have been correct.

@bgra8
Copy link
Contributor

bgra8 commented Feb 28, 2025

@dtcxzyw we (at google) have analyzed the code that is now broken by this change and decided it was correct. Can you please take a look at the reduced version @alexfh posted in #128365 (comment) and let us know if anything sticks out to you?

@nikic
Copy link
Contributor

nikic commented Feb 28, 2025

As far as I can tell, the transform on the provided IR is correct. Did you check your code under -fsanitize=pointer-overflow? Most likely, you are adding an offset to a null pointer, and that sanitizer should reliably detect that.

@alexfh
Copy link
Contributor

alexfh commented Mar 11, 2025

As far as I can tell, the transform on the provided IR is correct. Did you check your code under -fsanitize=pointer-overflow? Most likely, you are adding an offset to a null pointer, and that sanitizer should reliably detect that.

It turned out to be even more subtle: the optimization removed the last access to a global variable, which triggered an elimination of another global variable together with its dynamic initializer, which served the purpose of registering a certain type to a global registry. So ultimately, no issue with this commit. Thanks for checking!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants