llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Henrich Lauko (xlauko) <details> <summary>Changes</summary> FuncType::verify required every type reachable from a signature to be a CIR type, and proved it with a deep walk on every !cir.func construction. #<!-- -->232863 memoized the walk in the dialect behind a mutex, but a record that is still incomplete cannot be cached, and during CIRGen most of them are. The walk was needed because !cir.ptr, !cir.array, !cir.data_member, !cir.bitfield and the record types took unconstrained mlir::Type parameters. Constrain them to CIR types instead. Each type then checks only its own parameters, a CIR type holds only CIR types at any depth, and FuncType::verify checks only its inputs and result. The walk, the cache and the mutex go away. - Pointee, array element and data member types use a new CIR_DialectType constraint. - Bit-field storage, record members and union padding are checked in their verifiers. - StructType and UnionType declared `using Base::verifyInvariants` so that sub-element replacement could rebuild an anonymous record from its storage key. That also exposed MLIR's no-op default verifier, which get() picked over the record verifiers. An overload that verifies the key replaces it, so get() and replacement now both verify records. - Record completion goes through mutate(), which skips the verifier, so complete() now asserts what get() verifies. As elsewhere in MLIR, get() checks this only in builds with assertions. The parser builds these types with getChecked(), so it rejects bad textual IR in every build. On clang/lib/Sema/SemaExpr.cpp in an assertions build, -emit-cir goes from 56.4s to 30.7s and CXXABILowering from 4.9s to 1.3s, compared with the memoized walk. The emitted CIR is unchanged. Assisted-by: Claude Code (Claude Opus 5.5) --- Patch is 27.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/233846.diff 13 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+9-9) - (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.h (-2) - (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (-8) - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+21-21) - (modified) clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td (+13) - (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+22-6) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+1-28) - (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+36-14) - (modified) clang/test/CIR/IR/cast.cir (+2-2) - (modified) clang/test/CIR/IR/invalid-func.cir (-34) - (added) clang/test/CIR/IR/invalid-nested-types.cir (+55) - (modified) clang/unittests/CIR/CMakeLists.txt (+1) - (added) clang/unittests/CIR/RecordTypeVerifyTest.cpp (+111) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index b3cc021989fde4..40c0324c961897 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -537,9 +537,9 @@ def CIR_ConstRecordAttr : CIR_ValueLikeAttr<"ConstRecord", "const_record"> { Example: ``` - cir.global external @rgb2 = #cir.const_record<{0 : i8, - 5 : i64, #cir.null : !cir.ptr<i8> - }> : !cir.record<"", i8, i64, !cir.ptr<i8>> + cir.global external @rgb2 = #cir.const_record<{#cir.int<0> : !s8i, + #cir.int<5> : !s64i, #cir.ptr<null> : !cir.ptr<!s8i> + }> : !cir.struct<{data !s8i, data !s64i, data !cir.ptr<!s8i>}> ``` }]; @@ -1149,13 +1149,13 @@ def CIR_GlobalViewAttr : CIR_ValueLikeAttr<"GlobalView", "global_view"> { Example: ``` - cir.global external @s = @".str2": !cir.ptr<i8> - cir.global external @x = #cir.global_view<@s> : !cir.ptr<i8> + cir.global external @s = @".str2": !cir.ptr<!s8i> + cir.global external @x = #cir.global_view<@s> : !cir.ptr<!s8i> cir.global external @s_addr = #cir.global_view<@s> : !s64i - cir.global external @rgb = #cir.const_array<[0 : i8, -23 : i8, 33 : i8] - : !cir.array<i8 x 3>> - cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<i8> + cir.global external @rgb = #cir.const_array<[#cir.int<0> : !s8i, + #cir.int<-23> : !s8i, #cir.int<33> : !s8i]> : !cir.array<!s8i x 3> + cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<!s8i> ``` Note, that unlike LLVM IR's gep instruction, CIR doesn't add the leading @@ -2062,7 +2062,7 @@ def CIR_TypeInfoAttr : CIR_ValueLikeAttr<"TypeInfo", "typeinfo"> { ``` cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE - : !cir.ptr<i32> + : !cir.ptr<!s32i> !rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}> diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h index f28f2bf34422d0..d9018e93628b69 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h @@ -34,8 +34,6 @@ #include "clang/CIR/Interfaces/CIROpInterfaces.h" #include "clang/CIR/MissingFeatures.h" -#include <mutex> - using BuilderCallbackRef = llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>; using BuilderOpStateCallbackRef = llvm::function_ref<void( diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index 5bd26c6fa9b70d..cd6601c213ba96 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -147,14 +147,6 @@ def CIR_Dialect : Dialect { mlir::Type parseType(mlir::DialectAsmParser &parser) const override; void printType(mlir::Type type, mlir::DialectAsmPrinter &printer) const override; - - /// Returns true if \p ty and every type nested in it are CIR types. - /// Memoized, since FuncType verification re-queries the same records. - bool isPureCIRType(mlir::Type ty) const; - - private: - mutable llvm::DenseMap<mlir::Type, bool> pureCIRTypeCache; - mutable std::mutex pureCIRTypeCacheMutex; }]; } diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 6039e1f49a3ee7..08e711932ef47a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -335,7 +335,7 @@ def CIR_CastOp : CIR_Op<"cast", !listconcat([ %4 = cir.cast int_to_bool %3 : i32 -> !cir.bool ... %x = cir.cast array_to_ptrdecay %0 - : !cir.ptr<!cir.array<i32 x 10>> -> !cir.ptr<i32> + : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i> %y = cir.cast floating %f : !cir.double -> !cir.float fenv<> ``` }]; @@ -539,8 +539,8 @@ def CIR_PtrStrideOp : CIR_Op<"ptr_stride", [ It moves the pointer by `stride * sizeof(element_type)` bytes. ``` - %3 = cir.const 0 : i32 - %3 = cir.ptr_stride %1, %2 : (!cir.ptr<i32>, i32) -> !cir.ptr<i32> + %2 = cir.const #cir.int<1> : !s32i + %3 = cir.ptr_stride %1, %2 : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> ``` }]; @@ -774,10 +774,10 @@ def CIR_AllocaOp : CIR_Op<"alloca", [ ``` // int count; - %0 = cir.alloca "count" align(4) : !cir.ptr<i32> + %0 = cir.alloca "count" align(4) : !cir.ptr<!s32i> // int *ptr; - %1 = cir.alloca "ptr" align(8) : !cir.ptr<!cir.ptr<i32>> + %1 = cir.alloca "ptr" align(8) : !cir.ptr<!cir.ptr<!s32i>> ... ``` }]; @@ -862,20 +862,20 @@ def CIR_LoadOp : CIR_Op<"load", [ ``` // Read from local variable, address in %0. - %1 = cir.load %0 : !cir.ptr<i32>, i32 + %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i // Load address from memory at address %0. %3 is used by at least one // operation that dereferences a pointer. - %3 = cir.load deref %0 : !cir.ptr<!cir.ptr<i32>> + %3 = cir.load deref %0 : !cir.ptr<!cir.ptr<!s32i>> // Perform a volatile load from address in %0. - %4 = cir.load volatile %0 : !cir.ptr<i32>, i32 + %4 = cir.load volatile %0 : !cir.ptr<!s32i>, !s32i // Perform an invariant load from address in %0. - %5 = cir.load invariant %0 : !cir.ptr<i32>, i32 + %5 = cir.load invariant %0 : !cir.ptr<!s32i>, !s32i // Others - %x = cir.load align(16) atomic(seq_cst) %0 : !cir.ptr<i32>, i32 + %x = cir.load align(16) atomic(seq_cst) %0 : !cir.ptr<!s32i>, !s32i ``` }]; @@ -942,7 +942,7 @@ def CIR_VecMaskedLoadOp : CIR_Op<"vec.masked_load", [ ``` %v = cir.masked_load align(16) %ptr, %mask, %passthru - : !cir.ptr<i32>, <4xi1>, <4xi32> -> <4xi32> + : !cir.ptr<!s32i>, <4xi1>, <4xi32> -> <4xi32> ``` }]; @@ -987,13 +987,13 @@ def CIR_StoreOp : CIR_Op<"store", [ ``` // Store a function argument to local storage, address in %0. - cir.store %arg0, %0 : i32, !cir.ptr<i32> + cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i> // Perform a volatile store into memory location at the address in %0. - cir.store volatile %arg0, %0 : i32, !cir.ptr<i32> + cir.store volatile %arg0, %0 : !s32i, !cir.ptr<!s32i> // Others - cir.store align(16) atomic(seq_cst) %x, %addr : i32, !cir.ptr<i32> + cir.store align(16) atomic(seq_cst) %x, %addr : !s32i, !cir.ptr<!s32i> ``` }]; @@ -3618,11 +3618,11 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [ Example: ``` - %x = cir.get_global @gv : !cir.ptr<i32> + %x = cir.get_global @gv : !cir.ptr<!s32i> ... - %y = cir.get_global thread_local @tls_gv : !cir.ptr<i32> + %y = cir.get_global thread_local @tls_gv : !cir.ptr<!s32i> ... - %w = cir.get_global static_local @func_static : !cir.ptr<i32> + %w = cir.get_global static_local @func_static : !cir.ptr<!s32i> ``` }]; @@ -4368,7 +4368,7 @@ def CIR_FuncOp : CIR_Op<"func", [ cir.func no_inline @some_method(...) // Builtin function - cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool + cir.func builtin @__builtin_coro_end(!cir.ptr<!s8i>, !cir.bool) -> !cir.bool // Coroutine cir.func coroutine @_Z10silly_taskv() -> !CoroTask { ... @@ -8078,9 +8078,9 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> { Example: ``` - %size = cir.objsize min %ptr : !cir.ptr<i32> -> i64 - %dsize = cir.objsize max dynamic %ptr : !cir.ptr<i32> -> i64 - %nsize = cir.objsize min nullunknown %ptr : !cir.ptr<i32> -> i64 + %size = cir.objsize min %ptr : !cir.ptr<!s32i> -> !u64i + %dsize = cir.objsize max dynamic %ptr : !cir.ptr<!s32i> -> !u64i + %nsize = cir.objsize min nullunknown %ptr : !cir.ptr<!s32i> -> !u64i ``` }]; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 97d7b30236b822..a2dc8fde405346 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -43,6 +43,19 @@ class CIR_TypeSummaries<list<Type> types> { string value = !if(!eq(!size(types), 1), joined, "any of " # joined); } +//===----------------------------------------------------------------------===// +// Dialect predicates +//===----------------------------------------------------------------------===// + +// Constrains the types nested in a CIR type. Every CIR type admits only CIR +// types as parameters, so a CIR type holds no foreign type at any depth. +def CIR_DialectType + : Type<CPred<"$_self && " # + "::mlir::isa<::cir::CIRDialect>($_self.getDialect())">, + "any type from the CIR dialect"> { + let cppFunctionName = "isCIRType"; +} + //===----------------------------------------------------------------------===// // Bool Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 366a4669c3a56f..ea331ee8df90e8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -263,7 +263,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [ space attribute that specifies the address space of the pointer. If not specified, the pointer is assumed to be in the default address space. - The `!cir.ptr` type can point to any type, including fundamental types, + The `!cir.ptr` type can point to any CIR type, including fundamental types, records, arrays, vectors, functions, and other pointers. It can also point to incomplete types, such as incomplete records. @@ -279,7 +279,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [ }]; let parameters = (ins - "mlir::Type":$pointee, + CIR_DialectType:$pointee, OptionalParameter< "mlir::ptr::MemorySpaceAttrInterface">:$addrSpace ); @@ -355,7 +355,7 @@ def CIR_DataMemberType : CIR_Type<"DataMember", "data_member", [ containing record. }]; - let parameters = (ins "mlir::Type":$member_ty, + let parameters = (ins CIR_DialectType:$member_ty, "cir::RecordType":$class_ty); let builders = [ @@ -456,7 +456,7 @@ def CIR_ArrayType : CIR_Type<"Array", "array", [ `!cir.array` represents C/C++ constant arrays. }]; - let parameters = (ins "mlir::Type":$elementType, "uint64_t":$size); + let parameters = (ins CIR_DialectType:$elementType, "uint64_t":$size); let builders = [ TypeBuilderWithInferredContext<(ins @@ -973,7 +973,15 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ ]; let extraClassDeclaration = [{ - using Base::verifyInvariants; + /// Verifies a storage key, as sub-element replacement rebuilds from one. + /// It is a template because the storage class is incomplete here. + template <typename StorageKey> + static llvm::LogicalResult + verifyInvariants(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, + const StorageKey &key) { + return verifyInvariants(emitError, key.members, key.name, key.incomplete, + key.packed, key.member_kinds, key.is_class); + } bool isClass() const { return getIsClass(); } bool isStruct() const { return !getIsClass(); } @@ -1132,7 +1140,15 @@ def CIR_UnionType : CIR_Type<"Union", "union", [ ]; let extraClassDeclaration = [{ - using Base::verifyInvariants; + /// Verifies a storage key, as sub-element replacement rebuilds from one. + /// It is a template because the storage class is incomplete here. + template <typename StorageKey> + static llvm::LogicalResult + verifyInvariants(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, + const StorageKey &key) { + return verifyInvariants(emitError, key.members, key.name, key.incomplete, + key.packed, key.padding, key.member_kinds); + } bool isUnion() const { return true; } bool isComplete() const { return !isIncomplete(); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 4dfbfbb195ca46..c27cbc78a28cc0 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -253,33 +253,6 @@ static LogicalResult verifyOffloadContainer(mlir::Operation *op) { return success(); } -bool cir::CIRDialect::isPureCIRType(mlir::Type ty) const { - assert(ty && "isPureCIRType requires a non-null type"); - { - std::lock_guard<std::mutex> lock(pureCIRTypeCacheMutex); - auto it = pureCIRTypeCache.find(ty); - if (it != pureCIRTypeCache.end()) - return it->second; - } - // Records gain members when completed, so a "pure" answer is only stable - // when the walk saw no incomplete record. "Impure" answers stay stable. - bool sawIncompleteRecord = false; - bool result = !ty.walk([&](mlir::Type t) { - if (!t) - return mlir::WalkResult::advance(); - if (auto rec = mlir::dyn_cast<cir::RecordType>(t)) - sawIncompleteRecord |= rec.isIncomplete(); - return mlir::isa<cir::CIRDialect>(t.getDialect()) - ? mlir::WalkResult::advance() - : mlir::WalkResult::interrupt(); - }).wasInterrupted(); - if (!result || !sawIncompleteRecord) { - std::lock_guard<std::mutex> lock(pureCIRTypeCacheMutex); - pureCIRTypeCache[ty] = result; - } - return result; -} - LogicalResult cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op, mlir::NamedAttribute attr) { @@ -2678,7 +2651,7 @@ static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser, } else { // Parse constant with initializer, examples: // cir.global @y = 3.400000e+00 : f32 - // cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>> + // cir.global @rgb = #cir.const_array<[...] : !cir.array<!s8i x 3>> if (parseConstantValue(parser, initialValueAttr).failed()) return failure(); diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index c6296180cfb025..59c16887dafa7f 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -61,13 +61,6 @@ cir::FPTypeInterface cir::getFloatingPointType(const llvm::fltSemantics &sem, } } -static bool isPureCIRType(mlir::Type ty) { - if (!ty) - return true; - return ty.getContext()->getOrLoadDialect<cir::CIRDialect>()->isPureCIRType( - ty); -} - //===----------------------------------------------------------------------===// // CIR Custom Parser/Printer Signatures //===----------------------------------------------------------------------===// @@ -171,6 +164,16 @@ verifyRecordMemberKinds(function_ref<mlir::InFlightDiagnostic()> emitError, return mlir::success(); } +static mlir::LogicalResult +verifyRecordMemberTypes(function_ref<mlir::InFlightDiagnostic()> emitError, + llvm::ArrayRef<mlir::Type> members) { + for (auto [idx, memberTy] : llvm::enumerate(members)) + if (!cir::isCIRType(memberTy)) + return emitError() << "record member at index " << idx + << " must be a CIR type, got " << memberTy; + return mlir::success(); +} + /// The keywords that spell a member kind. A union's tail-padding slot probes /// for one of these to reject it, since that slot is not a member. static const llvm::StringRef memberKindMarks[] = {"data", "pad", "empty", @@ -345,6 +348,8 @@ mlir::LogicalResult StructType::verify( bool packed, llvm::ArrayRef<RecordMemberKind> member_kinds, bool is_class) { if (name && name.getValue().empty()) return emitError() << "identified records cannot have an empty name"; + if (failed(verifyRecordMemberTypes(emitError, members))) + return mlir::failure(); return verifyRecordMemberKinds(emitError, members.size(), member_kinds); } @@ -387,6 +392,12 @@ void StructType::removeABIConversionNamePrefix() { void StructType::complete(ArrayRef<Type> members, bool packed, ArrayRef<RecordMemberKind> memberKinds) { assert(!cir::MissingFeatures::astRecordDeclAttr()); + // mutate() bypasses the verifier, so check what get() would have checked. + assert( + succeeded(verifyInvariants( + mlir::detail::getDefaultDiagnosticEmitFn(getContext()), members, + getName(), /*incomplete=*/false, packed, memberKinds, isClass())) && + "invalid struct completion"); if (mutate(members, packed, memberKinds).failed()) llvm_unreachable("failed to complete struct"); } @@ -516,6 +527,10 @@ UnionType::verify(function_ref<mlir::InFlightDiagnostic()> emitError, // padding slot. if (llvm::is_contained(member_kinds, RecordMemberKind::Pad)) return emitError() << "a union member cannot be marked pad"; + if (failed(verifyRecordMemberTypes(emitError, members))) + return mlir::failure(); + if (padding && !cir::isCIRType(padding)) + return emitError() << "union padding must be a CIR type, got " << padding; // Every variant starts at offset zero, so a bit-field variant is an access // unit of its own. There is no run for a zero-width bit-field to end, so a // variant always has storage. @@ -563,6 +578,11 @@ void UnionType::complete(ArrayRef<Type> members, bool packed, mlir::Type padding, ArrayRef<RecordMemberKind> memberKinds) { assert(!cir::MissingFeatures::astRecordDeclAttr()); + // mutate() bypasses the verifier, so check what get() would have checked. + assert(succeeded(verifyInvariants( + mlir::detail::getDefaultDiagnosticEmitFn(getContext()), members, + getName(), /*incomplete=*/false, packed, padding, memberKinds)) && + "invalid union completion"); if (mutate(members, packed, padding, memberKinds).failed()) llvm_unreachable("failed to complete union"); } @@ -1303,13 +1323,10 @@ FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, << "!cir.func cannot have an explicit 'void' return type"; // The calling convention lowering pass expects all types in a function - // signature to be CIR types. - for (mlir::Type type : argTypes) { - if (!isPureCIRType(type)) - return emitError() - << "expected all types in the function signature to be CIR types"; - } - if (!isPureCIRType(returnType)) + // signature to be CIR types. CIR types only nest CIR types, so checking the + // signature's own types covers everything reachable from them. + if (!llvm::all_of(argTypes, cir::isCIRType) || + (returnType && !cir::isCIRType(returnType))) return emitError() << "expected all types in the function signature to be CIR types"; @@ -1446,6 +1463,11 @@ BitFieldType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, return mlir::success(); } + if (!cir::isCIRType(storageType)) + return emitError() << "bit-field access unit storage must be a CIR type, " + "got " + << storageType; + if (mlir::isa<cir::BitFieldType>(storageType)) return emitError() << "bit-field access unit storage cannot itself be a " "bit-field type"; diff --git a/clang/test/CIR/IR/cast.cir b/clang/test/CIR/IR/cast.cir index 3f2fca9fc307b7..7189031b583e25 100644 --- a/clang/test/CIR/IR/cast.cir +++ b/clang/test/CIR/IR/cast.cir @@ -10,7 +10,7 @@ module { } cir.func @bitcast(%p: !cir.ptr<!s32i>) { - %0 = cir.cast bitcast %p : !cir.ptr<!s32i> -> !cir.ptr<f32> + %0 = cir.cast bitcast %p : !cir.ptr<!s32i> -> !cir.ptr<!cir.float> cir.return } } @@ -20,4 +20,4 @@ module { // CHECK: %1 = cir.const #cir.int<0> : !s32i // CHECK: cir.func{{.*}} @bitcast -// CHECK: %0 = cir.cast bitcast %arg0 : !cir.ptr<!s32i>... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/233846 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
