Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<MemberPointerType>()->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();
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<CharUnits> getVBPtrOffsets(const CXXRecordDecl *RD);

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
55 changes: 55 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<MemberPointerType>();

// 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<cir::DataMemberAttr>(src);
auto adjIntAttr = cast<cir::IntAttr>(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<cir::DataMemberType>(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(
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
34 changes: 34 additions & 0 deletions clang/test/CIR/CodeGen/member-pointer-cast.cpp
Original file line number Diff line number Diff line change
@@ -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<int Derived::*>(&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<int Derived::*>(&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<int Derived::*>(&Base::baseField1);
7 changes: 2 additions & 5 deletions clang/test/CIR/crashes/constexpr-cast.cpp
Original file line number Diff line number Diff line change
@@ -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:
Expand Down