[llvm] [GlobalOpt] Check if global gets compared to pointer of different obj. (PR #153789)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 15 04:15:26 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Add an extra check to the compare handling to make sure the other
compared pointer cannot be based on a different object.

For example, consider the IR below, which may write `@<!-- -->B` via a pointer constructed
from `@<!-- -->A` using PtrToInt and a compare against `@<!-- -->B`.

```
  %cmp = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @<!-- -->A to i64), i64 8) to ptr) , @<!-- -->b
  br i1 %cmp, label %then, label %else

then:
  store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @<!-- -->A to i64), i64 8) to ptr)
  br label %exit

else:
  br label %exit

exit:
  %l = load i64, ptr @<!-- -->b
  ret i64 %l
}
```

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


2 Files Affected:

- (modified) llvm/lib/Transforms/Utils/GlobalStatus.cpp (+42) 
- (added) llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll (+148) 


``````````diff
diff --git a/llvm/lib/Transforms/Utils/GlobalStatus.cpp b/llvm/lib/Transforms/Utils/GlobalStatus.cpp
index 0b3016a86e287..2452737e97278 100644
--- a/llvm/lib/Transforms/Utils/GlobalStatus.cpp
+++ b/llvm/lib/Transforms/Utils/GlobalStatus.cpp
@@ -61,6 +61,42 @@ bool llvm::isSafeToDestroyConstant(const Constant *C) {
   return true;
 }
 
+static bool maybePointerToDifferentObjectRecursive(Value *V, SmallPtrSetImpl<Value *> &Visited) {
+  if (!Visited.insert(V).second)
+    return false;
+
+  if (Visited.size() > 32)
+    return true;
+
+  // PtrToInt may be used to construct a pointer to a different object. Loads and calls may return a pointer for a different object.
+  if (isa<PtrToIntInst, LoadInst, CallInst>(V))
+    return true;
+
+  if (auto *CE = dyn_cast<ConstantExpr>(V)) {
+    if (CE->getOpcode() == Instruction::PtrToInt)
+      return true;
+
+    for (auto &Op : CE->operands()) {
+      if (maybePointerToDifferentObjectRecursive(Op.get(), Visited))
+        return true;
+    }
+    return false;
+  }
+
+  if (auto *U = dyn_cast<User>(V)) {
+    for (auto &Op : U->operands()) {
+      if (maybePointerToDifferentObjectRecursive(Op.get(), Visited))
+        return true;
+    }
+  }
+  return false;
+}
+
+bool maybePointerToDifferentObject(Value *V) {
+  SmallPtrSet<Value *, 32> Visited;
+  return maybePointerToDifferentObjectRecursive(V, Visited);
+}
+
 static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
                              SmallPtrSetImpl<const Value *> &VisitedUsers) {
   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
@@ -158,6 +194,12 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
             return true;
       } else if (isa<CmpInst>(I)) {
         GS.IsCompared = true;
+
+        if (VisitedUsers.insert(I).second) {
+          for (Value *Op : I->operands())
+            if ( Op != V && maybePointerToDifferentObject(Op))
+              return true;
+        }
       } else if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
         if (MTI->isVolatile())
           return true;
