[clang] [CIR][NFC] Move ABI lowering of dynamic_cast to CXXABILowering (PR #176931)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 22 04:46:19 PST 2026
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/176931
>From ffa14b544ec0a345a3559541038099e6f82bd006 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Tue, 20 Jan 2026 22:20:23 +0800
Subject: [PATCH] [CIR][NFC] Move ABI lowering of dynamic_cast to
CXXABILowering
This patch moves the ABI lowering for dynamic_cast from LoweringPrepare to the
new CXXABILowering pass. This effectively removes ABI lowering code away from
LoweringPrepare, thus the patch also removes the LoweringPrepareCXXABI classes
and files.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 1 +
.../lib/CIR/Dialect/Transforms/CMakeLists.txt | 1 -
.../CIR/Dialect/Transforms/CXXABILowering.cpp | 10 ++
.../Dialect/Transforms/LoweringPrepare.cpp | 37 +---
.../Transforms/LoweringPrepareCXXABI.h | 38 ----
.../LoweringPrepareItaniumCXXABI.cpp | 170 ------------------
.../Transforms/TargetLowering/CIRCXXABI.h | 3 +
.../TargetLowering/LowerItaniumCXXABI.cpp | 167 +++++++++++++++++
clang/test/CIR/CodeGen/dynamic-cast.cpp | 6 +-
9 files changed, 185 insertions(+), 248 deletions(-)
delete mode 100644 clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
delete mode 100644 clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 89a879cefe857..fe35ab305f4ba 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -341,6 +341,7 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> {
}];
let hasLLVMLowering = false;
+ let hasCXXABILowering = true;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index 2a0d791edd22c..34d95a92c3bfe 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -7,7 +7,6 @@ add_clang_library(MLIRCIRTransforms
FlattenCFG.cpp
HoistAllocas.cpp
LoweringPrepare.cpp
- LoweringPrepareItaniumCXXABI.cpp
GotoSolver.cpp
DEPENDS
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 57a7cdc4f27a0..c8e06fed50cf9 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -294,6 +294,15 @@ mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRDynamicCastOpABILowering::matchAndRewrite(
+ cir::DynamicCastOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Value loweredResult =
+ lowerModule->getCXXABI().lowerDynamicCast(op, rewriter);
+ rewriter.replaceOp(op, loweredResult);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRGetMethodOpABILowering::matchAndRewrite(
cir::GetMethodOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -384,6 +393,7 @@ populateCXXABIConversionTarget(mlir::ConversionTarget &target,
[&typeConverter](cir::GlobalOp op) {
return typeConverter.isLegal(op.getSymType());
});
+ target.addIllegalOp<cir::DynamicCastOp>();
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 7551267eafb4a..b7cc8775d298f 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-#include "LoweringPrepareCXXABI.h"
#include "PassDetail.h"
#include "mlir/IR/Attributes.h"
#include "clang/AST/ASTContext.h"
@@ -71,7 +70,6 @@ struct LoweringPreparePass
void lowerComplexMulOp(cir::ComplexMulOp op);
void lowerUnaryOp(cir::UnaryOp op);
void lowerGlobalOp(cir::GlobalOp op);
- void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
void lowerTrivialCopyCall(cir::CallOp op);
@@ -107,9 +105,6 @@ struct LoweringPreparePass
clang::ASTContext *astCtx;
- // Helper for lowering C++ ABI specific operations.
- std::shared_ptr<cir::LoweringPrepareCXXABI> cxxABI;
-
/// Tracks current module.
mlir::ModuleOp mlirModule;
@@ -122,24 +117,7 @@ struct LoweringPreparePass
/// List of dtors and their priorities to be called when unloading module.
llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalDtorList;
- void setASTContext(clang::ASTContext *c) {
- astCtx = c;
- switch (c->getCXXABIKind()) {
- case clang::TargetCXXABI::GenericItanium:
- // We'll need X86-specific support for handling vaargs lowering, but for
- // now the Itanium ABI will work.
- assert(!cir::MissingFeatures::loweringPrepareX86CXXABI());
- cxxABI.reset(cir::LoweringPrepareCXXABI::createItaniumABI());
- break;
- case clang::TargetCXXABI::GenericAArch64:
- case clang::TargetCXXABI::AppleARM64:
- assert(!cir::MissingFeatures::loweringPrepareAArch64XXABI());
- cxxABI.reset(cir::LoweringPrepareCXXABI::createItaniumABI());
- break;
- default:
- llvm_unreachable("NYI");
- }
- }
+ void setASTContext(clang::ASTContext *c) { astCtx = c; }
};
} // namespace
@@ -985,17 +963,6 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
cir::ReturnOp::create(builder, f.getLoc());
}
-void LoweringPreparePass::lowerDynamicCastOp(DynamicCastOp op) {
- CIRBaseBuilderTy builder(getContext());
- builder.setInsertionPointAfter(op);
-
- assert(astCtx && "AST context is not available during lowering prepare");
- auto loweredValue = cxxABI->lowerDynamicCast(builder, *astCtx, op);
-
- op.replaceAllUsesWith(loweredValue);
- op.erase();
-}
-
static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
clang::ASTContext *astCtx,
mlir::Operation *op, mlir::Type eltTy,
@@ -1118,8 +1085,6 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerComplexMulOp(complexMul);
} else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
lowerGlobalOp(glob);
- } else if (auto dynamicCast = mlir::dyn_cast<cir::DynamicCastOp>(op)) {
- lowerDynamicCastOp(dynamicCast);
} else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
lowerUnaryOp(unary);
} else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
deleted file mode 100644
index 2582c332d52a6..0000000000000
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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 file provides the LoweringPrepareCXXABI class, which is the base class
-// for ABI specific functionalities that are required during LLVM lowering
-// prepare.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H
-#define CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H
-
-#include "mlir/IR/Value.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
-#include "clang/CIR/Dialect/IR/CIRDialect.h"
-
-namespace cir {
-
-class LoweringPrepareCXXABI {
-public:
- static LoweringPrepareCXXABI *createItaniumABI();
-
- virtual ~LoweringPrepareCXXABI() {}
-
- virtual mlir::Value lowerDynamicCast(CIRBaseBuilderTy &builder,
- clang::ASTContext &astCtx,
- cir::DynamicCastOp op) = 0;
-};
-
-} // namespace cir
-
-#endif // CIR_DIALECT_TRANSFORMS__LOWERINGPREPARECXXABI_H
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp
deleted file mode 100644
index f3c6692ce1130..0000000000000
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-//===--------------------------------------------------------------------===//
-//
-// 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 file provides Itanium C++ ABI specific code
-// that is used during LLVMIR lowering prepare.
-//
-//===--------------------------------------------------------------------===//
-
-#include "LoweringPrepareCXXABI.h"
-#include "mlir/IR/BuiltinAttributes.h"
-#include "mlir/IR/Value.h"
-#include "mlir/IR/ValueRange.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
-#include "clang/CIR/Dialect/IR/CIRAttrs.h"
-#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
-#include "clang/CIR/Dialect/IR/CIRDialect.h"
-#include "clang/CIR/MissingFeatures.h"
-
-class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI {
-public:
- mlir::Value lowerDynamicCast(cir::CIRBaseBuilderTy &builder,
- clang::ASTContext &astCtx,
- cir::DynamicCastOp op) override;
-};
-
-cir::LoweringPrepareCXXABI *cir::LoweringPrepareCXXABI::createItaniumABI() {
- return new LoweringPrepareItaniumCXXABI();
-}
-
-static void buildBadCastCall(cir::CIRBaseBuilderTy &builder, mlir::Location loc,
- mlir::FlatSymbolRefAttr badCastFuncRef) {
- builder.createCallOp(loc, badCastFuncRef, cir::VoidType(),
- mlir::ValueRange{});
- // TODO(cir): Set the 'noreturn' attribute on the function.
- assert(!cir::MissingFeatures::opFuncNoReturn());
- cir::UnreachableOp::create(builder, loc);
- builder.clearInsertionPoint();
-}
-
-static mlir::Value
-buildDynamicCastAfterNullCheck(cir::CIRBaseBuilderTy &builder,
- cir::DynamicCastOp op) {
- mlir::Location loc = op->getLoc();
- mlir::Value srcValue = op.getSrc();
- cir::DynamicCastInfoAttr castInfo = op.getInfo().value();
-
- // TODO(cir): consider address space
- assert(!cir::MissingFeatures::addressSpace());
-
- mlir::Value srcPtr = builder.createBitcast(srcValue, builder.getVoidPtrTy());
- cir::ConstantOp srcRtti = builder.getConstant(loc, castInfo.getSrcRtti());
- cir::ConstantOp destRtti = builder.getConstant(loc, castInfo.getDestRtti());
- cir::ConstantOp offsetHint =
- builder.getConstant(loc, castInfo.getOffsetHint());
-
- mlir::FlatSymbolRefAttr dynCastFuncRef = castInfo.getRuntimeFunc();
- mlir::Value dynCastFuncArgs[4] = {srcPtr, srcRtti, destRtti, offsetHint};
-
- mlir::Value castedPtr =
- builder
- .createCallOp(loc, dynCastFuncRef, builder.getVoidPtrTy(),
- dynCastFuncArgs)
- .getResult();
-
- assert(mlir::isa<cir::PointerType>(castedPtr.getType()) &&
- "the return value of __dynamic_cast should be a ptr");
-
- /// C++ [expr.dynamic.cast]p9:
- /// A failed cast to reference type throws std::bad_cast
- if (op.isRefCast()) {
- // Emit a cir.if that checks the casted value.
- mlir::Value castedValueIsNull = builder.createPtrIsNull(castedPtr);
- cir::IfOp::create(builder, loc, castedValueIsNull, false,
- [&](mlir::OpBuilder &, mlir::Location) {
- buildBadCastCall(builder, loc,
- castInfo.getBadCastFunc());
- });
- }
-
- // Note that castedPtr is a void*. Cast it to a pointer to the destination
- // type before return.
- return builder.createBitcast(castedPtr, op.getType());
-}
-
-static mlir::Value
-buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder,
- clang::ASTContext &astCtx,
- cir::DynamicCastOp op) {
- mlir::Location loc = op.getLoc();
- bool vtableUsesRelativeLayout = op.getRelativeLayout();
-
- // TODO(cir): consider address space in this function.
- assert(!cir::MissingFeatures::addressSpace());
-
- mlir::Type vtableElemTy;
- uint64_t vtableElemAlign;
- if (vtableUsesRelativeLayout) {
- vtableElemTy = builder.getSIntNTy(32);
- vtableElemAlign = 4;
- } else {
- const auto &targetInfo = astCtx.getTargetInfo();
- auto ptrdiffTy = targetInfo.getPtrDiffType(clang::LangAS::Default);
- bool ptrdiffTyIsSigned = clang::TargetInfo::isTypeSigned(ptrdiffTy);
- uint64_t ptrdiffTyWidth = targetInfo.getTypeWidth(ptrdiffTy);
-
- vtableElemTy = cir::IntType::get(builder.getContext(), ptrdiffTyWidth,
- ptrdiffTyIsSigned);
- vtableElemAlign =
- llvm::divideCeil(targetInfo.getPointerAlign(clang::LangAS::Default), 8);
- }
-
- // Access vtable to get the offset from the given object to its containing
- // complete object.
- // TODO: Add a specialized operation to get the object offset?
- auto vptrPtr = cir::VTableGetVPtrOp::create(builder, loc, op.getSrc());
- mlir::Value vptr = builder.createLoad(loc, vptrPtr);
- mlir::Value elementPtr =
- builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy));
- mlir::Value minusTwo = builder.getSignedInt(loc, -2, 64);
- auto offsetToTopSlotPtr = cir::PtrStrideOp::create(
- builder, loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo);
- mlir::Value offsetToTop =
- builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign);
-
- // Add the offset to the given pointer to get the cast result.
- // Cast the input pointer to a uint8_t* to allow pointer arithmetic.
- cir::PointerType u8PtrTy = builder.getPointerTo(builder.getUIntNTy(8));
- mlir::Value srcBytePtr = builder.createBitcast(op.getSrc(), u8PtrTy);
- auto dstBytePtr =
- cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop);
- // Cast the result to a void*.
- return builder.createBitcast(dstBytePtr, builder.getVoidPtrTy());
-}
-
-mlir::Value
-LoweringPrepareItaniumCXXABI::lowerDynamicCast(cir::CIRBaseBuilderTy &builder,
- clang::ASTContext &astCtx,
- cir::DynamicCastOp op) {
- mlir::Location loc = op->getLoc();
- mlir::Value srcValue = op.getSrc();
-
- assert(!cir::MissingFeatures::emitTypeCheck());
-
- if (op.isRefCast())
- return buildDynamicCastAfterNullCheck(builder, op);
-
- mlir::Value srcValueIsNotNull = builder.createPtrToBoolCast(srcValue);
- return cir::TernaryOp::create(
- builder, loc, srcValueIsNotNull,
- [&](mlir::OpBuilder &, mlir::Location) {
- mlir::Value castedValue =
- op.isCastToVoid()
- ? buildDynamicCastToVoidAfterNullCheck(builder, astCtx,
- op)
- : buildDynamicCastAfterNullCheck(builder, op);
- builder.createYield(loc, castedValue);
- },
- [&](mlir::OpBuilder &, mlir::Location) {
- builder.createYield(
- loc, builder.getNullPtr(op.getType(), loc).getResult());
- })
- .getResult();
-}
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
index 07d60ae6fb018..108e56a107738 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -111,6 +111,9 @@ class CIRCXXABI {
virtual mlir::Value lowerMethodToBoolCast(cir::CastOp op,
mlir::Value loweredSrc,
mlir::OpBuilder &builder) const = 0;
+
+ virtual mlir::Value lowerDynamicCast(cir::DynamicCastOp op,
+ mlir::OpBuilder &builder) const = 0;
};
/// Creates an Itanium-family ABI.
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
index 03fbfb2ec8554..c910bc09c73c3 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -96,6 +96,9 @@ class LowerItaniumCXXABI : public CIRCXXABI {
mlir::Value lowerMethodToBoolCast(cir::CastOp op, mlir::Value loweredSrc,
mlir::OpBuilder &builder) const override;
+
+ mlir::Value lowerDynamicCast(cir::DynamicCastOp op,
+ mlir::OpBuilder &builder) const override;
};
} // namespace
@@ -511,4 +514,168 @@ mlir::Value LowerItaniumCXXABI::lowerMethodToBoolCast(
ptrdiffZero);
}
+static void buildBadCastCall(mlir::OpBuilder &builder, mlir::Location loc,
+ mlir::FlatSymbolRefAttr badCastFuncRef) {
+ cir::CallOp::create(builder, loc, badCastFuncRef, /*resType=*/cir::VoidType(),
+ /*operands=*/mlir::ValueRange{});
+ // TODO(cir): Set the 'noreturn' attribute on the function.
+ assert(!cir::MissingFeatures::opFuncNoReturn());
+
+ cir::UnreachableOp::create(builder, loc);
+ builder.clearInsertionPoint();
+}
+
+static mlir::Value buildDynamicCastAfterNullCheck(cir::DynamicCastOp op,
+ mlir::OpBuilder &builder) {
+ mlir::Location loc = op->getLoc();
+ mlir::Value srcValue = op.getSrc();
+ cir::DynamicCastInfoAttr castInfo = op.getInfo().value();
+
+ // TODO(cir): consider address space
+ assert(!cir::MissingFeatures::addressSpace());
+
+ auto voidPtrTy =
+ cir::PointerType::get(cir::VoidType::get(builder.getContext()));
+
+ mlir::Value srcPtr = cir::CastOp::create(builder, loc, voidPtrTy,
+ cir::CastKind::bitcast, srcValue);
+ mlir::Value srcRtti =
+ cir::ConstantOp::create(builder, loc, castInfo.getSrcRtti());
+ mlir::Value destRtti =
+ cir::ConstantOp::create(builder, loc, castInfo.getDestRtti());
+ mlir::Value offsetHint =
+ cir::ConstantOp::create(builder, loc, castInfo.getOffsetHint());
+
+ mlir::FlatSymbolRefAttr dynCastFuncRef = castInfo.getRuntimeFunc();
+ mlir::Value dynCastFuncArgs[4] = {srcPtr, srcRtti, destRtti, offsetHint};
+
+ mlir::Value castedPtr = cir::CallOp::create(builder, loc, dynCastFuncRef,
+ voidPtrTy, dynCastFuncArgs)
+ .getResult();
+
+ assert(mlir::isa<cir::PointerType>(castedPtr.getType()) &&
+ "the return value of __dynamic_cast should be a ptr");
+
+ /// C++ [expr.dynamic.cast]p9:
+ /// A failed cast to reference type throws std::bad_cast
+ if (op.isRefCast()) {
+ // Emit a cir.if that checks the casted value.
+ mlir::Value null = cir::ConstantOp::create(
+ builder, loc,
+ cir::ConstPtrAttr::get(castedPtr.getType(),
+ builder.getI64IntegerAttr(0)));
+ mlir::Value castedPtrIsNull =
+ cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, castedPtr, null);
+ cir::IfOp::create(builder, loc, castedPtrIsNull, false,
+ [&](mlir::OpBuilder &, mlir::Location) {
+ buildBadCastCall(builder, loc,
+ castInfo.getBadCastFunc());
+ });
+ }
+
+ // Note that castedPtr is a void*. Cast it to a pointer to the destination
+ // type before return.
+ return cir::CastOp::create(builder, loc, op.getType(), cir::CastKind::bitcast,
+ castedPtr);
+}
+
+static mlir::Value buildDynamicCastToVoidAfterNullCheck(
+ cir::DynamicCastOp op, cir::LowerModule &lm, mlir::OpBuilder &builder) {
+ mlir::Location loc = op.getLoc();
+ bool vtableUsesRelativeLayout = op.getRelativeLayout();
+
+ // TODO(cir): consider address space in this function.
+ assert(!cir::MissingFeatures::addressSpace());
+
+ mlir::Type vtableElemTy;
+ uint64_t vtableElemAlign;
+ if (vtableUsesRelativeLayout) {
+ vtableElemTy =
+ cir::IntType::get(builder.getContext(), 32, /*isSigned=*/true);
+ vtableElemAlign = 4;
+ } else {
+ vtableElemTy = getPtrDiffCIRTy(lm);
+ vtableElemAlign = llvm::divideCeil(
+ lm.getTarget().getPointerAlign(clang::LangAS::Default), 8);
+ }
+
+ mlir::Type vtableElemPtrTy = cir::PointerType::get(vtableElemTy);
+ mlir::Type i64Ty = cir::IntType::get(builder.getContext(), /*width=*/64,
+ /*isSigned=*/true);
+
+ // Access vtable to get the offset from the given object to its containing
+ // complete object.
+ // TODO: Add a specialized operation to get the object offset?
+ auto vptrPtr = cir::VTableGetVPtrOp::create(builder, loc, op.getSrc());
+ mlir::Value vptr = cir::LoadOp::create(
+ builder, loc, vptrPtr,
+ /*isDeref=*/false,
+ /*is_volatile=*/false,
+ /*alignment=*/builder.getI64IntegerAttr(vtableElemAlign),
+ /*sync_scope=*/cir::SyncScopeKindAttr(),
+ /*mem_order=*/cir::MemOrderAttr());
+ mlir::Value elementPtr = cir::CastOp::create(builder, loc, vtableElemPtrTy,
+ cir::CastKind::bitcast, vptr);
+ mlir::Value minusTwo =
+ cir::ConstantOp::create(builder, loc, cir::IntAttr::get(i64Ty, -2));
+ mlir::Value offsetToTopSlotPtr = cir::PtrStrideOp::create(
+ builder, loc, vtableElemPtrTy, elementPtr, minusTwo);
+ mlir::Value offsetToTop = cir::LoadOp::create(
+ builder, loc, offsetToTopSlotPtr,
+ /*isDeref=*/false,
+ /*is_volatile=*/false,
+ /*alignment=*/builder.getI64IntegerAttr(vtableElemAlign),
+ /*sync_scope=*/cir::SyncScopeKindAttr(),
+ /*mem_order=*/cir::MemOrderAttr());
+
+ auto voidPtrTy =
+ cir::PointerType::get(cir::VoidType::get(builder.getContext()));
+
+ // Add the offset to the given pointer to get the cast result.
+ // Cast the input pointer to a uint8_t* to allow pointer arithmetic.
+ mlir::Type u8PtrTy =
+ cir::PointerType::get(cir::IntType::get(builder.getContext(), /*width=*/8,
+ /*isSigned=*/false));
+ mlir::Value srcBytePtr = cir::CastOp::create(
+ builder, loc, u8PtrTy, cir::CastKind::bitcast, op.getSrc());
+ auto dstBytePtr =
+ cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop);
+ // Cast the result to a void*.
+ return cir::CastOp::create(builder, loc, voidPtrTy, cir::CastKind::bitcast,
+ dstBytePtr);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerDynamicCast(cir::DynamicCastOp op,
+ mlir::OpBuilder &builder) const {
+ mlir::Location loc = op->getLoc();
+ mlir::Value srcValue = op.getSrc();
+
+ assert(!cir::MissingFeatures::emitTypeCheck());
+
+ if (op.isRefCast())
+ return buildDynamicCastAfterNullCheck(op, builder);
+
+ mlir::Value srcValueIsNotNull = cir::CastOp::create(
+ builder, loc, cir::BoolType::get(builder.getContext()),
+ cir::CastKind::ptr_to_bool, srcValue);
+ return cir::TernaryOp::create(
+ builder, loc, srcValueIsNotNull,
+ [&](mlir::OpBuilder &, mlir::Location) {
+ mlir::Value castedValue =
+ op.isCastToVoid()
+ ? buildDynamicCastToVoidAfterNullCheck(op, lm, builder)
+ : buildDynamicCastAfterNullCheck(op, builder);
+ cir::YieldOp::create(builder, loc, castedValue);
+ },
+ [&](mlir::OpBuilder &, mlir::Location) {
+ mlir::Value null = cir::ConstantOp::create(
+ builder, loc,
+ cir::ConstPtrAttr::get(op.getType(),
+ builder.getI64IntegerAttr(0)));
+ cir::YieldOp::create(builder, loc, null);
+ })
+ .getResult();
+}
+
} // namespace cir
diff --git a/clang/test/CIR/CodeGen/dynamic-cast.cpp b/clang/test/CIR/CodeGen/dynamic-cast.cpp
index e963be01950c4..233fe66e1a935 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t.before.log
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> %t.before.log
// RUN: FileCheck %s --input-file=%t.before.log -check-prefix=CIR-BEFORE
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2> %t.after.log
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-cxxabi-lowering %s -o %t.cir 2> %t.after.log
// RUN: FileCheck %s --input-file=%t.after.log -check-prefix=CIR-AFTER
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck %s --input-file=%t-cir.ll -check-prefix=LLVM
@@ -115,7 +115,7 @@ void *ptr_cast_to_complete(Base *ptr) {
// CIR-AFTER-NEXT: %[[SRC_IS_NOT_NULL:.*]] = cir.cast ptr_to_bool %[[SRC]] : !cir.ptr<!rec_Base> -> !cir.bool
// CIR-AFTER-NEXT: %{{.+}} = cir.ternary(%[[SRC_IS_NOT_NULL]], true {
// CIR-AFTER-NEXT: %[[VPTR_PTR:.*]] = cir.vtable.get_vptr %[[SRC]] : !cir.ptr<!rec_Base> -> !cir.ptr<!cir.vptr>
-// CIR-AFTER-NEXT: %[[VPTR:.*]] = cir.load %[[VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR-AFTER-NEXT: %[[VPTR:.*]] = cir.load {{.*}} %[[VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
// CIR-AFTER-NEXT: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[VPTR]] : !cir.vptr -> !cir.ptr<!s64i>
// CIR-AFTER-NEXT: %[[MINUS_TWO:.*]] = cir.const #cir.int<-2> : !s64i
// CIR-AFTER-NEXT: %[[BASE_OFFSET_PTR:.*]] = cir.ptr_stride %[[ELEM_PTR]], %[[MINUS_TWO]] : (!cir.ptr<!s64i>, !s64i) -> !cir.ptr<!s64i>
More information about the cfe-commits
mailing list