https://github.com/Lancern updated 
https://github.com/llvm/llvm-project/pull/176931

>From d5dd82923a59657d41f4e35fa41421f2c60f75cb 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 958947230290b..e5d6538f8b1fb 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -340,6 +340,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 4429ca10415d8..d964f23dcdc98 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -256,6 +256,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 {
@@ -346,6 +355,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 a7d733afd18c6..12838925658ea 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -93,6 +93,9 @@ class CIRCXXABI {
   virtual mlir::Value lowerMethodCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                      mlir::Value loweredRhs,
                                      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 94342f864fca6..6fd38a0a5a3ff 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class LowerItaniumCXXABI : public CIRCXXABI {
   mlir::Value lowerMethodCmp(cir::CmpOp op, mlir::Value loweredLhs,
                              mlir::Value loweredRhs,
                              mlir::OpBuilder &builder) const override;
+
+  mlir::Value lowerDynamicCast(cir::DynamicCastOp op,
+                               mlir::OpBuilder &builder) const override;
 };
 
 } // namespace
@@ -450,4 +453,168 @@ mlir::Value LowerItaniumCXXABI::lowerMethodCmp(cir::CmpOp 
op,
   return result;
 }
 
+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

Reply via email to