[clang] [CIR] Recognize global objects in CIRBasicAliasAnalysis (PR #216402)
Rithik Sharma via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 14 14:04:28 PDT 2026
https://github.com/SharmaRithik created https://github.com/llvm/llvm-project/pull/216402
`CIRBasicAliasAnalysis::getUnderlyingObject` can expose a `cir.get_global` root, but `classifyObjects` currently recognizes only distinct `cir.alloca` roots. Queries involving globals therefore fall back to `MayAlias`.
At the source level, this affects simple cases such as
```cpp
int first_global;
int second_global;
void use(int *, int *, int *);
void example() {
int stack;
use(&first_global, &second_global, &stack);
}
```
The addresses passed to `use` refer to three different objects, but CIR alias analysis cannot currently distinguish them.
This change resolves `cir.get_global` operations to their `cir.global` symbols and includes them in identified-object classification. Two references to the same symbol return `MustAlias`. Different resolved globals return `NoAlias` when both have stable identity. A resolved global and a `cir.alloca` return `NoAlias`.
A global-to-global query remains `MayAlias` when either symbol has an aliasee or interposable linkage. This restriction does not apply to a global-to-alloca query because an aliased or interposable symbol still cannot denote that stack object.
This change is limited to root classification. The underlying-object walk still stops at dynamic `cir.get_element` operations and call results, so those queries remain `MayAlias`.
The tests cover repeated references to one symbol, different stable globals, global aliases, interposable globals, and global-to-alloca comparisons.
>From b6dc4d43d930d4cbdbea208ac913d7b5a7b48394 Mon Sep 17 00:00:00 2001
From: SharmaRithik <rithiksh02 at gmail.com>
Date: Fri, 14 Aug 2026 21:00:11 +0000
Subject: [PATCH] [CIR] Recognize global objects in CIRBasicAliasAnalysis
`CIRBasicAliasAnalysis::getUnderlyingObject` can expose a `cir.get_global` root, but `classifyObjects` currently recognizes only distinct `cir.alloca` roots. Queries involving globals therefore fall back to `MayAlias`.
At the source level, this affects simple cases such as
```cpp
int first_global;
int second_global;
void use(int *, int *, int *);
void example() {
int stack;
use(&first_global, &second_global, &stack);
}
```
The addresses passed to `use` refer to three different objects, but CIR alias analysis cannot currently distinguish them.
This change resolves `cir.get_global` operations to their `cir.global` symbols and includes them in identified-object classification. Two references to the same symbol return `MustAlias`. Different resolved globals return `NoAlias` when both have stable identity. A resolved global and a `cir.alloca` return `NoAlias`.
A global-to-global query remains `MayAlias` when either symbol has an aliasee or interposable linkage. This restriction does not apply to a global-to-alloca query because an aliased or interposable symbol still cannot denote that stack object.
This change is limited to root classification. The underlying-object walk still stops at dynamic `cir.get_element` operations and call results, so those queries remain `MayAlias`.
The tests cover repeated references to one symbol, different stable globals, global aliases, interposable globals, and global-to-alloca comparisons.
---
.../Analysis/CIRBasicAliasAnalysis.cpp | 52 +++++++++++++---
clang/test/CIR/Analysis/alias-analysis.cir | 59 +++++++++++++++++++
2 files changed, 103 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp b/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
index ceaca4916fdae..8a0526ace2ea3 100644
--- a/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
+++ b/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h"
+#include "mlir/IR/SymbolTable.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
@@ -23,6 +24,27 @@ using namespace cir;
static constexpr unsigned MaxLookupDepth = 6;
+static mlir::Operation *getIdentifiedObject(mlir::Value value,
+ bool &mayAliasOtherGlobal) {
+ mayAliasOtherGlobal = false;
+
+ if (auto alloca = value.getDefiningOp<cir::AllocaOp>())
+ return alloca.getOperation();
+
+ auto address = value.getDefiningOp<cir::GetGlobalOp>();
+ if (!address)
+ return nullptr;
+
+ auto global = mlir::SymbolTable::lookupNearestSymbolFrom<cir::GlobalOp>(
+ address.getOperation(), address.getNameAttr());
+ if (!global)
+ return nullptr;
+
+ mayAliasOtherGlobal =
+ global.getAliasee() || cir::isInterposableLinkage(global.getLinkage());
+ return global.getOperation();
+}
+
mlir::Value CIRBasicAliasAnalysis::getUnderlyingObject(mlir::Value val) {
LDBG() << "Getting underlying object for: " << val;
@@ -134,10 +156,6 @@ CIRBasicAliasAnalysis::ObjectRelation
CIRBasicAliasAnalysis::classifyObjects(mlir::Value lhs, mlir::Value rhs) {
LDBG() << "Checking if " << lhs << " and " << rhs << " are distinct objects";
- // Two values are distinct allocations if they originate from different
- // cir.alloca operations (or other allocation ops) in the same function.
- // TODO: Extend to cover global addresses, function arguments with noalias,
- // and heap allocations.
mlir::Value lhsObj = getUnderlyingObject(lhs);
mlir::Value rhsObj = getUnderlyingObject(rhs);
@@ -146,10 +164,28 @@ CIRBasicAliasAnalysis::classifyObjects(mlir::Value lhs, mlir::Value rhs) {
return ObjectRelation::Identical;
}
- // Different cir.alloca ops in the same function cannot alias.
- if (mlir::isa_and_nonnull<cir::AllocaOp>(lhsObj.getDefiningOp()) &&
- mlir::isa_and_nonnull<cir::AllocaOp>(rhsObj.getDefiningOp())) {
- LDBG() << "Different cir.alloca ops in the same function, distinct";
+ auto lhsGlobal = lhsObj.getDefiningOp<cir::GetGlobalOp>();
+ auto rhsGlobal = rhsObj.getDefiningOp<cir::GetGlobalOp>();
+ if (lhsGlobal && rhsGlobal &&
+ lhsGlobal.getNameAttr() == rhsGlobal.getNameAttr()) {
+ LDBG() << "Same global object";
+ return ObjectRelation::Identical;
+ }
+
+ bool lhsMayAliasOtherGlobal;
+ bool rhsMayAliasOtherGlobal;
+ mlir::Operation *lhsObject =
+ getIdentifiedObject(lhsObj, lhsMayAliasOtherGlobal);
+ mlir::Operation *rhsObject =
+ getIdentifiedObject(rhsObj, rhsMayAliasOtherGlobal);
+ if (lhsObject && rhsObject) {
+ if (lhsGlobal && rhsGlobal &&
+ (lhsMayAliasOtherGlobal || rhsMayAliasOtherGlobal)) {
+ LDBG() << "Global object may resolve to another global";
+ return ObjectRelation::Unknown;
+ }
+
+ LDBG() << "Different identified objects";
return ObjectRelation::Distinct;
}
diff --git a/clang/test/CIR/Analysis/alias-analysis.cir b/clang/test/CIR/Analysis/alias-analysis.cir
index c4705ce2a9c3e..bde27e40d9099 100644
--- a/clang/test/CIR/Analysis/alias-analysis.cir
+++ b/clang/test/CIR/Analysis/alias-analysis.cir
@@ -63,3 +63,62 @@ cir.func @arg_and_alloca_no_alias(%p: !cir.ptr<!s32i>)
%local = cir.alloca "local" align(4) : !cir.ptr<!s32i> {test.ptr = "local"}
cir.return
}
+
+// -----
+
+// CHECK-LABEL: Testing : "global_objects"
+// CHECK-DAG: first_ref_a#0 <-> first_ref_b#0: MustAlias
+// CHECK-DAG: first_ref_a#0 <-> second_ref#0: NoAlias
+// CHECK-DAG: first_ref_b#0 <-> second_ref#0: NoAlias
+// CHECK-DAG: first_ref_a#0 <-> stack#0: NoAlias
+// CHECK-DAG: first_ref_b#0 <-> stack#0: NoAlias
+// CHECK-DAG: second_ref#0 <-> stack#0: NoAlias
+
+!s32i = !cir.int<s, 32>
+cir.global external dso_local @first_global = #cir.int<1> : !s32i
+cir.global external dso_local @second_global = #cir.int<2> : !s32i
+cir.func @global_objects() {
+ %first_ref_a = cir.get_global @first_global : !cir.ptr<!s32i> {test.ptr = "first_ref_a"}
+ %first_ref_b = cir.get_global @first_global : !cir.ptr<!s32i> {test.ptr = "first_ref_b"}
+ %second_ref = cir.get_global @second_global : !cir.ptr<!s32i> {test.ptr = "second_ref"}
+ %stack = cir.alloca "stack" align(4) : !cir.ptr<!s32i> {test.ptr = "stack"}
+ cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "global_alias"
+// CHECK-DAG: target_ref#0 <-> alias_ref#0: MayAlias
+// CHECK-DAG: target_ref#0 <-> unrelated_ref#0: NoAlias
+// CHECK-DAG: alias_ref#0 <-> unrelated_ref#0: MayAlias
+// CHECK-DAG: alias_ref#0 <-> stack#0: NoAlias
+
+!s32i = !cir.int<s, 32>
+cir.global internal @target_global = #cir.int<1> : !s32i
+cir.global external @target_alias alias(@target_global) : !s32i
+cir.global internal @unrelated_global = #cir.int<2> : !s32i
+cir.func @global_alias() {
+ %target_ref = cir.get_global @target_global : !cir.ptr<!s32i> {test.ptr = "target_ref"}
+ %alias_ref = cir.get_global @target_alias : !cir.ptr<!s32i> {test.ptr = "alias_ref"}
+ %unrelated_ref = cir.get_global @unrelated_global : !cir.ptr<!s32i> {test.ptr = "unrelated_ref"}
+ %stack = cir.alloca "stack" align(4) : !cir.ptr<!s32i> {test.ptr = "stack"}
+ cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "interposable_global"
+// CHECK-DAG: weak_ref_a#0 <-> weak_ref_b#0: MustAlias
+// CHECK-DAG: weak_ref_a#0 <-> internal_ref#0: MayAlias
+// CHECK-DAG: weak_ref_a#0 <-> stack#0: NoAlias
+
+!s32i = !cir.int<s, 32>
+cir.global weak @weak_global = #cir.int<1> : !s32i
+cir.global internal @internal_global = #cir.int<2> : !s32i
+cir.func @interposable_global() {
+ %weak_ref_a = cir.get_global @weak_global : !cir.ptr<!s32i> {test.ptr = "weak_ref_a"}
+ %weak_ref_b = cir.get_global @weak_global : !cir.ptr<!s32i> {test.ptr = "weak_ref_b"}
+ %internal_ref = cir.get_global @internal_global : !cir.ptr<!s32i> {test.ptr = "internal_ref"}
+ %stack = cir.alloca "stack" align(4) : !cir.ptr<!s32i> {test.ptr = "stack"}
+ cir.return
+}
More information about the cfe-commits
mailing list