https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/230841
Propagate the source pointer address space to cir.base_class_addr, cir.derived_class_addr and the virtual base pointer adjustment Fix invalid LLVM IR for class hierarchies in non-default address spaces >From 589added47f8f6cb29b3da55c0fe6e1422dc8e26 Mon Sep 17 00:00:00 2001 From: Arseniy Obolenskiy <[email protected]> Date: Sat, 10 Oct 2026 21:37:03 +0200 Subject: [PATCH] [CIR] Preserve address space in base/derived class address casts Propagate the source pointer address space to cir.base_class_addr, cir.derived_class_addr and the virtual base pointer adjustment Fix invalid LLVM IR for class hierarchies in non-default address spaces --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 + clang/lib/CIR/CodeGen/CIRGenBuilder.h | 4 +- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 7 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 20 +++++ .../test/CIR/CodeGen/base-class-addrspace.cpp | 90 +++++++++++++++++++ clang/test/CIR/IR/invalid-class-addr.cir | 27 ++++++ 6 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 clang/test/CIR/CodeGen/base-class-addrspace.cpp create mode 100644 clang/test/CIR/IR/invalid-class-addr.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 6a7d8ca8f7fc9..6a377661d8241 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -6769,6 +6769,8 @@ class CIR_ClassCastOp<string mnemonic> : CIR_Op<mnemonic, [Pure]> { `:` qualified(type($src_addr)) `->` qualified(type($result)) attr-dict }]; + + let hasVerifier = 1; } def CIR_BaseClassAddrOp : CIR_ClassCastOp<"base_class_addr"> { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 0d22c40072f63..2169bcd6bc6ac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -482,7 +482,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { if (destType == addr.getElementType()) return addr; - auto ptrTy = getPointerTo(destType); + auto ptrTy = getPointerTo(destType, addr.getAddressSpace()); auto baseAddr = cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull); @@ -495,7 +495,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { if (destType == addr.getElementType()) return addr; - cir::PointerType ptrTy = getPointerTo(destType); + cir::PointerType ptrTy = getPointerTo(destType, addr.getAddressSpace()); auto derivedAddr = cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull); diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 679fe082ac37e..9e6ff99792500 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -393,7 +393,8 @@ static Address applyNonVirtualAndVirtualOffset( // not bytes. So the pointer must be cast to a byte pointer and back. mlir::Value ptr = addr.getPointer(); - mlir::Type charPtrType = cgf.cgm.uInt8PtrTy; + mlir::Type charPtrType = + cgf.getBuilder().getPointerTo(cgf.uInt8Ty, addr.getAddressSpace()); mlir::Value charPtr = cgf.getBuilder().createBitcast(ptr, charPtrType); mlir::Value adjusted = cir::PtrStrideOp::create( cgf.getBuilder(), loc, charPtrType, charPtr, baseOffset); @@ -1256,7 +1257,6 @@ Address CIRGenFunction::getAddressOfBaseClass( // Get the base pointer type. mlir::Type baseValueTy = convertType((path.end()[-1])->getType()); - assert(!cir::MissingFeatures::addressSpace()); // If there is no virtual base, use cir.base_class_addr. It takes care of // the adjustment and the null pointer check. @@ -1277,7 +1277,8 @@ Address CIRGenFunction::getAddressOfBaseClass( CharUnits alignment = cgm.getVBaseAlignment(value.getAlignment(), derived, vBase) .alignmentAtOffset(nonVirtualOffset); - mlir::Type basePtrTy = builder.getPointerTo(baseValueTy); + mlir::Type basePtrTy = + builder.getPointerTo(baseValueTy, value.getAddressSpace()); mlir::Value ptrIsNull = builder.createPtrIsNull(value.getPointer()); mlir::Value result = cir::TernaryOp::create( diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 80696e2f7e990..0c072536603de 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -3621,6 +3621,26 @@ OpFoldResult cir::NotOp::fold(FoldAdaptor adaptor) { return {}; } +//===----------------------------------------------------------------------===// +// BaseClassAddrOp & DerivedClassAddrOp +//===----------------------------------------------------------------------===// + +static LogicalResult verifyClassAddrCast(Operation *op, cir::PointerType srcTy, + cir::PointerType resultTy) { + if (srcTy.getAddrSpace() != resultTy.getAddrSpace()) + return op->emitOpError() << "address space mismatch"; + + return mlir::success(); +} + +LogicalResult cir::BaseClassAddrOp::verify() { + return verifyClassAddrCast(getOperation(), getSrcAddr().getType(), getType()); +} + +LogicalResult cir::DerivedClassAddrOp::verify() { + return verifyClassAddrCast(getOperation(), getSrcAddr().getType(), getType()); +} + //===----------------------------------------------------------------------===// // BaseDataMemberOp & DerivedDataMemberOp //===----------------------------------------------------------------------===// diff --git a/clang/test/CIR/CodeGen/base-class-addrspace.cpp b/clang/test/CIR/CodeGen/base-class-addrspace.cpp new file mode 100644 index 0000000000000..1976c3232517a --- /dev/null +++ b/clang/test/CIR/CodeGen/base-class-addrspace.cpp @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// FIXME: Add LLVM and OGCG checks for the virtual base once cir.vtable.get_vptr +// keeps the address space. +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -DVBASE %s -o %t-vbase.cir +// RUN: FileCheck --input-file=%t-vbase.cir %s -check-prefix=CIR-VBASE + +// A base or derived class subobject is in the address space of the object. + +#define AS1 __attribute__((address_space(1))) + +struct A { int a; }; +struct B { int b; }; +struct D : A, B { int d; }; + +int base_member(AS1 D *d) { return d->a; } + +// CIR-LABEL: cir.func {{.*}}@_Z11base_memberPU3AS11D +// CIR: cir.base_class_addr nonnull %{{.*}} [0] : !cir.ptr<!rec_D, target_address_space(1)> -> !cir.ptr<!rec_A, target_address_space(1)> + +// LLVM-LABEL: define {{.*}}@_Z11base_memberPU3AS11D +// LLVM: %[[A:.*]] = getelementptr inbounds nuw %struct.A, ptr addrspace(1) %{{.*}}, i32 0, i32 0 +// LLVM: load i32, ptr addrspace(1) %[[A]] + +// OGCG-LABEL: define {{.*}}@_Z11base_memberPU3AS11D +// OGCG: %[[A:.*]] = getelementptr inbounds nuw %struct.A, ptr addrspace(1) %{{.*}}, i32 0, i32 0 +// OGCG: load i32, ptr addrspace(1) %[[A]] + +int nonzero_base_member(AS1 D *d) { return d->b; } + +// CIR-LABEL: cir.func {{.*}}@_Z19nonzero_base_memberPU3AS11D +// CIR: cir.base_class_addr nonnull %{{.*}} [4] : !cir.ptr<!rec_D, target_address_space(1)> -> !cir.ptr<!rec_B, target_address_space(1)> + +// LLVM-LABEL: define {{.*}}@_Z19nonzero_base_memberPU3AS11D +// LLVM: %[[BASE:.*]] = getelementptr i8, ptr addrspace(1) %{{.*}}, i32 4 +// LLVM: %[[B:.*]] = getelementptr inbounds nuw %struct.B, ptr addrspace(1) %[[BASE]], i32 0, i32 0 +// LLVM: load i32, ptr addrspace(1) %[[B]] + +// OGCG-LABEL: define {{.*}}@_Z19nonzero_base_memberPU3AS11D +// OGCG: %[[BASE:.*]] = getelementptr inbounds i8, ptr addrspace(1) %{{.*}}, i64 4 +// OGCG: %[[B:.*]] = getelementptr inbounds nuw %struct.B, ptr addrspace(1) %[[BASE]], i32 0, i32 0 +// OGCG: load i32, ptr addrspace(1) %[[B]] + +AS1 B *to_base(AS1 D *d) { return d; } + +// CIR-LABEL: cir.func {{.*}}@_Z7to_basePU3AS11D +// CIR: cir.base_class_addr %{{.*}} [4] : !cir.ptr<!rec_D, target_address_space(1)> -> !cir.ptr<!rec_B, target_address_space(1)> + +// LLVM-LABEL: define {{.*}}@_Z7to_basePU3AS11D +// LLVM: %[[ISNULL:.*]] = icmp eq ptr addrspace(1) %[[D:.*]], null +// LLVM: %[[BASE:.*]] = getelementptr i8, ptr addrspace(1) %[[D]], i32 4 +// LLVM: select i1 %[[ISNULL]], ptr addrspace(1) %[[D]], ptr addrspace(1) %[[BASE]] + +// OGCG-LABEL: define {{.*}}@_Z7to_basePU3AS11D +// OGCG: %[[BASE:.*]] = getelementptr inbounds i8, ptr addrspace(1) %{{.*}}, i64 4 +// OGCG: phi ptr addrspace(1) [ %[[BASE]], %{{.*}} ], [ null, %{{.*}} ] + +AS1 D *to_derived(AS1 B *b) { return static_cast<AS1 D *>(b); } + +// CIR-LABEL: cir.func {{.*}}@_Z10to_derivedPU3AS11B +// CIR: cir.derived_class_addr %{{.*}} [4] : !cir.ptr<!rec_B, target_address_space(1)> -> !cir.ptr<!rec_D, target_address_space(1)> + +// LLVM-LABEL: define {{.*}}@_Z10to_derivedPU3AS11B +// LLVM: %[[ISNULL:.*]] = icmp eq ptr addrspace(1) %[[B:.*]], null +// LLVM: %[[DERIVED:.*]] = getelementptr inbounds i8, ptr addrspace(1) %[[B]], i32 -4 +// LLVM: select i1 %[[ISNULL]], ptr addrspace(1) %[[B]], ptr addrspace(1) %[[DERIVED]] + +// OGCG-LABEL: define {{.*}}@_Z10to_derivedPU3AS11B +// OGCG: %[[DERIVED:.*]] = getelementptr inbounds i8, ptr addrspace(1) %{{.*}}, i64 -4 +// OGCG: phi ptr addrspace(1) [ %[[DERIVED]], %{{.*}} ], [ null, %{{.*}} ] + +#ifdef VBASE +struct V { int v; }; +struct W : virtual V { int w; }; + +AS1 V *to_virtual_base(AS1 W *w) { return w; } + +// CIR-VBASE-LABEL: cir.func {{.*}}@_Z15to_virtual_basePU3AS11W +// CIR-VBASE: cir.ternary +// CIR-VBASE: cir.const #cir.ptr<null> : !cir.ptr<!rec_V, target_address_space(1)> +// CIR-VBASE: }, false { +// CIR-VBASE: %[[BYTES:.*]] = cir.cast bitcast %{{.*}} : !cir.ptr<!rec_W, target_address_space(1)> -> !cir.ptr<!u8i, target_address_space(1)> +// CIR-VBASE: cir.ptr_stride %[[BYTES]], %{{.*}} : (!cir.ptr<!u8i, target_address_space(1)>, !s64i) -> !cir.ptr<!u8i, target_address_space(1)> +// CIR-VBASE: }) : (!cir.bool) -> !cir.ptr<!rec_V, target_address_space(1)> +#endif diff --git a/clang/test/CIR/IR/invalid-class-addr.cir b/clang/test/CIR/IR/invalid-class-addr.cir new file mode 100644 index 0000000000000..833694cc3284d --- /dev/null +++ b/clang/test/CIR/IR/invalid-class-addr.cir @@ -0,0 +1,27 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!s32i = !cir.int<s, 32> +!rec_B = !cir.struct<"B" {data !s32i}> +!rec_D = !cir.struct<"D" {data !rec_B}> + +module { + cir.func @base_class_addr_address_space_mismatch(%arg0: !cir.ptr<!rec_D, target_address_space(1)>) { + // expected-error @below {{address space mismatch}} + %0 = cir.base_class_addr %arg0 [0] : !cir.ptr<!rec_D, target_address_space(1)> -> !cir.ptr<!rec_B> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_B = !cir.struct<"B" {data !s32i}> +!rec_D = !cir.struct<"D" {data !rec_B}> + +module { + cir.func @derived_class_addr_address_space_mismatch(%arg0: !cir.ptr<!rec_B, target_address_space(1)>) { + // expected-error @below {{address space mismatch}} + %0 = cir.derived_class_addr %arg0 [0] : !cir.ptr<!rec_B, target_address_space(1)> -> !cir.ptr<!rec_D> + cir.return + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
