[clang] [CIR] Upstream DynamicCastOp (PR #161734)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 6 13:36:18 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/161734
>From 03ac434cce6980004bd662480e72db5d4e24d9f6 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 1 Oct 2025 17:52:53 -0700
Subject: [PATCH 1/3] [CIR] Upstream DynamicCastOp
This adds the dialect handling for CIR_DynamicCastOp and
CIR_DynamicCastInfoAttr. Support for generating these operations from
source will be added in a later change.
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 53 +++++++++++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 94 +++++++++++++++++++
.../CIR/Dialect/IR/CIRTypeConstraints.td | 8 ++
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 43 +++++++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 +
clang/test/CIR/IR/dynamic-cast.cir | 59 ++++++++++++
clang/test/CIR/IR/invalid-dyn-cast.cir | 43 +++++++++
7 files changed, 304 insertions(+)
create mode 100644 clang/test/CIR/IR/dynamic-cast.cir
create mode 100644 clang/test/CIR/IR/invalid-dyn-cast.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 7714750a53d44..0a757a0a68f3c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -601,6 +601,59 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
}];
}
+//===----------------------------------------------------------------------===//
+// DynamicCastInfoAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_DynamicCastInfoAttr : CIR_Attr<"DynamicCastInfo", "dyn_cast_info"> {
+ let summary = "ABI specific information about a dynamic cast";
+ let description = [{
+ Provide ABI specific information about a dynamic cast operation.
+
+ The `srcRtti` and the `destRtti` parameters give the RTTI of the source
+ record type and the destination record type, respectively.
+
+ The `runtimeFunc` parameter gives the `__dynamic_cast` function which is
+ provided by the runtime. The `badCastFunc` parameter gives the
+ `__cxa_bad_cast` function which is also provided by the runtime.
+
+ The `offsetHint` parameter gives the hint value that should be passed to the
+ `__dynamic_cast` runtime function.
+ }];
+
+ let parameters = (ins
+ CIR_GlobalViewAttr:$srcRtti,
+ CIR_GlobalViewAttr:$destRtti,
+ "mlir::FlatSymbolRefAttr":$runtimeFunc,
+ "mlir::FlatSymbolRefAttr":$badCastFunc,
+ CIR_IntAttr:$offsetHint
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "GlobalViewAttr":$srcRtti,
+ "GlobalViewAttr":$destRtti,
+ "mlir::FlatSymbolRefAttr":$runtimeFunc,
+ "mlir::FlatSymbolRefAttr":$badCastFunc,
+ "IntAttr":$offsetHint), [{
+ return $_get(srcRtti.getContext(), srcRtti, destRtti, runtimeFunc,
+ badCastFunc, offsetHint);
+ }]>,
+ ];
+
+ let genVerifyDecl = 1;
+ let assemblyFormat = [{
+ `<`
+ qualified($srcRtti) `,` qualified($destRtti) `,`
+ $runtimeFunc `,` $badCastFunc `,` qualified($offsetHint)
+ `>`
+ }];
+
+ let extraClassDeclaration = [{
+ /// Get attribute alias name for this attribute.
+ std::string getAlias() const;
+ }];
+}
+
//===----------------------------------------------------------------------===//
// TargetAddressSpaceAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index c81f64deff7bc..f2183bf509219 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -232,6 +232,100 @@ def CIR_CastOp : CIR_Op<"cast", [
}];
}
+//===----------------------------------------------------------------------===//
+// DynamicCastOp
+//===----------------------------------------------------------------------===//
+
+def CIR_DynamicCastKind : CIR_I32EnumAttr<
+ "DynamicCastKind", "dynamic cast kind", [
+ I32EnumAttrCase<"Ptr", 0, "ptr">,
+ I32EnumAttrCase<"Ref", 1, "ref">
+]>;
+
+def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> {
+ let summary = "Perform dynamic cast on record pointers";
+ let description = [{
+ The `cir.dyn_cast` operation models part of the semantics of the
+ `dynamic_cast` operator in C++. It can be used to perform 3 kinds of casts
+ on record pointers:
+
+ - Down-cast, which casts a base class pointer to a derived class pointer;
+ - Side-cast, which casts a class pointer to a sibling class pointer;
+ - Cast-to-complete, which casts a class pointer to a void pointer.
+
+ The input of the operation must be a record pointer. The result of the
+ operation is either a record pointer or a void pointer.
+
+ The parameter `kind` specifies the semantics of this operation. If its value
+ is `ptr`, then the operation models dynamic casts on pointers. Otherwise, if
+ its value is `ref`, the operation models dynamic casts on references.
+ Specifically:
+
+ - When the input pointer is a null pointer value:
+ - If `kind` is `ref`, the operation will invoke undefined behavior. A
+ sanitizer check will be emitted if sanitizer is on.
+ - Otherwise, the operation will return a null pointer value as its result.
+ - When the runtime type check fails:
+ - If `kind` is `ref`, the operation will throw a `bad_cast` exception.
+ - Otherwise, the operation will return a null pointer value as its result.
+
+ The `info` argument gives detailed information about the requested dynamic
+ cast operation. It is an optional `#cir.dyn_cast_info` attribute that is
+ only present when the operation models a down-cast or a side-cast.
+
+ The `relative_layout` argument specifies whether the Itanium C++ ABI vtable
+ uses relative layout. It is only meaningful when the operation models a
+ cast-to-complete operation.
+
+ Examples:
+
+ ```mlir
+ %0 = cir.dyn_cast ptr %p : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived>
+ %1 = cir.dyn_cast ptr relative_layout %p : !cir.ptr<!rec_Base>
+ -> !cir.ptr<!rec_Derived>
+ %2 = cir.dyn_cast ref %r : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived>
+ #cir.dyn_cast_info<
+ #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>,
+ @__dynamic_cast,
+ @__cxa_bad_cast,
+ #cir.int<0> : !s64i
+ >
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_DynamicCastKind:$kind,
+ CIR_PtrToRecordType:$src,
+ OptionalAttr<CIR_DynamicCastInfoAttr>:$info,
+ UnitAttr:$relative_layout
+ );
+
+ let results = (outs
+ CIR_PtrToAnyOf<[CIR_VoidType, CIR_RecordType]>:$result
+ );
+
+ let assemblyFormat = [{
+ $kind (`relative_layout` $relative_layout^)? $src
+ `:` qualified(type($src)) `->` qualified(type($result))
+ (qualified($info)^)? attr-dict
+ }];
+
+ let extraClassDeclaration = [{
+ /// Determine whether this operation models reference casting in C++.
+ bool isRefcast() {
+ return getKind() == ::cir::DynamicCastKind::Ref;
+ }
+
+ /// Determine whether this operation represents a dynamic cast to a void
+ /// pointer.
+ bool isCastToVoid() {
+ return getType().isVoidPtr();
+ }
+ }];
+
+ let hasLLVMLowering = false;
+}
//===----------------------------------------------------------------------===//
// PtrStrideOp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
index da03a291a7690..9e8e1298308a4 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
@@ -171,6 +171,12 @@ def CIR_AnyComplexOrIntOrFloatType : AnyTypeOf<[
let cppFunctionName = "isComplexOrIntegerOrFloatingPointType";
}
+//===----------------------------------------------------------------------===//
+// Record Type predicates
+//===----------------------------------------------------------------------===//
+
+def CIR_AnyRecordType : CIR_TypeBase<"::cir::RecordType", "record type">;
+
//===----------------------------------------------------------------------===//
// Array Type predicates
//===----------------------------------------------------------------------===//
@@ -228,6 +234,8 @@ def CIR_PtrToIntOrFloatType : CIR_PtrToType<CIR_AnyIntOrFloatType>;
def CIR_PtrToComplexType : CIR_PtrToType<CIR_AnyComplexType>;
+def CIR_PtrToRecordType : CIR_PtrToType<CIR_AnyRecordType>;
+
def CIR_PtrToArray : CIR_PtrToType<CIR_AnyArrayType>;
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 3484c59df4ece..64ac97025e7c7 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -472,6 +472,49 @@ LogicalResult cir::VTableAttr::verify(
return success();
}
+//===----------------------------------------------------------------------===//
+// DynamicCastInfoAtttr definitions
+//===----------------------------------------------------------------------===//
+
+std::string DynamicCastInfoAttr::getAlias() const {
+ // The alias looks like: `dyn_cast_info_<src>_<dest>`
+
+ std::string alias = "dyn_cast_info_";
+
+ alias.append(getSrcRtti().getSymbol().getValue());
+ alias.push_back('_');
+ alias.append(getDestRtti().getSymbol().getValue());
+
+ return alias;
+}
+
+LogicalResult DynamicCastInfoAttr::verify(
+ function_ref<InFlightDiagnostic()> emitError, cir::GlobalViewAttr srcRtti,
+ cir::GlobalViewAttr destRtti, mlir::FlatSymbolRefAttr runtimeFunc,
+ mlir::FlatSymbolRefAttr badCastFunc, cir::IntAttr offsetHint) {
+ auto isRttiPtr = [](mlir::Type ty) {
+ // RTTI pointers are !cir.ptr<!u8i>.
+
+ auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty);
+ if (!ptrTy)
+ return false;
+
+ auto pointeeIntTy = mlir::dyn_cast<cir::IntType>(ptrTy.getPointee());
+ if (!pointeeIntTy)
+ return false;
+
+ return pointeeIntTy.isUnsigned() && pointeeIntTy.getWidth() == 8;
+ };
+
+ if (!isRttiPtr(srcRtti.getType()))
+ return emitError() << "srcRtti must be an RTTI pointer";
+
+ if (!isRttiPtr(destRtti.getType()))
+ return emitError() << "destRtti must be an RTTI pointer";
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index cdd4e3c96ca98..5f88590c48d30 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -71,6 +71,10 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface {
os << "bfi_" << bitfield.getName().str();
return AliasResult::FinalAlias;
}
+ if (auto dynCastInfoAttr = mlir::dyn_cast<cir::DynamicCastInfoAttr>(attr)) {
+ os << dynCastInfoAttr.getAlias();
+ return AliasResult::FinalAlias;
+ }
return AliasResult::NoAlias;
}
};
diff --git a/clang/test/CIR/IR/dynamic-cast.cir b/clang/test/CIR/IR/dynamic-cast.cir
new file mode 100644
index 0000000000000..a7468f1e97211
--- /dev/null
+++ b/clang/test/CIR/IR/dynamic-cast.cir
@@ -0,0 +1,59 @@
+// RUN: cir-opt --verify-roundtrip %s | FileCheck %s
+
+!s64i = !cir.int<s, 64>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+
+!rec_Base = !cir.record<struct "Base" {!cir.vptr}>
+!rec_Derived = !cir.record<struct "Derived" {!rec_Base}>
+
+#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+
+// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+
+module {
+ cir.global "private" constant external @_ZTI4Base : !cir.ptr<!u8i>
+ cir.global "private" constant external @_ZTI7Derived : !cir.ptr<!u8i>
+ cir.func private @__dynamic_cast(!cir.ptr<!void>, !cir.ptr<!u8i>, !cir.ptr<!u8i>, !s64i) -> !cir.ptr<!void>
+ cir.func private @__cxa_bad_cast()
+
+ cir.func @test_ptr_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!rec_Derived> {
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
+ cir.return %0 : !cir.ptr<!rec_Derived>
+ }
+
+ // CHECK: cir.func @test_ptr_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!rec_Derived> {
+ // CHECK: %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
+ // CHECK: cir.return %0 : !cir.ptr<!rec_Derived>
+ // CHECK: }
+
+ cir.func @test_ref_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!rec_Derived> {
+ %0 = cir.dyn_cast ref %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
+ cir.return %0 : !cir.ptr<!rec_Derived>
+ }
+
+ // CHECK: cir.func @test_ref_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!rec_Derived> {
+ // CHECK: %0 = cir.dyn_cast ref %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived
+ // CHECK: cir.return %0 : !cir.ptr<!rec_Derived>
+ // CHECK: }
+
+ cir.func dso_local @test_cast_to_void(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!void> {
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+ cir.return %0 : !cir.ptr<!void>
+ }
+
+ // CHECK: cir.func dso_local @test_cast_to_void(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!void> {
+ // CHECK: %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+ // CHECK: cir.return %0 : !cir.ptr<!void>
+ // CHECK: }
+
+ cir.func dso_local @test_relative_layout_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!void> {
+ %0 = cir.dyn_cast ptr relative_layout %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+ cir.return %0 : !cir.ptr<!void>
+ }
+
+ // CHECK: cir.func dso_local @test_relative_layout_cast(%arg0: !cir.ptr<!rec_Base>) -> !cir.ptr<!void> {
+ // CHECK: %0 = cir.dyn_cast ptr relative_layout %arg0 : !cir.ptr<!rec_Base> -> !cir.ptr<!void>
+ // CHECK: cir.return %0 : !cir.ptr<!void>
+ // CHECK: }
+}
diff --git a/clang/test/CIR/IR/invalid-dyn-cast.cir b/clang/test/CIR/IR/invalid-dyn-cast.cir
new file mode 100644
index 0000000000000..b6ac3ebcfef95
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-dyn-cast.cir
@@ -0,0 +1,43 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s64i = !cir.int<s, 64>
+!s8i = !cir.int<s, 8>
+!u32i = !cir.int<u, 32>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+
+!Base = !cir.record<struct "Base" {!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 32>>>>}>
+!Derived = !cir.record<struct "Derived" {!cir.record<struct "Base" {!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 32>>>>}>}>
+
+module {
+ cir.global "private" constant external @_ZTI4Base : !cir.ptr<!u32i>
+ cir.global "private" constant external @_ZTI7Derived : !cir.ptr<!u8i>
+ cir.func private @__dynamic_cast(!cir.ptr<!void>, !cir.ptr<!u8i>, !cir.ptr<!u8i>, !s64i) -> !cir.ptr<!void>
+ cir.func private @__cxa_bad_cast()
+ cir.func @test(%arg0 : !cir.ptr<!Base>) {
+ // expected-error at +1 {{srcRtti must be an RTTI pointer}}
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u32i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+ }
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!s8i = !cir.int<s, 8>
+!u32i = !cir.int<u, 32>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+
+!Base = !cir.record<struct "Base" {!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 32>>>>}>
+!Derived = !cir.record<struct "Derived" {!cir.record<struct "Base" {!cir.ptr<!cir.ptr<!cir.func<() -> !cir.int<u, 32>>>>}>}>
+
+module {
+ cir.global "private" constant external @_ZTI4Base : !cir.ptr<!u8i>
+ cir.global "private" constant external @_ZTI7Derived : !cir.ptr<!u32i>
+ cir.func private @__dynamic_cast(!cir.ptr<!void>, !cir.ptr<!u8i>, !cir.ptr<!u8i>, !s64i) -> !cir.ptr<!void>
+ cir.func private @__cxa_bad_cast()
+ cir.func @test(%arg0 : !cir.ptr<!Base>) {
+ // expected-error at +1 {{destRtti must be an RTTI pointer}}
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+ }
+}
>From d849dc26f92a1028ac728f2a1af873ab6c11438c Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Fri, 3 Oct 2025 10:41:11 -0700
Subject: [PATCH 2/3] Apply review feedback
---
clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 5 +++--
clang/include/clang/CIR/Dialect/IR/CIROps.td | 12 ++++++------
clang/test/CIR/IR/dynamic-cast.cir | 4 ++--
clang/test/CIR/IR/invalid-dyn-cast.cir | 4 ++--
4 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 0a757a0a68f3c..1cd67ef794f69 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -643,8 +643,9 @@ def CIR_DynamicCastInfoAttr : CIR_Attr<"DynamicCastInfo", "dyn_cast_info"> {
let genVerifyDecl = 1;
let assemblyFormat = [{
`<`
- qualified($srcRtti) `,` qualified($destRtti) `,`
- $runtimeFunc `,` $badCastFunc `,` qualified($offsetHint)
+ `srcRtti` `=` qualified($srcRtti) `,` `destRtti` `=` qualified($destRtti)
+ `,` `runtimeFunc` `=` $runtimeFunc `,` `badCastFunc` `=` $badCastFunc `,`
+ `offsetHint` `=` qualified($offsetHint)
`>`
}];
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index f2183bf509219..ce7019f9e21f7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -285,11 +285,11 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> {
-> !cir.ptr<!rec_Derived>
%2 = cir.dyn_cast ref %r : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived>
#cir.dyn_cast_info<
- #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>,
- #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>,
- @__dynamic_cast,
- @__cxa_bad_cast,
- #cir.int<0> : !s64i
+ srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>,
+ destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>,
+ runtimeFunc = @__dynamic_cast,
+ badCastFunc = @__cxa_bad_cast,
+ offsetHint = #cir.int<0> : !s64i
>
```
}];
@@ -313,7 +313,7 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> {
let extraClassDeclaration = [{
/// Determine whether this operation models reference casting in C++.
- bool isRefcast() {
+ bool isRefCast() {
return getKind() == ::cir::DynamicCastKind::Ref;
}
diff --git a/clang/test/CIR/IR/dynamic-cast.cir b/clang/test/CIR/IR/dynamic-cast.cir
index a7468f1e97211..3d9ac2cbebe76 100644
--- a/clang/test/CIR/IR/dynamic-cast.cir
+++ b/clang/test/CIR/IR/dynamic-cast.cir
@@ -7,9 +7,9 @@
!rec_Base = !cir.record<struct "Base" {!cir.vptr}>
!rec_Derived = !cir.record<struct "Derived" {!rec_Base}>
-#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
-// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
module {
cir.global "private" constant external @_ZTI4Base : !cir.ptr<!u8i>
diff --git a/clang/test/CIR/IR/invalid-dyn-cast.cir b/clang/test/CIR/IR/invalid-dyn-cast.cir
index b6ac3ebcfef95..b5f0c928a634f 100644
--- a/clang/test/CIR/IR/invalid-dyn-cast.cir
+++ b/clang/test/CIR/IR/invalid-dyn-cast.cir
@@ -16,7 +16,7 @@ module {
cir.func private @__cxa_bad_cast()
cir.func @test(%arg0 : !cir.ptr<!Base>) {
// expected-error at +1 {{srcRtti must be an RTTI pointer}}
- %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u32i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u32i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
}
}
@@ -38,6 +38,6 @@ module {
cir.func private @__cxa_bad_cast()
cir.func @test(%arg0 : !cir.ptr<!Base>) {
// expected-error at +1 {{destRtti must be an RTTI pointer}}
- %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i>
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
}
}
>From 5bc63da62ba59eedada8fbf51d40da1c532b4210 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Mon, 6 Oct 2025 13:32:46 -0700
Subject: [PATCH 3/3] Apply more review feedback
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 42 ++++++++++---------
clang/test/CIR/IR/dynamic-cast.cir | 4 +-
clang/test/CIR/IR/invalid-dyn-cast.cir | 4 +-
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1cd67ef794f69..38dcf428b62de 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -610,42 +610,44 @@ def CIR_DynamicCastInfoAttr : CIR_Attr<"DynamicCastInfo", "dyn_cast_info"> {
let description = [{
Provide ABI specific information about a dynamic cast operation.
- The `srcRtti` and the `destRtti` parameters give the RTTI of the source
+ The `src_rtti` and the `dest_rtti` parameters give the RTTI of the source
record type and the destination record type, respectively.
- The `runtimeFunc` parameter gives the `__dynamic_cast` function which is
- provided by the runtime. The `badCastFunc` parameter gives the
+ The `runtime_func` parameter gives the `__dynamic_cast` function which is
+ provided by the runtime. The `bad_cast_func` parameter gives the
`__cxa_bad_cast` function which is also provided by the runtime.
- The `offsetHint` parameter gives the hint value that should be passed to the
- `__dynamic_cast` runtime function.
+ The `offset_hint` parameter gives the hint value that should be passed to
+ the `__dynamic_cast` runtime function.
}];
let parameters = (ins
- CIR_GlobalViewAttr:$srcRtti,
- CIR_GlobalViewAttr:$destRtti,
- "mlir::FlatSymbolRefAttr":$runtimeFunc,
- "mlir::FlatSymbolRefAttr":$badCastFunc,
- CIR_IntAttr:$offsetHint
+ CIR_GlobalViewAttr:$src_rtti,
+ CIR_GlobalViewAttr:$dest_rtti,
+ "mlir::FlatSymbolRefAttr":$runtime_func,
+ "mlir::FlatSymbolRefAttr":$bad_cast_func,
+ CIR_IntAttr:$offset_hint
);
let builders = [
- AttrBuilderWithInferredContext<(ins "GlobalViewAttr":$srcRtti,
- "GlobalViewAttr":$destRtti,
- "mlir::FlatSymbolRefAttr":$runtimeFunc,
- "mlir::FlatSymbolRefAttr":$badCastFunc,
- "IntAttr":$offsetHint), [{
- return $_get(srcRtti.getContext(), srcRtti, destRtti, runtimeFunc,
- badCastFunc, offsetHint);
+ AttrBuilderWithInferredContext<(ins "GlobalViewAttr":$src_rtti,
+ "GlobalViewAttr":$dest_rtti,
+ "mlir::FlatSymbolRefAttr":$runtime_func,
+ "mlir::FlatSymbolRefAttr":$bad_cast_func,
+ "IntAttr":$offset_hint), [{
+ return $_get(src_rtti.getContext(), src_rtti, dest_rtti, runtime_func,
+ bad_cast_func, offset_hint);
}]>,
];
let genVerifyDecl = 1;
let assemblyFormat = [{
`<`
- `srcRtti` `=` qualified($srcRtti) `,` `destRtti` `=` qualified($destRtti)
- `,` `runtimeFunc` `=` $runtimeFunc `,` `badCastFunc` `=` $badCastFunc `,`
- `offsetHint` `=` qualified($offsetHint)
+ struct(qualified($src_rtti),
+ qualified($dest_rtti),
+ $runtime_func,
+ $bad_cast_func,
+ qualified($offset_hint))
`>`
}];
diff --git a/clang/test/CIR/IR/dynamic-cast.cir b/clang/test/CIR/IR/dynamic-cast.cir
index 3d9ac2cbebe76..283f11e25b82b 100644
--- a/clang/test/CIR/IR/dynamic-cast.cir
+++ b/clang/test/CIR/IR/dynamic-cast.cir
@@ -7,9 +7,9 @@
!rec_Base = !cir.record<struct "Base" {!cir.vptr}>
!rec_Derived = !cir.record<struct "Derived" {!rec_Base}>
-#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
+#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<src_rtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtime_func = @__dynamic_cast, bad_cast_func = @__cxa_bad_cast, offset_hint = #cir.int<0> : !s64i>
-// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
+// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<src_rtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtime_func = @__dynamic_cast, bad_cast_func = @__cxa_bad_cast, offset_hint = #cir.int<0> : !s64i>
module {
cir.global "private" constant external @_ZTI4Base : !cir.ptr<!u8i>
diff --git a/clang/test/CIR/IR/invalid-dyn-cast.cir b/clang/test/CIR/IR/invalid-dyn-cast.cir
index b5f0c928a634f..65c7fc1e5594b 100644
--- a/clang/test/CIR/IR/invalid-dyn-cast.cir
+++ b/clang/test/CIR/IR/invalid-dyn-cast.cir
@@ -16,7 +16,7 @@ module {
cir.func private @__cxa_bad_cast()
cir.func @test(%arg0 : !cir.ptr<!Base>) {
// expected-error at +1 {{srcRtti must be an RTTI pointer}}
- %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u32i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<src_rtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u32i>, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i>, runtime_func = @__dynamic_cast, bad_cast_func = @__cxa_bad_cast, offset_hint = #cir.int<0> : !s64i>
}
}
@@ -38,6 +38,6 @@ module {
cir.func private @__cxa_bad_cast()
cir.func @test(%arg0 : !cir.ptr<!Base>) {
// expected-error at +1 {{destRtti must be an RTTI pointer}}
- %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i>
+ %0 = cir.dyn_cast ptr %arg0 : !cir.ptr<!Base> -> !cir.ptr<!Derived> #cir.dyn_cast_info<src_rtti = #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i>, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u32i>, runtime_func = @__dynamic_cast, bad_cast_func = @__cxa_bad_cast, offset_hint = #cir.int<0> : !s64i>
}
}
More information about the cfe-commits
mailing list