Author: Andy Kaylor
Date: 2026-08-13T16:48:11-07:00
New Revision: 23ca09c96d24b5cd06f54a3c764e9acede166b44

URL: 
https://github.com/llvm/llvm-project/commit/23ca09c96d24b5cd06f54a3c764e9acede166b44
DIFF: 
https://github.com/llvm/llvm-project/commit/23ca09c96d24b5cd06f54a3c764e9acede166b44.diff

LOG: [CIR] Implement CIRBasicAliasAnalysis::getUnderlyingObject (#215683)

This implements the CIRBasicAliasAnalysis::getUnderlyingObject to follow
casts, pointer strides, array element, and struct member accesses back
to the underlying alloca operation if the operation does not introduce
an offset from the original pointer operand.

This still conservatively returns MayAlias for any comparison involving
a pointer with a non-zero offset from its base alloca address. We could
go further, calculating the offset and determining non-alias or partial
alias from offset pointers, but that is deferred until a future PR.

Assisted-by: Claude / Sonnet-4.6

Added: 
    clang/test/CIR/Analysis/alias-analysis-underlying-object.cir

Modified: 
    clang/include/clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h
    clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h 
b/clang/include/clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h
index f653534060080..014688092c597 100644
--- a/clang/include/clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h
+++ b/clang/include/clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h
@@ -27,6 +27,15 @@ namespace cir {
 /// sites. Conservative defaults (MayAlias / ModRef) are returned for cases
 /// that are not yet handled.
 class CIRBasicAliasAnalysis {
+  enum class ObjectRelation {
+    /// Provably 
diff erent underlying allocations.
+    Distinct,
+    /// Same underlying allocation, no offset.
+    Identical,
+    /// Cannot determine the relationship.
+    Unknown,
+  };
+
 public:
   CIRBasicAliasAnalysis() = default;
   CIRBasicAliasAnalysis(CIRBasicAliasAnalysis &&) = default;
@@ -50,9 +59,11 @@ class CIRBasicAliasAnalysis {
   /// no more specific source is found.
   mlir::Value getUnderlyingObject(mlir::Value val);
 
-  /// Return true if `lhs` and `rhs` are provably 
diff erent allocations and
-  /// therefore cannot alias.
-  bool areDistinctObjects(mlir::Value lhs, mlir::Value rhs);
+  /// Classify the relationship between \p lhs and \p rhs.  Returns one of:
+  ///   Distinct      – provably 
diff erent allocations
+  ///   Identical     – same allocation, no offset
+  ///   Unknown       – cannot determine
+  ObjectRelation classifyObjects(mlir::Value lhs, mlir::Value rhs);
 };
 
 } // namespace cir

diff  --git a/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp 
b/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
index d56454ddb4586..ceaca4916fdae 100644
--- a/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
+++ b/clang/lib/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.cpp
@@ -8,6 +8,7 @@
 
 #include "clang/CIR/Dialect/Analysis/CIRBasicAliasAnalysis.h"
 #include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "llvm/Support/DebugLog.h"
 
@@ -20,17 +21,117 @@ using namespace cir;
 // Helpers
 
//===----------------------------------------------------------------------===//
 
+static constexpr unsigned MaxLookupDepth = 6;
+
 mlir::Value CIRBasicAliasAnalysis::getUnderlyingObject(mlir::Value val) {
   LDBG() << "Getting underlying object for: " << val;
 
-  // TODO: Walk through cir.ptr_stride, cir.cast, cir.get_member, etc.
-  // to find the root allocation (cir.alloca, cir.global_addr, function args).
-  LDBG() << "Not yet implemented";
+  for (unsigned depth = 0; depth < MaxLookupDepth; ++depth) {
+    mlir::Operation *defOp = val.getDefiningOp();
+    if (!defOp) {
+      LDBG() << "No defining operation, stopping";
+      break; // Block argument (e.g. function parameter) — stop here.
+    }
+
+    // Bitcast and address-space casts don't change the underlying object.
+    // array_to_ptrdecay produces an element pointer to the same storage as
+    // the array pointer, so strip through it too.
+    if (auto castOp = mlir::dyn_cast<cir::CastOp>(defOp)) {
+      if (castOp.isAllocaPreservingCast() ||
+          castOp.getKind() == cir::CastKind::array_to_ptrdecay) {
+        LDBG() << "Walking past cast operation";
+        val = castOp.getSrc();
+        continue;
+      }
+      LDBG() << "Opaque cast operation, stopping";
+      break;
+    }
+
+    // Pointer stride: only strip through when we can prove the access stays
+    // within the bounds of the underlying allocation.
+    if (auto strideOp = mlir::dyn_cast<cir::PtrStrideOp>(defOp)) {
+      auto constOp = strideOp.getStride().getDefiningOp<cir::ConstantOp>();
+      if (constOp) {
+        if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(constOp.getValue())) {
+          APInt stride = intAttr.getValue();
+
+          // Zero stride is trivially in-bounds.
+          if (stride.isZero()) {
+            LDBG() << "Walking past zero-strided PtrStrideOp";
+            val = strideOp.getBase();
+            continue;
+          }
+        }
+      }
+      // Dynamic stride or unverifiable bounds — stop here conservatively.
+      LDBG() << "Non-zero or dynamic PtrStrideOp, stopping";
+      break;
+    }
+
+    // Handle special cases for zero-offset sub-object accesses.
+    if (auto op = mlir::dyn_cast<cir::GetMemberOp>(defOp)) {
+      if (op.getIndex() == 0) {
+        LDBG() << "GetMemberOp[0], following to underlying object";
+        val = op.getAddr();
+        continue;
+      } else {
+        LDBG() << "GetMemberOp, non-zero index, stopping";
+        break;
+      }
+    }
+    if (auto op = mlir::dyn_cast<cir::GetElementOp>(defOp)) {
+      cir::IntAttr index;
+      if (auto constOp = op.getIndex().getDefiningOp<cir::ConstantOp>())
+        index = mlir::dyn_cast<cir::IntAttr>(constOp.getValue());
+      if (index && index.getValue().isZero()) {
+        LDBG() << "GetElementOp[0], following to underlying object";
+        val = op.getBase();
+        continue;
+      }
+      LDBG() << "GetElementOp, non-zero or dynamic index, stopping";
+      break;
+    }
+    if (auto op = mlir::dyn_cast<cir::BaseClassAddrOp>(defOp)) {
+      // A zero byte offset means the base subobject starts at the same address
+      // as the derived object.
+      if (op.getOffset().isZero()) {
+        LDBG() << "BaseClassAddrOp[0], following to underlying object";
+        val = op.getDerivedAddr();
+        continue;
+      }
+      LDBG() << "BaseClassAddrOp, non-zero offset, stopping";
+      break;
+    }
+    if (auto op = mlir::dyn_cast<cir::DerivedClassAddrOp>(defOp)) {
+      // The offset is stored unsigned but applied as a negative adjustment. A
+      // zero offset means the derived object starts at the same address as the
+      // base subobject.
+      if (op.getOffset().isZero()) {
+        LDBG() << "DerivedClassAddrOp[0], following to underlying object";
+        val = op.getBaseAddr();
+        continue;
+      }
+      LDBG() << "DerivedClassAddrOp, non-zero offset, stopping";
+      break;
+    }
+    if (auto op = mlir::dyn_cast<cir::ComplexRealPtrOp>(defOp)) {
+      LDBG() << "Getting input pointer for ComplexRealPtrOp";
+      val = op.getOperand();
+      continue;
+    }
+    if (auto op = mlir::dyn_cast<cir::ComplexImagPtrOp>(defOp)) {
+      LDBG() << "ComplexImagPtrOp, stopping";
+      break;
+    }
+
+    LDBG() << "Unhandled operation, stopping";
+    break; // Unknown op — stop here conservatively.
+  }
   return val;
 }
 
-bool CIRBasicAliasAnalysis::areDistinctObjects(mlir::Value lhs,
-                                               mlir::Value rhs) {
+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 
diff erent
@@ -42,18 +143,18 @@ bool CIRBasicAliasAnalysis::areDistinctObjects(mlir::Value 
lhs,
 
   if (lhsObj == rhsObj) {
     LDBG() << "Identical values, not distinct";
-    return false;
+    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";
-    return true;
+    return ObjectRelation::Distinct;
   }
 
   LDBG() << "Conservative fallback, not distinct";
-  return false;
+  return ObjectRelation::Unknown;
 }
 
 
//===----------------------------------------------------------------------===//
@@ -69,14 +170,20 @@ mlir::AliasResult CIRBasicAliasAnalysis::alias(mlir::Value 
lhs,
     return mlir::AliasResult::MustAlias;
   }
 
-  if (areDistinctObjects(lhs, rhs)) {
+  ObjectRelation relation = classifyObjects(lhs, rhs);
+  switch (relation) {
+  case ObjectRelation::Distinct:
     LDBG() << "No alias between distinct objects";
     return mlir::AliasResult::NoAlias;
+  case ObjectRelation::Identical:
+    LDBG() << "Must alias between identical objects";
+    return mlir::AliasResult::MustAlias;
+  case ObjectRelation::Unknown:
+    // Conservative fallback — the aggregate will try other implementations.
+    LDBG() << "Conservative fallback, may alias";
+    return mlir::AliasResult::MayAlias;
   }
-
-  // Conservative fallback — the aggregate will try other implementations.
-  LDBG() << "Conservative fallback, may alias";
-  return mlir::AliasResult::MayAlias;
+  llvm_unreachable("Unhandled ObjectRelation");
 }
 
 mlir::ModRefResult CIRBasicAliasAnalysis::getModRef(mlir::Operation *op,

diff  --git a/clang/test/CIR/Analysis/alias-analysis-underlying-object.cir 
b/clang/test/CIR/Analysis/alias-analysis-underlying-object.cir
new file mode 100644
index 0000000000000..73768fcd44241
--- /dev/null
+++ b/clang/test/CIR/Analysis/alias-analysis-underlying-object.cir
@@ -0,0 +1,305 @@
+// Use --mlir-disable-threading so that the AA queries are serialized
+// as well as their diagnostic output.
+// RUN: cir-opt %s 
-pass-pipeline='builtin.module(cir.func(test-cir-alias-analysis))' \
+// RUN:   -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
+
+// -----
+
+// CHECK-LABEL: Testing : "bitcast_strips_to_alloca"
+// CHECK-DAG: x#0 <-> y#0: NoAlias
+// CHECK-DAG: x#0 <-> bc#0: MustAlias
+// CHECK-DAG: y#0 <-> bc#0: NoAlias
+
+!s32i = !cir.int<s, 32>
+!u8i  = !cir.int<u, 8>
+cir.func @bitcast_strips_to_alloca() {
+  %x = cir.alloca "x" align(4) : !cir.ptr<!s32i> {test.ptr = "x"}
+  %y = cir.alloca "y" align(4) : !cir.ptr<!s32i> {test.ptr = "y"}
+  %bc = cir.cast bitcast %x : !cir.ptr<!s32i> -> !cir.ptr<!u8i> {test.ptr = 
"bc"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "array_to_ptrdecay_strips_to_alloca"
+// CHECK-DAG: arr#0 <-> other#0: NoAlias
+// CHECK-DAG: arr#0 <-> ptr#0: MustAlias
+// CHECK-DAG: other#0 <-> ptr#0: NoAlias
+
+!s32i = !cir.int<s, 32>
+cir.func @array_to_ptrdecay_strips_to_alloca() {
+  %arr   = cir.alloca "arr"   align(4) : !cir.ptr<!cir.array<!s32i x 4>> 
{test.ptr = "arr"}
+  %other = cir.alloca "other" align(4) : !cir.ptr<!s32i> {test.ptr = "other"}
+  %ptr   = cir.cast array_to_ptrdecay %arr
+             : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i> {test.ptr = 
"ptr"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "ptr_stride_zero_strips_to_alloca"
+// CHECK-DAG: arr#0 <-> other#0: NoAlias
+// CHECK-DAG: arr#0 <-> ptr#0: MustAlias
+// CHECK-DAG: other#0 <-> ptr#0: NoAlias
+// CHECK-DAG: arr#0 <-> elem#0: MustAlias
+// CHECK-DAG: other#0 <-> elem#0: NoAlias
+// CHECK-DAG: ptr#0 <-> elem#0: MustAlias
+
+!s32i = !cir.int<s, 32>
+cir.func @ptr_stride_zero_strips_to_alloca() {
+  %arr   = cir.alloca "arr"   align(4) : !cir.ptr<!cir.array<!s32i x 4>> 
{test.ptr = "arr"}
+  %other = cir.alloca "other" align(4) : !cir.ptr<!s32i> {test.ptr = "other"}
+  %ptr   = cir.cast array_to_ptrdecay %arr
+             : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i> {test.ptr = 
"ptr"}
+  %zero  = cir.const #cir.int<0> : !s32i
+  %elem  = cir.ptr_stride %ptr, %zero : (!cir.ptr<!s32i>, !s32i) -> 
!cir.ptr<!s32i>
+             {test.ptr = "elem"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "ptr_stride_inbounds_strips_to_alloca"
+// CHECK-DAG: arr#0 <-> other#0: NoAlias
+// CHECK-DAG: arr#0 <-> ptr#0: MustAlias
+// CHECK-DAG: other#0 <-> ptr#0: NoAlias
+// CHECK-DAG: arr#0 <-> elem#0: MayAlias
+// CHECK-DAG: other#0 <-> elem#0: MayAlias
+// CHECK-DAG: ptr#0 <-> elem#0: MayAlias
+
+!s32i = !cir.int<s, 32>
+cir.func @ptr_stride_inbounds_strips_to_alloca() {
+  %arr   = cir.alloca "arr"   align(4) : !cir.ptr<!cir.array<!s32i x 4>> 
{test.ptr = "arr"}
+  %other = cir.alloca "other" align(4) : !cir.ptr<!s32i> {test.ptr = "other"}
+  %ptr   = cir.cast array_to_ptrdecay %arr
+             : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i> {test.ptr = 
"ptr"}
+  %two   = cir.const #cir.int<2> : !s32i
+  %elem  = cir.ptr_stride %ptr, %two : (!cir.ptr<!s32i>, !s32i) -> 
!cir.ptr<!s32i>
+             {test.ptr = "elem"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "ptr_stride_dynamic_not_stripped"
+// CHECK-DAG: arr#0 <-> other#0: NoAlias
+// CHECK-DAG: arr#0 <-> ptr#0: MustAlias
+// CHECK-DAG: other#0 <-> ptr#0: NoAlias
+// CHECK-DAG: arr#0 <-> dyn#0: MayAlias
+// CHECK-DAG: other#0 <-> dyn#0: MayAlias
+// CHECK-DAG: ptr#0 <-> dyn#0: MayAlias
+
+!s32i = !cir.int<s, 32>
+cir.func @ptr_stride_dynamic_not_stripped(%n: !s32i) {
+  %arr   = cir.alloca "arr"   align(4) : !cir.ptr<!cir.array<!s32i x 4>> 
{test.ptr = "arr"}
+  %other = cir.alloca "other" align(4) : !cir.ptr<!s32i> {test.ptr = "other"}
+  %ptr   = cir.cast array_to_ptrdecay %arr
+             : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i> {test.ptr = 
"ptr"}
+  %dyn   = cir.ptr_stride %ptr, %n : (!cir.ptr<!s32i>, !s32i) -> 
!cir.ptr<!s32i>
+             {test.ptr = "dyn"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "get_member_distinct_allocas"
+// CHECK-DAG: s1#0 <-> s2#0: NoAlias
+// CHECK-DAG: s1#0 <-> m1_0#0: MustAlias
+// CHECK-DAG: s2#0 <-> m1_0#0: NoAlias
+// CHECK-DAG: s1#0 <-> m1_1#0: MayAlias
+// CHECK-DAG: s2#0 <-> m1_1#0: MayAlias
+// CHECK-DAG: m1_0#0 <-> m1_1#0: MayAlias
+// CHECK-DAG: s1#0 <-> m2_0#0: NoAlias
+// CHECK-DAG: s2#0 <-> m2_0#0: MustAlias
+// CHECK-DAG: m1_0#0 <-> m2_0#0: NoAlias
+// CHECK-DAG: m1_1#0 <-> m2_0#0: MayAlias
+// CHECK-DAG: s1#0 <-> m2_1#0: MayAlias
+// CHECK-DAG: s2#0 <-> m2_1#0: MayAlias
+// CHECK-DAG: m1_0#0 <-> m2_1#0: MayAlias
+// CHECK-DAG: m1_1#0 <-> m2_1#0: MayAlias
+// CHECK-DAG: m2_0#0 <-> m2_1#0: MayAlias
+
+!s32i = !cir.int<s, 32>
+!rec_S = !cir.struct<"S" {!s32i, !s32i}>
+cir.func @get_member_distinct_allocas() {
+  %s1 = cir.alloca "s1" align(4) : !cir.ptr<!rec_S> {test.ptr = "s1"}
+  %s2 = cir.alloca "s2" align(4) : !cir.ptr<!rec_S> {test.ptr = "s2"}
+  %m1_0 = cir.get_member %s1[0] {name = "x", test.ptr = "m1_0"}
+          : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+  %m1_1 = cir.get_member %s1[1] {name = "y", test.ptr = "m1_1"}
+          : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+  %m2_0 = cir.get_member %s2[0] {name = "x", test.ptr = "m2_0"}
+          : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+  %m2_1 = cir.get_member %s2[1] {name = "y", test.ptr = "m2_1"}
+          : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "get_element_distinct_allocas"
+// CHECK-DAG: a1#0 <-> a2#0: NoAlias
+// CHECK-DAG: a1#0 <-> e1_0#0: MustAlias
+// CHECK-DAG: a2#0 <-> e1_0#0: NoAlias
+// CHECK-DAG: a1#0 <-> e2_0#0: NoAlias
+// CHECK-DAG: a2#0 <-> e2_0#0: MustAlias
+// CHECK-DAG: e1_0#0 <-> e2_0#0: NoAlias
+// CHECK-DAG: a1#0 <-> e1_1#0: MayAlias
+// CHECK-DAG: a2#0 <-> e1_1#0: MayAlias
+// CHECK-DAG: e1_0#0 <-> e1_1#0: MayAlias
+// CHECK-DAG: e2_0#0 <-> e1_1#0: MayAlias
+// CHECK-DAG: a1#0 <-> e2_1#0: MayAlias
+// CHECK-DAG: a2#0 <-> e2_1#0: MayAlias
+// CHECK-DAG: e1_0#0 <-> e2_1#0: MayAlias
+// CHECK-DAG: e2_0#0 <-> e2_1#0: MayAlias
+// CHECK-DAG: e1_1#0 <-> e2_1#0: MayAlias
+
+!s32i = !cir.int<s, 32>
+cir.func @get_element_distinct_allocas() {
+  %a1  = cir.alloca "a1" align(4) : !cir.ptr<!cir.array<!s32i x 4>> {test.ptr 
= "a1"}
+  %a2  = cir.alloca "a2" align(4) : !cir.ptr<!cir.array<!s32i x 4>> {test.ptr 
= "a2"}
+  %idx = cir.const #cir.int<0> : !s32i
+  %e1_0  = cir.get_element %a1[%idx : !s32i] {test.ptr = "e1_0"}
+           : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i>
+  %e2_0  = cir.get_element %a2[%idx : !s32i] {test.ptr = "e2_0"}
+           : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i>
+  %idx2 = cir.const #cir.int<1> : !s32i
+  %e1_1  = cir.get_element %a1[%idx2 : !s32i] {test.ptr = "e1_1"}
+           : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i>
+  %e2_1  = cir.get_element %a2[%idx2 : !s32i] {test.ptr = "e2_1"}
+           : !cir.ptr<!cir.array<!s32i x 4>> -> !cir.ptr<!s32i>
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "base_class_addr_distinct_allocas"
+// CHECK-DAG: d1#0 <-> d2#0: NoAlias
+// CHECK-DAG: d1#0 <-> base1#0: MustAlias
+// CHECK-DAG: d2#0 <-> base1#0: NoAlias
+// CHECK-DAG: d1#0 <-> base2#0: NoAlias
+// CHECK-DAG: d2#0 <-> base2#0: MustAlias
+// CHECK-DAG: base1#0 <-> base2#0: NoAlias
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!rec_Base    = !cir.struct<"Base"    {!u8i}>
+!rec_Derived = !cir.struct<"Derived" {!rec_Base, !s32i}>
+cir.func @base_class_addr_distinct_allocas() {
+  %d1    = cir.alloca "d1" align(4) : !cir.ptr<!rec_Derived> {test.ptr = "d1"}
+  %d2    = cir.alloca "d2" align(4) : !cir.ptr<!rec_Derived> {test.ptr = "d2"}
+  %base1 = cir.base_class_addr %d1 : !cir.ptr<!rec_Derived> nonnull [0]
+              -> !cir.ptr<!rec_Base> {test.ptr = "base1"}
+  %base2 = cir.base_class_addr %d2 : !cir.ptr<!rec_Derived> nonnull [0]
+              -> !cir.ptr<!rec_Base> {test.ptr = "base2"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "base_class_addr_nonzero_offset"
+// CHECK-DAG: d1#0 <-> d2#0: NoAlias
+// CHECK-DAG: d1#0 <-> base1#0: MayAlias
+// CHECK-DAG: d2#0 <-> base1#0: MayAlias
+// CHECK-DAG: d1#0 <-> base2#0: MayAlias
+// CHECK-DAG: d2#0 <-> base2#0: MayAlias
+// CHECK-DAG: base1#0 <-> base2#0: MayAlias
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!rec_Base    = !cir.struct<"Base"    {!u8i}>
+!rec_Derived = !cir.struct<"Derived" {!s32i, !rec_Base}>
+cir.func @base_class_addr_nonzero_offset() {
+  %d1    = cir.alloca "d1" align(4) : !cir.ptr<!rec_Derived> {test.ptr = "d1"}
+  %d2    = cir.alloca "d2" align(4) : !cir.ptr<!rec_Derived> {test.ptr = "d2"}
+  %base1 = cir.base_class_addr %d1 : !cir.ptr<!rec_Derived> nonnull [4]
+              -> !cir.ptr<!rec_Base> {test.ptr = "base1"}
+  %base2 = cir.base_class_addr %d2 : !cir.ptr<!rec_Derived> nonnull [4]
+              -> !cir.ptr<!rec_Base> {test.ptr = "base2"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "derived_class_addr_zero_offset"
+// CHECK-DAG: b1#0 <-> b2#0: NoAlias
+// CHECK-DAG: b1#0 <-> d1#0: MustAlias
+// CHECK-DAG: b2#0 <-> d1#0: NoAlias
+// CHECK-DAG: b1#0 <-> d2#0: NoAlias
+// CHECK-DAG: b2#0 <-> d2#0: MustAlias
+// CHECK-DAG: d1#0 <-> d2#0: NoAlias
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!rec_Base    = !cir.struct<"Base"    {!u8i}>
+!rec_Derived = !cir.struct<"Derived" {!rec_Base, !s32i}>
+cir.func @derived_class_addr_zero_offset() {
+  %b1    = cir.alloca "d1" align(4) : !cir.ptr<!rec_Base> {test.ptr = "b1"}
+  %b2    = cir.alloca "d2" align(4) : !cir.ptr<!rec_Base> {test.ptr = "b2"}
+  %d1 = cir.derived_class_addr %b1 : !cir.ptr<!rec_Base> nonnull [0]
+              -> !cir.ptr<!rec_Derived> {test.ptr = "d1"}
+  %d2 = cir.derived_class_addr %b2 : !cir.ptr<!rec_Base> nonnull [0]
+              -> !cir.ptr<!rec_Derived> {test.ptr = "d2"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "derived_class_addr_nonzero_offset"
+// CHECK-DAG: b1#0 <-> b2#0: NoAlias
+// CHECK-DAG: b1#0 <-> d1#0: MayAlias
+// CHECK-DAG: b2#0 <-> d1#0: MayAlias
+// CHECK-DAG: b1#0 <-> d2#0: MayAlias
+// CHECK-DAG: b2#0 <-> d2#0: MayAlias
+// CHECK-DAG: d1#0 <-> d2#0: MayAlias
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!rec_Base    = !cir.struct<"Base"    {!u8i}>
+!rec_Derived = !cir.struct<"Derived" {!s32i, !rec_Base}>
+cir.func @derived_class_addr_nonzero_offset() {
+  %b1    = cir.alloca "d1" align(4) : !cir.ptr<!rec_Base> {test.ptr = "b1"}
+  %b2    = cir.alloca "d2" align(4) : !cir.ptr<!rec_Base> {test.ptr = "b2"}
+  %d1 = cir.derived_class_addr %b1 : !cir.ptr<!rec_Base> nonnull [4]
+              -> !cir.ptr<!rec_Derived> {test.ptr = "d1"}
+  %d2 = cir.derived_class_addr %b2 : !cir.ptr<!rec_Base> nonnull [4]
+              -> !cir.ptr<!rec_Derived> {test.ptr = "d2"}
+  cir.return
+}
+
+// -----
+
+// CHECK-LABEL: Testing : "complex_parts_distinct_allocas"
+// CHECK-DAG: c1#0 <-> c2#0: NoAlias
+// CHECK-DAG: c1#0 <-> real1#0: MustAlias
+// CHECK-DAG: c2#0 <-> real1#0: NoAlias
+// CHECK-DAG: c1#0 <-> imag1#0: MayAlias
+// CHECK-DAG: c2#0 <-> imag1#0: MayAlias
+// CHECK-DAG: real1#0 <-> imag1#0: MayAlias
+// CHECK-DAG: c1#0 <-> real2#0: NoAlias
+// CHECK-DAG: c2#0 <-> real2#0: MustAlias
+// CHECK-DAG: real1#0 <-> real2#0: NoAlias
+// CHECK-DAG: imag1#0 <-> real2#0: MayAlias
+// CHECK-DAG: c1#0 <-> imag2#0: MayAlias
+// CHECK-DAG: c2#0 <-> imag2#0: MayAlias
+// CHECK-DAG: real1#0 <-> imag2#0: MayAlias
+// CHECK-DAG: imag1#0 <-> imag2#0: MayAlias
+// CHECK-DAG: real2#0 <-> imag2#0: MayAlias
+
+cir.func @complex_parts_distinct_allocas() {
+  %c1    = cir.alloca "c1" align(4) : !cir.ptr<!cir.complex<!cir.float>> 
{test.ptr = "c1"}
+  %c2    = cir.alloca "c2" align(4) : !cir.ptr<!cir.complex<!cir.float>> 
{test.ptr = "c2"}
+  %real1 = cir.complex.real_ptr %c1
+              : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!cir.float>
+              {test.ptr = "real1"}
+  %imag1 = cir.complex.imag_ptr %c1
+              : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!cir.float>
+              {test.ptr = "imag1"}
+  %real2 = cir.complex.real_ptr %c2
+              : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!cir.float>
+              {test.ptr = "real2"}
+  %imag2 = cir.complex.imag_ptr %c2
+              : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!cir.float>
+              {test.ptr = "imag2"}
+  cir.return
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to