-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[CIR] Add lowering support for dynamic cast #162715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds support for lowering cir.dyn_cast operations to a form that can be lowered to LLVM IR.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds support for lowering cir.dyn_cast operations to a form that can be lowered to LLVM IR. Patch is 21.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/162715.diff 9 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 11ad61fdb8065..b4c24d7e4a8aa 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -451,6 +451,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createBitcast(src, getPointerTo(newPointeeTy));
}
+ mlir::Value createPtrIsNull(mlir::Value ptr) {
+ mlir::Value nullPtr = getNullPtr(ptr.getType(), ptr.getLoc());
+ return createCompare(ptr.getLoc(), cir::CmpOpKind::eq, ptr, nullPtr);
+ }
+
//===--------------------------------------------------------------------===//
// Binary Operators
//===--------------------------------------------------------------------===//
@@ -644,6 +649,12 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return getI64IntegerAttr(size.getQuantity());
}
+ // Creates constant nullptr for pointer type ty.
+ cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
+ assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
+ return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0));
+ }
+
/// Create a loop condition.
cir::ConditionOp createCondition(mlir::Value condition) {
return cir::ConditionOp::create(*this, condition.getLoc(), condition);
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index ace20868532f0..df82ca138d4b1 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -85,6 +85,7 @@ struct MissingFeatures {
static bool opFuncReadOnly() { return false; }
static bool opFuncSection() { return false; }
static bool opFuncWillReturn() { return false; }
+ static bool opFuncNoReturn() { return false; }
static bool setLLVMFunctionFEnvAttributes() { return false; }
static bool setFunctionAttributes() { return false; }
@@ -256,6 +257,8 @@ struct MissingFeatures {
static bool loopInfoStack() { return false; }
static bool lowerAggregateLoadStore() { return false; }
static bool lowerModeOptLevel() { return false; }
+ static bool loweringPrepareX86CXXABI() { return false; }
+ static bool loweringPrepareAArch64XXABI() { return false; }
static bool maybeHandleStaticInExternC() { return false; }
static bool mergeAllConstants() { return false; }
static bool metaDataNode() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 25afe8b6b901d..a6f10e6bb9e9c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -319,12 +319,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(sInt64Ty, c));
}
- // Creates constant nullptr for pointer type ty.
- cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
- assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
- return cir::ConstantOp::create(*this, loc, getConstPtrAttr(ty, 0));
- }
-
mlir::Value createNeg(mlir::Value value) {
if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index df7a1a3e0acb5..3fc5b06b74e4d 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(MLIRCIRTransforms
FlattenCFG.cpp
HoistAllocas.cpp
LoweringPrepare.cpp
+ LoweringPrepareItaniumCXXABI.cpp
GotoSolver.cpp
DEPENDS
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 706e54f064aa6..dbff0b98fbe42 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "LoweringPrepareCXXABI.h"
#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Module.h"
@@ -62,6 +63,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<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);
@@ -91,6 +93,9 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
clang::ASTContext *astCtx;
+ // Helper for lowering C++ ABI specific operations.
+ std::shared_ptr<cir::LoweringPrepareCXXABI> cxxABI;
+
/// Tracks current module.
mlir::ModuleOp mlirModule;
@@ -101,7 +106,24 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
/// List of ctors and their priorities to be called before main()
llvm::SmallVector<std::pair<std::string, uint32_t>, 4> globalCtorList;
- void setASTContext(clang::ASTContext *c) { astCtx = c; }
+ 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");
+ }
+ }
};
} // namespace
@@ -850,6 +872,17 @@ 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,
@@ -954,6 +987,8 @@ 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);
}
@@ -967,8 +1002,8 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
- cir::ComplexMulOp, cir::ComplexDivOp, cir::GlobalOp,
- cir::UnaryOp>(op))
+ cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
+ cir::GlobalOp, cir::UnaryOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
new file mode 100644
index 0000000000000..2582c332d52a6
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareCXXABI.h
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
new file mode 100644
index 0000000000000..7d3c711251b9f
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepareItaniumCXXABI.cpp
@@ -0,0 +1,126 @@
+//===--------------------------------------------------------------------===//
+//
+// 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);
+ builder.create<cir::IfOp>(
+ 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) {
+ llvm_unreachable("dynamic cast to void is NYI");
+}
+
+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 builder
+ .create<cir::TernaryOp>(
+ 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/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a1ecfc7a70909..26e0ba9b4e45a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1739,7 +1739,6 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
const StringRef symbol = op.getSymName();
SmallVector<mlir::NamedAttribute> attributes;
- mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
if (init.has_value()) {
if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {
@@ -1771,6 +1770,7 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
}
// Rewrite op.
+ mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),
alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);
diff --git a/clang/test/CIR/CodeGen/dynamic-cast.cpp b/clang/test/CIR/CodeGen/dynamic-cast.cpp
index e5244b220e76c..b4938402f0256 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast.cpp
@@ -1,5 +1,11 @@
// 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: 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: 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
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o %t.ll
+// RUN: FileCheck %s --input-file=%t.ll -check-prefix=OGCG
struct Base {
virtual ~Base();
@@ -19,6 +25,46 @@ Derived *ptr_cast(Base *b) {
// CIR-BEFORE: %{{.+}} = cir.dyn_cast ptr %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
// CIR-BEFORE: }
+// CIR-AFTER: cir.func dso_local @_Z8ptr_castP4Base
+// CIR-AFTER: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base>>, !cir.ptr<!rec_Base>
+// 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: %[[SRC_VOID_PTR:.*]] = cir.cast bitcast %[[SRC]] : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+// CIR-AFTER-NEXT: %[[BASE_RTTI:.*]] = cir.const #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>
+// CIR-AFTER-NEXT: %[[DERIVED_RTTI:.*]] = cir.const #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>
+// CIR-AFTER-NEXT: %[[HINT:.*]] = cir.const #cir.int<0> : !s64i
+// CIR-AFTER-NEXT: %[[RT_CALL_RET:.*]] = cir.call @__dynamic_cast(%[[SRC_VOID_PTR]], %[[BASE_RTTI]], %[[DERIVED_RTTI]], %[[HINT]]) : (!cir.ptr<!void>, !cir.ptr<!u8i>, !cir.ptr<!u8i>, !s64i) -> !cir.ptr<!void>
+// CIR-AFTER-NEXT: %[[CASTED:.*]] = cir.cast bitcast %[[RT_CALL_RET]] : !cir.ptr<!void> -> !cir.ptr<!rec_Derived>
+// CIR-AFTER-NEXT: cir.yield %[[CASTED]] : !cir.ptr<!rec_Derived>
+// CIR-AFTER-NEXT: }, false {
+// CIR-AFTER-NEXT: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Derived>
+// CIR-AFTER-NEXT: cir.yield %[[NULL_PTR]] : !cir.ptr<!rec_Derived>
+// CIR-AFTER-NEXT: }) : (!cir.bool) -> !cir.ptr<!rec_Derived>
+// CIR-AFTER: }
+
+// LLVM: define {{.*}} @_Z8ptr_castP4Base
+// LLVM: %[[IS_NOT_NULL:.*]] = icmp ne ptr %[[PTR:.*]], null
+// LLVM: br i1 %[[IS_NOT_NULL]], label %[[NOT_NULL:.*]], label %[[NULL:.*]]
+// LLVM: [[NOT_NULL]]:
+// LLVM: %[[RESULT:.*]] = call ptr @__dynamic_cast(ptr %[[PTR]], ptr @_ZTI4Base, ptr @_ZTI7Derived, i64 0)
+// LLVM: br label %[[DONE:.*]]
+// LLVM: [[NULL]]:
+// LLVM: br label %[[DONE]]
+// LLVM: [[DONE]]:
+// LLVM: %[[RET:.*]] = phi ptr [ null, %[[NULL]] ], [ %[[RESULT]], %[[NOT_NULL]] ]
+
+// OGCG: define {{.*}} @_Z8ptr_castP4Base
+// OGCG: %[[IS_NULL:.*]] = icmp eq ptr %[[PTR:.*]], null
+// OGCG: br i1 %[[IS_NULL]], label %[[NULL:.*]], label %[[NOT_NULL:.*]]
+// OGCG: [[NOT_NULL]]:
+// OGCG: %[[RESULT:.*]] = call ptr @__dynamic_cast(ptr %[[PTR]], ptr @_ZTI4Base, ptr @_ZTI7Derived, i64 0)
+// OGCG: br label %[[DONE:.*]]
+// OGCG: [[NULL]]:
+// OGCG: br label %[[DONE]]
+// OGCG: [[DONE]]:
+// OGCG: %[[RET:.*]] = phi ptr [ %[[RESULT]], %[[NOT_NULL]] ], [ null, %[[NULL]] ]
+
+
Derived &ref_cast(Base &b) {
return dynamic_cast<Derived &>(b);
}
@@ -26,3 +72,32 @@ Derived &ref_cast(Base &b) {
// CIR-BEFORE: cir.func dso_local @_Z8ref_castR4Base
// CIR-BEFORE: %{{.+}} = cir.dyn_cast ref %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
// CIR-BEFORE: }
+
+// CIR-AFTER: cir.func dso_local @_Z8ref_castR4Base
+// CIR-AFTER: %[[SRC_VOID_PTR:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+// CIR-AFTER-NEXT: %[[SRC_RTTI:.*]] = cir.const #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>
+// CIR-AFTER-NEXT: %[[DEST_RTTI:.*]] = cir.const #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>
+// CIR-AFTER-NEXT: %[[OFFSET_HINT:.*]] = cir.const #cir.int<0> : !s64i
+// CIR-AFTER-NEXT: %[[CASTED_PTR:.*]] = cir.call @__dynamic_cast(%[[SRC_VOID_PTR]], %[[SRC_RTTI]], %[[DEST_RTTI]], %[[OFFSET_HINT]]) : (!cir.ptr<!void>, !cir.ptr<!u8i>, !cir.ptr<!u8i>, !s64i) -> !cir.ptr<!void>
+// CIR-AFTER-NEXT: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR-AFTER-NEXT: %[[CASTED_PTR_IS_NULL:.*]] = cir.cmp(eq, %[[CASTED_PTR]], %[[N...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incremental and straightforward, thanks! LGTM
This adds support for lowering cir.dyn_cast operations to a form that can be lowered to LLVM IR.