From 7559708d50ee63177245ea7100e5962b9f2de36a Mon Sep 17 00:00:00 2001 From: Nathan Lanza Date: Sun, 23 Nov 2025 17:01:01 -0800 Subject: [PATCH] Update [ghstack-poisoned] --- clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp | 27 +++++++++ clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 10 ++++ clang/lib/CIR/CodeGen/CIRGenExprConst.cpp | 5 +- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 55 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenModule.cpp | 16 ++++++ clang/lib/CIR/CodeGen/CIRGenModule.h | 7 +++ .../test/CIR/CodeGen/member-pointer-cast.cpp | 34 ++++++++++++ clang/test/CIR/crashes/constexpr-cast.cpp | 7 +-- 8 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 clang/test/CIR/CodeGen/member-pointer-cast.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp index 9d8b43587a19..0ec5c2382906 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp @@ -90,6 +90,33 @@ mlir::TypedAttr CIRGenCXXABI::emitNullMemberPointer(clang::QualType T) { llvm_unreachable("NYI"); } +/// Returns the adjustment, in bytes, required for the given +/// member-pointer operation. Returns null if no adjustment is +/// required. +mlir::Attribute +CIRGenCXXABI::getMemberPointerAdjustment(const CastExpr *castExpr) { + assert(castExpr->getCastKind() == CK_DerivedToBaseMemberPointer || + castExpr->getCastKind() == CK_BaseToDerivedMemberPointer); + + QualType derivedType; + if (castExpr->getCastKind() == CK_DerivedToBaseMemberPointer) + derivedType = castExpr->getSubExpr()->getType(); + else + derivedType = castExpr->getType(); + + const CXXRecordDecl *derivedClass = + derivedType->castAs()->getMostRecentCXXRecordDecl(); + + return CGM.getNonVirtualBaseClassOffsetAsAttr( + derivedClass, castExpr->path_begin(), castExpr->path_end()); +} + +mlir::Attribute +CIRGenCXXABI::emitMemberPointerConversion(const CastExpr *castExpr, + mlir::Attribute src) { + llvm_unreachable("NYI"); +} + CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *E) { if (!requiresArrayCookie(E)) return CharUnits::Zero(); diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 81f5eb73daf9..78f2aa45a1de 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -330,6 +330,16 @@ class CIRGenCXXABI { /// Create a null member pointer of the given type. virtual mlir::TypedAttr emitNullMemberPointer(clang::QualType T); + /// Returns the adjustment, in bytes, required for the given + /// member-pointer operation. Returns null if no adjustment is + /// required. Does not handle virtual conversions. + mlir::Attribute getMemberPointerAdjustment(const CastExpr *castExpr); + + /// Perform a derived-to-base, base-to-derived, or bitcast member pointer + /// conversion on a constant value. + virtual mlir::Attribute emitMemberPointerConversion(const CastExpr *castExpr, + mlir::Attribute src); + /// Gets the offsets of all the virtual base pointers in a given class. virtual std::vector getVBPtrOffsets(const CXXRecordDecl *RD); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index c481d6c9b37e..ec61b62a23c3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -1003,7 +1003,10 @@ class ConstExprEmitter case CK_ReinterpretMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_BaseToDerivedMemberPointer: { - llvm_unreachable("not implemented"); + auto src = Emitter.tryEmitPrivate(subExpr, subExpr->getType()); + if (!src) + return nullptr; + return CGM.getCXXABI().emitMemberPointerConversion(E, src); } // These will never be supported. diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 83126f124734..016c397cb0f1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -124,6 +124,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { bool classifyReturnType(CIRGenFunctionInfo &FI) const override; bool isZeroInitializable(const MemberPointerType *MPT) override; mlir::TypedAttr emitNullMemberPointer(clang::QualType T) override; + mlir::Attribute emitMemberPointerConversion(const CastExpr *castExpr, + mlir::Attribute src) override; AddedStructorArgCounts buildStructorSignature(GlobalDecl GD, @@ -3186,6 +3188,59 @@ mlir::TypedAttr CIRGenItaniumCXXABI::emitNullMemberPointer(clang::QualType T) { llvm_unreachable("NYI"); } +mlir::Attribute +CIRGenItaniumCXXABI::emitMemberPointerConversion(const CastExpr *castExpr, + mlir::Attribute src) { + assert(castExpr->getCastKind() == CK_DerivedToBaseMemberPointer || + castExpr->getCastKind() == CK_BaseToDerivedMemberPointer || + castExpr->getCastKind() == CK_ReinterpretMemberPointer); + + // Under Itanium, reinterprets don't require any additional processing. + if (castExpr->getCastKind() == CK_ReinterpretMemberPointer) + return src; + + // If the adjustment is trivial, we don't need to do anything. + mlir::Attribute adj = getMemberPointerAdjustment(castExpr); + if (!adj) + return src; + + bool isDerivedToBase = + (castExpr->getCastKind() == CK_DerivedToBaseMemberPointer); + + const MemberPointerType *destTy = + castExpr->getType()->castAs(); + + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (destTy->isMemberDataPointer()) { + auto dataMemberAttr = cast(src); + auto adjIntAttr = cast(adj); + + // null maps to null. + if (dataMemberAttr.isNullPtr()) + return src; + + // Get the current member index. + auto memberIndex = dataMemberAttr.getMemberIndex().value(); + + // Apply the adjustment. + int64_t newIndex; + if (isDerivedToBase) + newIndex = memberIndex - adjIntAttr.getSInt(); + else + newIndex = memberIndex + adjIntAttr.getSInt(); + + // Create a new data member attribute with the adjusted index. + auto resultType = + cast(CGM.convertType(castExpr->getType())); + return cir::DataMemberAttr::get(resultType, newIndex); + } + + // For member function pointers, the adjustment is more complex. + // They are represented as a struct with {ptr, adj}. + llvm_unreachable("Member function pointer conversions NYI"); +} + /// The Itanium ABI always places an offset to the complete object /// at entry -2 in the vtable. void CIRGenItaniumCXXABI::emitVirtualObjectDelete( diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index c148a3f503c7..955a37dc73b9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -4277,6 +4277,22 @@ CharUnits CIRGenModule::computeNonVirtualBaseClassOffset( return offset; } +mlir::Attribute CIRGenModule::getNonVirtualBaseClassOffsetAsAttr( + const CXXRecordDecl *classDecl, CastExpr::path_const_iterator pathBegin, + CastExpr::path_const_iterator pathEnd) { + assert(pathBegin != pathEnd && "Base path should not be empty!"); + + CharUnits offset = + computeNonVirtualBaseClassOffset(classDecl, pathBegin, pathEnd); + if (offset.isZero()) + return nullptr; + + mlir::Type ptrDiffTy = + getTypes().convertType(getASTContext().getPointerDiffType()); + + return cir::IntAttr::get(ptrDiffTy, offset.getQuantity()); +} + void CIRGenModule::Error(SourceLocation loc, StringRef message) { unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "%0"); getDiags().Report(astContext.getFullLoc(loc), diagID) << message; diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 844fff10abf3..2c27289f4631 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -405,6 +405,13 @@ class CIRGenModule : public CIRGenTypeCache { CastExpr::path_const_iterator pathBegin, CastExpr::path_const_iterator pathEnd); + /// Returns the offset from a derived class to a class as a constant + /// attribute. Returns null if the offset is 0. + mlir::Attribute + getNonVirtualBaseClassOffsetAsAttr(const CXXRecordDecl *classDecl, + CastExpr::path_const_iterator pathBegin, + CastExpr::path_const_iterator pathEnd); + /// Get the CIR attributes and calling convention to use for a particular /// function type. /// diff --git a/clang/test/CIR/CodeGen/member-pointer-cast.cpp b/clang/test/CIR/CodeGen/member-pointer-cast.cpp new file mode 100644 index 000000000000..b314bc5e15b2 --- /dev/null +++ b/clang/test/CIR/CodeGen/member-pointer-cast.cpp @@ -0,0 +1,34 @@ +// 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.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ogcg.ll +// RUN: FileCheck --input-file=%t.ogcg.ll %s -check-prefix=LLVM + +// Test base-to-derived member data pointer conversion + +class Base { +public: + int baseField1; + int baseField2; +}; + +class Derived : public Base { +public: + int derivedField; +}; + +// Test 1: Base-to-derived conversion with zero offset (baseField1 at field index 0) +// CIR: cir.global external @ptrZeroOffset = #cir.data_member<0> +// LLVM: @ptrZeroOffset = global i64 0 +int Derived::*ptrZeroOffset = static_cast(&Base::baseField1); + +// Test 2: Base-to-derived conversion with non-zero offset (baseField2 at field index 1) +// CIR: cir.global external @ptrNonZeroOffset = #cir.data_member<1> +// LLVM: @ptrNonZeroOffset = global i64 4 +int Derived::*ptrNonZeroOffset = static_cast(&Base::baseField2); + +// Test 3: Reinterpret cast (should preserve original value) +// CIR: cir.global external @ptrReinterpret = #cir.data_member<0> +// LLVM: @ptrReinterpret = global i64 0 +int Derived::*ptrReinterpret = reinterpret_cast(&Base::baseField1); diff --git a/clang/test/CIR/crashes/constexpr-cast.cpp b/clang/test/CIR/crashes/constexpr-cast.cpp index 879d282f340c..980ca3d0e474 100644 --- a/clang/test/CIR/crashes/constexpr-cast.cpp +++ b/clang/test/CIR/crashes/constexpr-cast.cpp @@ -1,11 +1,8 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // XFAIL: * // -// Constant expression NYI -// Location: CIRGenExprConst.cpp:1006 -// -// Original failure: exprconst_1006 from LLVM build -// Reduced from /tmp/HexagonAttributeParser-40f1ed.cpp +// Member function pointer emission NYI +// Location: CIRGenExprConst.cpp:2045 class a { public: