From 03ac434cce6980004bd662480e72db5d4e24d9f6 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Wed, 1 Oct 2025 17:52:53 -0700 Subject: [PATCH 1/4] [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 -> !cir.ptr + %1 = cir.dyn_cast ptr relative_layout %p : !cir.ptr + -> !cir.ptr + %2 = cir.dyn_cast ref %r : !cir.ptr -> !cir.ptr + #cir.dyn_cast_info< + #cir.global_view<@_ZTI4Base> : !cir.ptr, + #cir.global_view<@_ZTI7Derived> : !cir.ptr, + @__dynamic_cast, + @__cxa_bad_cast, + #cir.int<0> : !s64i + > + ``` + }]; + + let arguments = (ins + CIR_DynamicCastKind:$kind, + CIR_PtrToRecordType:$src, + OptionalAttr:$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; def CIR_PtrToComplexType : CIR_PtrToType; +def CIR_PtrToRecordType : CIR_PtrToType; + def CIR_PtrToArray : CIR_PtrToType; //===----------------------------------------------------------------------===// 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__` + + 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 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. + + auto ptrTy = mlir::dyn_cast(ty); + if (!ptrTy) + return false; + + auto pointeeIntTy = mlir::dyn_cast(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(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 +!u8i = !cir.int +!void = !cir.void + +!rec_Base = !cir.record +!rec_Derived = !cir.record + +#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__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, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> + +module { + cir.global "private" constant external @_ZTI4Base : !cir.ptr + cir.global "private" constant external @_ZTI7Derived : !cir.ptr + cir.func private @__dynamic_cast(!cir.ptr, !cir.ptr, !cir.ptr, !s64i) -> !cir.ptr + cir.func private @__cxa_bad_cast() + + cir.func @test_ptr_cast(%arg0: !cir.ptr) -> !cir.ptr { + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #dyn_cast_info__ZTI4Base__ZTI7Derived + cir.return %0 : !cir.ptr + } + + // CHECK: cir.func @test_ptr_cast(%arg0: !cir.ptr) -> !cir.ptr { + // CHECK: %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #dyn_cast_info__ZTI4Base__ZTI7Derived + // CHECK: cir.return %0 : !cir.ptr + // CHECK: } + + cir.func @test_ref_cast(%arg0: !cir.ptr) -> !cir.ptr { + %0 = cir.dyn_cast ref %arg0 : !cir.ptr -> !cir.ptr #dyn_cast_info__ZTI4Base__ZTI7Derived + cir.return %0 : !cir.ptr + } + + // CHECK: cir.func @test_ref_cast(%arg0: !cir.ptr) -> !cir.ptr { + // CHECK: %0 = cir.dyn_cast ref %arg0 : !cir.ptr -> !cir.ptr #dyn_cast_info__ZTI4Base__ZTI7Derived + // CHECK: cir.return %0 : !cir.ptr + // CHECK: } + + cir.func dso_local @test_cast_to_void(%arg0: !cir.ptr) -> !cir.ptr { + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr + cir.return %0 : !cir.ptr + } + + // CHECK: cir.func dso_local @test_cast_to_void(%arg0: !cir.ptr) -> !cir.ptr { + // CHECK: %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr + // CHECK: cir.return %0 : !cir.ptr + // CHECK: } + + cir.func dso_local @test_relative_layout_cast(%arg0: !cir.ptr) -> !cir.ptr { + %0 = cir.dyn_cast ptr relative_layout %arg0 : !cir.ptr -> !cir.ptr + cir.return %0 : !cir.ptr + } + + // CHECK: cir.func dso_local @test_relative_layout_cast(%arg0: !cir.ptr) -> !cir.ptr { + // CHECK: %0 = cir.dyn_cast ptr relative_layout %arg0 : !cir.ptr -> !cir.ptr + // CHECK: cir.return %0 : !cir.ptr + // 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 +!s8i = !cir.int +!u32i = !cir.int +!u8i = !cir.int +!void = !cir.void + +!Base = !cir.record !cir.int>>>}> +!Derived = !cir.record !cir.int>>>}>}> + +module { + cir.global "private" constant external @_ZTI4Base : !cir.ptr + cir.global "private" constant external @_ZTI7Derived : !cir.ptr + cir.func private @__dynamic_cast(!cir.ptr, !cir.ptr, !cir.ptr, !s64i) -> !cir.ptr + cir.func private @__cxa_bad_cast() + cir.func @test(%arg0 : !cir.ptr) { + // expected-error@+1 {{srcRtti must be an RTTI pointer}} + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> + } +} + +// ----- + +!s64i = !cir.int +!s8i = !cir.int +!u32i = !cir.int +!u8i = !cir.int +!void = !cir.void + +!Base = !cir.record !cir.int>>>}> +!Derived = !cir.record !cir.int>>>}>}> + +module { + cir.global "private" constant external @_ZTI4Base : !cir.ptr + cir.global "private" constant external @_ZTI7Derived : !cir.ptr + cir.func private @__dynamic_cast(!cir.ptr, !cir.ptr, !cir.ptr, !s64i) -> !cir.ptr + cir.func private @__cxa_bad_cast() + cir.func @test(%arg0 : !cir.ptr) { + // expected-error@+1 {{destRtti must be an RTTI pointer}} + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> + } +} From d849dc26f92a1028ac728f2a1af873ab6c11438c Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Fri, 3 Oct 2025 10:41:11 -0700 Subject: [PATCH 2/4] 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 %2 = cir.dyn_cast ref %r : !cir.ptr -> !cir.ptr #cir.dyn_cast_info< - #cir.global_view<@_ZTI4Base> : !cir.ptr, - #cir.global_view<@_ZTI7Derived> : !cir.ptr, - @__dynamic_cast, - @__cxa_bad_cast, - #cir.int<0> : !s64i + srcRtti = #cir.global_view<@_ZTI4Base> : !cir.ptr, + destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, + 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 !rec_Derived = !cir.record -#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> +#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, 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, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> +// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> module { cir.global "private" constant external @_ZTI4Base : !cir.ptr 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) { // expected-error@+1 {{srcRtti must be an RTTI pointer}} - %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, 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) { // expected-error@+1 {{destRtti must be an RTTI pointer}} - %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> } } From 5bc63da62ba59eedada8fbf51d40da1c532b4210 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 6 Oct 2025 13:32:46 -0700 Subject: [PATCH 3/4] 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 !rec_Derived = !cir.record -#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> +#dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info : !cir.ptr, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, 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 : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> +// CHECK: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info : !cir.ptr, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, 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 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) { // expected-error@+1 {{srcRtti must be an RTTI pointer}} - %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, 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) { // expected-error@+1 {{destRtti must be an RTTI pointer}} - %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, destRtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtimeFunc = @__dynamic_cast, badCastFunc = @__cxa_bad_cast, offsetHint = #cir.int<0> : !s64i> + %0 = cir.dyn_cast ptr %arg0 : !cir.ptr -> !cir.ptr #cir.dyn_cast_info : !cir.ptr, dest_rtti = #cir.global_view<@_ZTI7Derived> : !cir.ptr, runtime_func = @__dynamic_cast, bad_cast_func = @__cxa_bad_cast, offset_hint = #cir.int<0> : !s64i> } } From 7791a0476bda24cd695041b4f924516afc695c34 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 6 Oct 2025 13:50:48 -0700 Subject: [PATCH 4/4] Reformat builder to fit 80 columns --- clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 38dcf428b62de..43832b7c88063 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -630,11 +630,12 @@ def CIR_DynamicCastInfoAttr : CIR_Attr<"DynamicCastInfo", "dyn_cast_info"> { ); let builders = [ - AttrBuilderWithInferredContext<(ins "GlobalViewAttr":$src_rtti, - "GlobalViewAttr":$dest_rtti, - "mlir::FlatSymbolRefAttr":$runtime_func, - "mlir::FlatSymbolRefAttr":$bad_cast_func, - "IntAttr":$offset_hint), [{ + 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); }]>,