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
