aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen
diff options
context:
space:
mode:
authorAndy Kaylor <akaylor@nvidia.com>2025-06-09 13:11:12 -0700
committerGitHub <noreply@github.com>2025-06-09 13:11:12 -0700
commit6559831025711a21fd1f6a4065c4f3ac53f16875 (patch)
tree1af415800dcb75c9d9fd9f1d9f31f2abef8da623 /clang/lib/CIR/CodeGen
parentf12e4f2faf404a7f44b5505b0a4c14e3a003d2d1 (diff)
downloadllvm-6559831025711a21fd1f6a4065c4f3ac53f16875.zip
llvm-6559831025711a21fd1f6a4065c4f3ac53f16875.tar.gz
llvm-6559831025711a21fd1f6a4065c4f3ac53f16875.tar.bz2
[CIR] Add support for accessing members of base classes (#143195)
This change adds the support for accessing a member of a base class from a derived class object.
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r--clang/lib/CIR/CodeGen/Address.h14
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenBuilder.cpp12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenBuilder.h12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenClass.cpp65
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExpr.cpp34
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.cpp22
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h7
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp28
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.h4
-rw-r--r--clang/lib/CIR/CodeGen/CMakeLists.txt1
10 files changed, 194 insertions, 5 deletions
diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h
index 2cc8ada..6f76c3e 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 @@ public:
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 5620821..4c8c6ed 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 5f33ae1..03077ee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -309,6 +309,18 @@ public:
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 0000000..4cdaa480
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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,
+ llvm::iterator_range<CastExpr::path_const_iterator> path,
+ bool nullCheckValue, SourceLocation loc) {
+ assert(!path.empty() && "Base path should not be empty!");
+
+ if ((*path.begin())->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, path);
+
+ // Get the base pointer type.
+ mlir::Type baseValueTy = convertType((path.end()[-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 305e88b..8129fe0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -98,9 +98,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(),
+ shouldNullCheckClassCastValue(ce),
+ ce->getExprLoc());
}
case CK_AnyPointerToBlockPointerCast:
@@ -824,8 +829,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:
@@ -864,6 +867,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(),
+ /*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 b008ee9..e32a5c8 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 e5264ba..d6002c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -465,6 +465,8 @@ public:
// 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
@@ -480,6 +482,11 @@ public:
return Address(ptr, convertTypeForMem(t), alignment);
}
+ Address getAddressOfBaseClass(
+ Address value, const CXXRecordDecl *derived,
+ llvm::iterator_range<CastExpr::path_const_iterator> path,
+ 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 e5eae31..3d46c44 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"
@@ -1683,6 +1684,33 @@ bool CIRGenModule::verifyModule() const {
return mlir::verify(theModule).succeeded();
}
+// TODO(cir): this can be shared with LLVM codegen.
+CharUnits CIRGenModule::computeNonVirtualBaseClassOffset(
+ const CXXRecordDecl *derivedClass,
+ llvm::iterator_range<CastExpr::path_const_iterator> path) {
+ CharUnits offset = CharUnits::Zero();
+
+ const ASTContext &astContext = getASTContext();
+ const CXXRecordDecl *rd = derivedClass;
+
+ for (const CXXBaseSpecifier *base : path) {
+ 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 ac25d52..24ec9ca 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -141,6 +141,10 @@ public:
getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty = {},
ForDefinition_t isForDefinition = NotForDefinition);
+ CharUnits computeNonVirtualBaseClassOffset(
+ const CXXRecordDecl *derivedClass,
+ llvm::iterator_range<CastExpr::path_const_iterator> path);
+
/// 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 185a0e1..8bfcd27 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