https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/176931
>From d58a8fd64f4aaffd856c7c3ff7790ae8e6e6a465 Mon Sep 17 00:00:00 2001 From: Sirui Mu <[email protected]> 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 27e6a650fde27..920d4044743b6 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> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