diff --git a/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll b/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
new file mode 100644
index 0000000000000..25495aa6de559
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
@@ -0,0 +1,148 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
+; RUN: opt -p globalopt -S %s | FileCheck %s
+
+ at A = internal global i64 zeroinitializer
+ at B = internal global i64 zeroinitializer
+
+ at C = internal global i64 zeroinitializer
+ at D = internal global i64 zeroinitializer
+
+ at E = internal global i64 zeroinitializer
+ at F = internal global i64 zeroinitializer
+
+ at G = internal global i64 zeroinitializer
+ at H = internal global i64 zeroinitializer
+
+
+
+;.
+; CHECK: @A = internal global i64 0
+; CHECK: @B = internal global i64 0
+; CHECK: @C = internal global i64 0
+; CHECK: @D = internal global i64 0
+; CHECK: @G = internal global i64 0
+; CHECK: @H = internal global i64 0
+;.
+define i64 @A_and_B_cmp_ptrtoint_constant_expr() {
+; CHECK-LABEL: define i64 @A_and_B_cmp_ptrtoint_constant_expr() local_unnamed_addr {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr), @B
+; CHECK-NEXT:    br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr), align 4
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[L:%.*]] = load i64, ptr @B, align 4
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %cmp = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr) , @B
+  br i1 %cmp, label %then, label %else
+
+then:
+  store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr)
+  br label %exit
+
+else:
+  br label %exit
+
+exit:
+  %l = load i64, ptr @B
+  ret i64 %l
+}
+
+define i64 @G_and_H_cmp_ptrtoint_constant_expr_cmp_ops_swapped() {
+; CHECK-LABEL: define i64 @G_and_H_cmp_ptrtoint_constant_expr_cmp_ops_swapped() local_unnamed_addr {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @G to i64), i64 8) to ptr), @H
+; CHECK-NEXT:    br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @G to i64), i64 8) to ptr), align 4
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[L:%.*]] = load i64, ptr @H, align 4
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %cmp = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @G to i64), i64 8) to ptr) , @H
+  br i1 %cmp, label %then, label %else
+
+then:
+  store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @G to i64), i64 8) to ptr)
+  br label %exit
+
+else:
+  br label %exit
+
+exit:
+  %l = load i64, ptr @H
+  ret i64 %l
+}
+
+define i64 @C_and_D_cmp_ptr_load() {
+; CHECK-LABEL: define i64 @C_and_D_cmp_ptr_load() local_unnamed_addr {
+; CHECK-NEXT:    [[P:%.*]] = alloca ptr, align 8
+; CHECK-NEXT:    store ptr inttoptr (i64 add (i64 ptrtoint (ptr @C to i64), i64 8) to ptr), ptr [[P]], align 8
+; CHECK-NEXT:    [[L_P:%.*]] = load ptr, ptr [[P]], align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[L_P]], @D
+; CHECK-NEXT:    br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @C to i64), i64 8) to ptr), align 4
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[L:%.*]] = load i64, ptr @D, align 4
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %p = alloca ptr
+  store ptr inttoptr (i64 add (i64 ptrtoint (ptr @C to i64), i64 8) to ptr), ptr %p
+  %l.p = load ptr, ptr %p
+  %cmp = icmp eq ptr %l.p, @D
+  br i1 %cmp, label %then, label %else
+
+then:
+  store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @C to i64), i64 8) to ptr)
+  br label %exit
+
+else:
+  br label %exit
+
+exit:
+  %l = load i64, ptr @D
+  ret i64 %l
+}
+
+define i64 @D_and_E_cmp_ptrtoint_constant_expr() {
+; CHECK-LABEL: define i64 @D_and_E_cmp_ptrtoint_constant_expr() local_unnamed_addr {
+; CHECK-NEXT:    [[PTR2INT:%.*]] = ptrtoint ptr @A to i64
+; CHECK-NEXT:    [[ADD:%.*]] = add i64 [[PTR2INT]], 8
+; CHECK-NEXT:    [[INT2PTR:%.*]] = inttoptr i64 [[ADD]] to ptr
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[INT2PTR]], @B
+; CHECK-NEXT:    br i1 [[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr), align 4
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[L:%.*]] = load i64, ptr @B, align 4
+; CHECK-NEXT:    ret i64 [[L]]
+;
+  %ptr2int = ptrtoint ptr @A to i64
+  %add = add i64 %ptr2int, 8
+  %int2ptr = inttoptr i64 %add to ptr
+  %cmp = icmp eq ptr %int2ptr , @B
+  br i1 %cmp, label %then, label %else
+
+then:
+  store i64 10, ptr inttoptr (i64 add (i64 ptrtoint (ptr @A to i64), i64 8) to ptr)
+  br label %exit
+
+else:
+  br label %exit
+
+exit:
+  %l = load i64, ptr @B
+  ret i64 %l
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/153789


More information about the llvm-commits mailing list