[llvm] [GlobalOpt] Check if global gets compared to pointer of different obj. (PR #153789)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 15 04:14:50 PDT 2025
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/153789
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
}
```
>From e9fcbfdbc10e5e839c41eee1e8ee047b2a139894 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 15 Aug 2025 10:54:56 +0100
Subject: [PATCH 1/2] [GloablOpt] Add tests comparing global with ptrtoint.
---
.../globals-compares-with-ptrtoint.ll | 144 ++++++++++++++++++
1 file changed, 144 insertions(+)
create mode 100644 llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
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..640be038c4f9b
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
@@ -0,0 +1,144 @@
+; 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 constant i64 0
+; CHECK: @C = internal global i64 0
+; CHECK: @D = internal constant i64 0
+; CHECK: @G = internal global i64 0
+; CHECK: @H = internal constant 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: ret i64 0
+;
+ %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: ret i64 0
+;
+ %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: ret i64 0
+;
+ %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: ret i64 0
+;
+ %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
+}
>From fceb7b1f7e14d08dfef523d14cf3d80f474884c2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 15 Aug 2025 10:47:32 +0100
Subject: [PATCH 2/2] [GlobalOpt] Check if global gets compared to pointer of
different obj.
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
}
```
---
llvm/lib/Transforms/Utils/GlobalStatus.cpp | 42 +++++++++++++++++++
.../globals-compares-with-ptrtoint.ll | 18 ++++----
2 files changed, 53 insertions(+), 7 deletions(-)
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
index 640be038c4f9b..25495aa6de559 100644
--- a/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
+++ b/llvm/test/Transforms/GlobalOpt/globals-compares-with-ptrtoint.ll
@@ -17,11 +17,11 @@
;.
; CHECK: @A = internal global i64 0
-; CHECK: @B = internal constant i64 0
+; CHECK: @B = internal global i64 0
; CHECK: @C = internal global i64 0
-; CHECK: @D = internal constant i64 0
+; CHECK: @D = internal global i64 0
; CHECK: @G = internal global i64 0
-; CHECK: @H = internal constant 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 {
@@ -33,7 +33,8 @@ define i64 @A_and_B_cmp_ptrtoint_constant_expr() {
; CHECK: [[ELSE]]:
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: ret i64 0
+; 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
@@ -60,7 +61,8 @@ define i64 @G_and_H_cmp_ptrtoint_constant_expr_cmp_ops_swapped() {
; CHECK: [[ELSE]]:
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: ret i64 0
+; 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
@@ -90,7 +92,8 @@ define i64 @C_and_D_cmp_ptr_load() {
; CHECK: [[ELSE]]:
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: ret i64 0
+; 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
@@ -123,7 +126,8 @@ define i64 @D_and_E_cmp_ptrtoint_constant_expr() {
; CHECK: [[ELSE]]:
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: ret i64 0
+; 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
More information about the llvm-commits
mailing list