https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/143195
This change adds the support for accessing a member of a base class from a derived class object. >From 6fb28507d57ce04faa712b630e308ba029230fd5 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <akay...@nvidia.com> Date: Fri, 30 May 2025 16:07:19 -0700 Subject: [PATCH] [CIR] Add support for accessing members of base classes This change adds the support for accessing a member of a base class from a derived class object. --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 5 ++ clang/include/clang/CIR/Dialect/IR/CIROps.td | 44 ++++++++++++ clang/include/clang/CIR/MissingFeatures.h | 5 ++ clang/lib/CIR/CodeGen/Address.h | 14 ++++ clang/lib/CIR/CodeGen/CIRGenBuilder.cpp | 12 ++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 12 ++++ clang/lib/CIR/CodeGen/CIRGenClass.cpp | 69 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 34 +++++++-- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 22 ++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 7 ++ clang/lib/CIR/CodeGen/CIRGenModule.cpp | 29 ++++++++ clang/lib/CIR/CodeGen/CIRGenModule.h | 5 ++ clang/lib/CIR/CodeGen/CMakeLists.txt | 1 + .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 33 +++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++ clang/test/CIR/CodeGen/class.cpp | 49 +++++++++++++ 16 files changed, 346 insertions(+), 5 deletions(-) create mode 100644 clang/lib/CIR/CodeGen/CIRGenClass.cpp diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 7a5f192618a5d..a3754f4de66b0 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -278,6 +278,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return createCast(loc, cir::CastKind::bitcast, src, newTy); } + mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) { + assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src"); + return createBitcast(src, getPointerTo(newPointeeTy)); + } + //===--------------------------------------------------------------------===// // Binary Operators //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 00878f7dd8ed7..962b5be051610 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2231,4 +2231,48 @@ def VecTernaryOp : CIR_Op<"vec.ternary", let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// BaseClassAddrOp +//===----------------------------------------------------------------------===// + +def BaseClassAddrOp : CIR_Op<"base_class_addr"> { + let summary = "Get the base class address for a class/struct"; + let description = [{ + The `cir.base_class_addr` operaration gets the address of a particular + non-virtual base class given a derived class pointer. The offset in bytes + of the base class must be passed in, since it is easier for the front end + to calculate that than the MLIR passes. The operation contains a flag for + whether or not the operand may be nullptr. That depends on the context and + cannot be known by the operation, and that information affects how the + operation is lowered. + + Example: + ```c++ + struct Base { }; + struct Derived : Base { }; + Derived d; + Base& b = d; + ``` + will generate + ```mlir + %3 = cir.base_class_addr (%1 : !cir.ptr<!rec_Derived> nonnull) [0] -> !cir.ptr<!rec_Base> + ``` + }]; + + // The validity of the relationship of derived and base cannot yet be + // verified, currently not worth adding a verifier. + let arguments = (ins + Arg<CIR_PointerType, "derived class pointer", [MemRead]>:$derived_addr, + IndexAttr:$offset, UnitAttr:$assume_not_null); + + let results = (outs Res<CIR_PointerType, "">:$base_addr); + + let assemblyFormat = [{ + `(` + $derived_addr `:` qualified(type($derived_addr)) + (`nonnull` $assume_not_null^)? + `)` `[` $offset `]` `->` qualified(type($base_addr)) attr-dict + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index f1e0c15d41f64..b4e928f32f130 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -151,6 +151,11 @@ struct MissingFeatures { static bool cxxabiAppleARM64CXXABI() { return false; } static bool cxxabiStructorImplicitParam() { return false; } + // Address class + static bool addressOffset() { return false; } + static bool addressIsKnownNonNull() { return false; } + static bool addressPointerAuthInfo() { return false; } + // Misc static bool cirgenABIInfo() { return false; } static bool abiArgInfo() { return false; } diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h index 2cc8ada783197..6f76c3ebb1c5e 100644 --- a/clang/lib/CIR/CodeGen/Address.h +++ b/clang/lib/CIR/CodeGen/Address.h @@ -21,6 +21,9 @@ namespace clang::CIRGen { +// Forward declaration to avoid a circular dependency +class CIRGenBuilderTy; + class Address { // The boolean flag indicates whether the pointer is known to be non-null. @@ -65,11 +68,22 @@ class Address { return pointerAndKnownNonNull.getPointer() != nullptr; } + /// Return address with different element type, a bitcast pointer, and + /// the same alignment. + Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const; + mlir::Value getPointer() const { assert(isValid()); return pointerAndKnownNonNull.getPointer(); } + mlir::Value getBasePointer() const { + // TODO(cir): Remove the version above when we catchup with OG codegen on + // ptr auth. + assert(isValid() && "pointer isn't valid"); + return getPointer(); + } + mlir::Type getType() const { assert(mlir::cast<cir::PointerType>( pointerAndKnownNonNull.getPointer().getType()) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index 5620821a5375a..4c8c6ed289c3b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -38,3 +38,15 @@ mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin, const mlir::Type flatPtrTy = basePtr.getType(); return create<cir::PtrStrideOp>(arrayLocEnd, flatPtrTy, basePtr, idx); } + +// This can't be defined in Address.h because that file is included by +// CIRGenBuilder.h +Address Address::withElementType(CIRGenBuilderTy &builder, + mlir::Type elemTy) const { + assert(!cir::MissingFeatures::addressOffset()); + assert(!cir::MissingFeatures::addressIsKnownNonNull()); + assert(!cir::MissingFeatures::addressPointerAuthInfo()); + + return Address(builder.createPtrBitcast(getBasePointer(), elemTy), elemTy, + getAlignment()); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 5f33ae1af35ee..03077ee062a65 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -309,6 +309,18 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create<cir::BinOp>(loc, cir::BinOpKind::Div, lhs, rhs); } + Address createBaseClassAddr(mlir::Location loc, Address addr, + mlir::Type destType, unsigned offset, + bool assumeNotNull) { + if (destType == addr.getElementType()) + return addr; + + auto ptrTy = getPointerTo(destType); + auto baseAddr = create<cir::BaseClassAddrOp>( + loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull); + return Address(baseAddr, destType, addr.getAlignment()); + } + cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile = false) { mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment()); diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp new file mode 100644 index 0000000000000..7fe022abe504d --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of classes +// +//===----------------------------------------------------------------------===// + +#include "CIRGenFunction.h" + +#include "clang/AST/RecordLayout.h" +#include "clang/CIR/MissingFeatures.h" + +using namespace clang; +using namespace clang::CIRGen; + +Address +CIRGenFunction::getAddressOfBaseClass(Address value, + const CXXRecordDecl *derived, + CastExpr::path_const_iterator pathBegin, + CastExpr::path_const_iterator pathEnd, + bool nullCheckValue, SourceLocation loc) { + assert(pathBegin != pathEnd && "Base path should not be empty!"); + + CastExpr::path_const_iterator start = pathBegin; + + if ((*start)->isVirtual()) { + // The implementation here is actually complete, but let's flag this + // as an error until the rest of the virtual base class support is in place. + cgm.errorNYI(loc, "getAddrOfBaseClass: virtual base"); + return Address::invalid(); + } + + // Compute the static offset of the ultimate destination within its + // allocating subobject (the virtual base, if there is one, or else + // the "complete" object that we see). + CharUnits nonVirtualOffset = + cgm.computeNonVirtualBaseClassOffset(derived, start, pathEnd); + + // Get the base pointer type. + mlir::Type baseValueTy = convertType((pathEnd[-1])->getType()); + assert(!cir::MissingFeatures::addressSpace()); + + // The if statement here is redundant now, but it will be needed when we add + // support for virtual base classes. + // If there is no virtual base, use cir.base_class_addr. It takes care of + // the adjustment and the null pointer check. + if (nonVirtualOffset.isZero()) { + assert(!cir::MissingFeatures::sanitizers()); + return builder.createBaseClassAddr(getLoc(loc), value, baseValueTy, 0, + /*assumeNotNull=*/true); + } + + assert(!cir::MissingFeatures::sanitizers()); + + // Apply the offset + value = builder.createBaseClassAddr(getLoc(loc), value, baseValueTy, + nonVirtualOffset.getQuantity(), + /*assumeNotNull=*/true); + + // Cast to the destination type. + value = value.withElementType(builder, baseValueTy); + + return value; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 1175fdc0be2cf..8e72d8000428d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -97,9 +97,14 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr, case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - cgm.errorNYI(expr->getSourceRange(), - "emitPointerWithAlignment: derived-to-base cast"); - return Address::invalid(); + assert(!cir::MissingFeatures::opTBAA()); + assert(!cir::MissingFeatures::addressIsKnownNonNull()); + Address addr = emitPointerWithAlignment(ce->getSubExpr(), baseInfo); + const CXXRecordDecl *derived = + ce->getSubExpr()->getType()->getPointeeCXXRecordDecl(); + return getAddressOfBaseClass( + addr, derived, ce->path_begin(), ce->path_end(), + shouldNullCheckClassCastValue(ce), ce->getExprLoc()); } case CK_AnyPointerToBlockPointerCast: @@ -823,8 +828,6 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_NonAtomicToAtomic: case CK_AtomicToNonAtomic: case CK_Dynamic: - case CK_UncheckedDerivedToBase: - case CK_DerivedToBase: case CK_ToUnion: case CK_BaseToDerived: case CK_LValueBitCast: @@ -863,6 +866,27 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { return lv; } + case CK_UncheckedDerivedToBase: + case CK_DerivedToBase: { + const auto *derivedClassTy = + e->getSubExpr()->getType()->castAs<clang::RecordType>(); + auto *derivedClassDecl = cast<CXXRecordDecl>(derivedClassTy->getDecl()); + + LValue lv = emitLValue(e->getSubExpr()); + Address thisAddr = lv.getAddress(); + + // Perform the derived-to-base conversion + Address baseAddr = getAddressOfBaseClass( + thisAddr, derivedClassDecl, e->path_begin(), e->path_end(), + /*NullCheckValue=*/false, e->getExprLoc()); + + // TODO: Support accesses to members of base classes in TBAA. For now, we + // conservatively pretend that the complete object is of the base class + // type. + assert(!cir::MissingFeatures::opTBAA()); + return makeAddrLValue(baseAddr, e->getType(), lv.getBaseInfo()); + } + case CK_ZeroToOCLOpaqueType: llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index b008ee9b472a1..e32a5c836be02 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -16,6 +16,7 @@ #include "CIRGenCall.h" #include "CIRGenValue.h" #include "mlir/IR/Location.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/GlobalDecl.h" #include "clang/CIR/MissingFeatures.h" @@ -629,4 +630,25 @@ void CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr, builder.createStore(loc, zeroValue, destPtr); } +// TODO(cir): should be shared with LLVM codegen. +bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) { + const Expr *e = ce->getSubExpr(); + + if (ce->getCastKind() == CK_UncheckedDerivedToBase) + return false; + + if (isa<CXXThisExpr>(e->IgnoreParens())) { + // We always assume that 'this' is never null. + return false; + } + + if (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(ce)) { + // And that glvalue casts are never null. + if (ice->isGLValue()) + return false; + } + + return true; +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index ee014adc961be..78732da52d459 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -430,6 +430,8 @@ class CIRGenFunction : public CIRGenTypeCache { // TODO: Add symbol table support } + bool shouldNullCheckClassCastValue(const CastExpr *ce); + LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t); /// Construct an address with the natural alignment of T. If a pointer to T @@ -445,6 +447,11 @@ class CIRGenFunction : public CIRGenTypeCache { return Address(ptr, convertTypeForMem(t), alignment); } + Address getAddressOfBaseClass(Address value, const CXXRecordDecl *derived, + CastExpr::path_const_iterator pathBegin, + CastExpr::path_const_iterator pathEnd, + bool nullCheckValue, SourceLocation loc); + LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source = AlignmentSource::Type) { return makeAddrLValue(addr, ty, LValueBaseInfo(source)); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index ce3c57e5f20a8..e0f65bba69f08 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclOpenACC.h" #include "clang/AST/GlobalDecl.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Interfaces/CIROpInterfaces.h" @@ -1677,6 +1678,34 @@ bool CIRGenModule::verifyModule() const { return mlir::verify(theModule).succeeded(); } +// TODO(cir): this can be shared with LLVM codegen. +CharUnits CIRGenModule::computeNonVirtualBaseClassOffset( + const CXXRecordDecl *derivedClass, CastExpr::path_const_iterator start, + CastExpr::path_const_iterator end) { + CharUnits offset = CharUnits::Zero(); + + const ASTContext &astContext = getASTContext(); + const CXXRecordDecl *rd = derivedClass; + + for (CastExpr::path_const_iterator i = start; i != end; ++i) { + const CXXBaseSpecifier *base = *i; + assert(!base->isVirtual() && "Should not see virtual bases here!"); + + // Get the layout. + const ASTRecordLayout &layout = astContext.getASTRecordLayout(rd); + + const auto *baseDecl = cast<CXXRecordDecl>( + base->getType()->castAs<clang::RecordType>()->getDecl()); + + // Add the offset. + offset += layout.getBaseClassOffset(baseDecl); + + rd = baseDecl; + } + + return offset; +} + DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, llvm::StringRef feature) { unsigned diagID = diags.getCustomDiagID( diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 7055170ac7ac3..5b112a0685509 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -141,6 +141,11 @@ class CIRGenModule : public CIRGenTypeCache { getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty = {}, ForDefinition_t isForDefinition = NotForDefinition); + CharUnits + computeNonVirtualBaseClassOffset(const CXXRecordDecl *derivedClass, + CastExpr::path_const_iterator start, + CastExpr::path_const_iterator end); + /// Return a constant array for the given string. mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e); diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 185a0e10547af..8bfcd2773d07a 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangCIR CIRGenerator.cpp CIRGenBuilder.cpp CIRGenCall.cpp + CIRGenClass.cpp CIRGenCXXABI.cpp CIRGenCXXExpr.cpp CIRGenDecl.cpp diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 8059836db6b71..210afba86444a 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -673,6 +673,38 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite( + cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + const mlir::Type resultType = + getTypeConverter()->convertType(baseClassOp.getType()); + mlir::Value derivedAddr = adaptor.getDerivedAddr(); + llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = { + adaptor.getOffset().getZExtValue()}; + mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8, + mlir::IntegerType::Signless); + if (adaptor.getOffset().getZExtValue() == 0) { + rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>( + baseClassOp, resultType, adaptor.getDerivedAddr()); + return mlir::success(); + } + + if (baseClassOp.getAssumeNotNull()) { + rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>( + baseClassOp, resultType, byteType, derivedAddr, offset); + } else { + auto loc = baseClassOp.getLoc(); + mlir::Value isNull = rewriter.create<mlir::LLVM::ICmpOp>( + loc, mlir::LLVM::ICmpPredicate::eq, derivedAddr, + rewriter.create<mlir::LLVM::ZeroOp>(loc, derivedAddr.getType())); + mlir::Value adjusted = rewriter.create<mlir::LLVM::GEPOp>( + loc, resultType, byteType, derivedAddr, offset); + rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(baseClassOp, isNull, + derivedAddr, adjusted); + } + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite( cir::AllocaOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -1752,6 +1784,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { dl); patterns.add< // clang-format off + CIRToLLVMBaseClassAddrOpLowering, CIRToLLVMBinOpLowering, CIRToLLVMBrCondOpLowering, CIRToLLVMBrOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index d1efa4e181a07..fef7e240940e3 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -297,6 +297,16 @@ class CIRToLLVMPtrStrideOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMBaseClassAddrOpLowering + : public mlir::OpConversionPattern<cir::BaseClassAddrOp> { +public: + using mlir::OpConversionPattern<cir::BaseClassAddrOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::BaseClassAddrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMStackSaveOpLowering : public mlir::OpConversionPattern<cir::StackSaveOp> { public: diff --git a/clang/test/CIR/CodeGen/class.cpp b/clang/test/CIR/CodeGen/class.cpp index 7c41bdb7112e9..6f5c1b7769c70 100644 --- a/clang/test/CIR/CodeGen/class.cpp +++ b/clang/test/CIR/CodeGen/class.cpp @@ -51,3 +51,52 @@ class Derived : public Base { int use(Derived *d) { return d->b; } +// CIR: cir.func @_Z3useP7Derived(%[[ARG0:.*]]: !cir.ptr<!rec_Derived> +// CIR: %[[D_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["d", init] +// CIR: cir.store %[[ARG0]], %[[D_ADDR]] +// CIR: %[[D_PTR:.*]] = cir.load align(8) %0 +// CIR: %[[D_B_ADDR:.*]] = cir.get_member %[[D_PTR]][1] {name = "b"} +// CIR: %[[D_B:.*]] = cir.load align(4) %[[D_B_ADDR]] + +// LLVM: define{{.*}} i32 @_Z3useP7Derived +// LLVM: getelementptr %class.Derived, ptr %{{.*}}, i32 0, i32 1 + +// OGCG: define{{.*}} i32 @_Z3useP7Derived +// OGCG: getelementptr inbounds nuw %class.Derived, ptr %{{.*}}, i32 0, i32 1 + +int use_base() { + Derived d; + return d.a; +} + +// CIR: cir.func @_Z8use_basev +// CIR: %[[D_ADDR:.*]] = cir.alloca !rec_Derived, !cir.ptr<!rec_Derived>, ["d"] +// CIR: %[[BASE_ADDR:.*]] cir.base_class_addr(%[[D_ADDR]] : !cir.ptr<!rec_Derived> nonnull) [0] -> !cir.ptr<!rec_Base> +// CIR: %[[D_A_ADDR:.*]] = cir.get_member %2[0] {name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i> +// CIR: %[[D_A:.*]] = cir.load align(4) %3 : !cir.ptr<!s32i>, !s32i + +// LLVM: define{{.*}} i32 @_Z8use_basev +// LLVM: %[[D:.*]] = alloca %class.Derived +// LLVM: %[[D_A_ADDR:.*]] = getelementptr %class.Base, ptr %[[D]], i32 0, i32 0 + +// OGCG: define{{.*}} i32 @_Z8use_basev +// OGCG: %[[D:.*]] = alloca %class.Derived +// OGCG: %[[D_A_ADDR:.*]] = getelementptr inbounds nuw %class.Base, ptr %[[D]], i32 0, i32 0 + +int use_base_via_pointer(Derived *d) { + return d->a; +} + +// CIR: cir.func @_Z20use_base_via_pointerP7Derived(%[[ARG0:.*]]: !cir.ptr<!rec_Derived> +// CIR: %[[D_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["d", init] +// CIR: cir.store %[[ARG0]], %[[D_ADDR]] +// CIR: %[[D:.*]] = cir.load align(8) %[[D_ADDR]] +// CIR: %[[BASE_ADDR:.*]] = cir.base_class_addr(%[[D]] : !cir.ptr<!rec_Derived> nonnull) [0] -> !cir.ptr<!rec_Base> +// CIR: %[[D_A_ADDR:.*]] = cir.get_member %[[BASE_ADDR]][0] {name = "a"} +// CIR: %[[D_A:.*]] = cir.load align(4) %[[D_A_ADDR]] + +// LLVM: define{{.*}} i32 @_Z20use_base_via_pointerP7Derived +// LLVM: %[[D_A_ADDR:.*]] = getelementptr %class.Base, ptr %{{.*}}, i32 0, i32 0 + +// OGCG: define{{.*}} i32 @_Z20use_base_via_pointerP7Derived +// OGCG: %[[D_A_ADDR:.*]] = getelementptr inbounds nuw %class.Base, ptr %{{.*}}, i32 0, i32 0 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits