[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