Author: Adam Smith Date: 2026-08-17T11:24:17-05:00 New Revision: 5f81b8d924fba12b4e851352959b5c4a54260d9a
URL: https://github.com/llvm/llvm-project/commit/5f81b8d924fba12b4e851352959b5c4a54260d9a DIFF: https://github.com/llvm/llvm-project/commit/5f81b8d924fba12b4e851352959b5c4a54260d9a.diff LOG: [CIR] Derive record padding from the member marks (#215176)r Now that every record member carries a kind, the record-level `padded` bool is redundant: a record is padded exactly when some member is marked pad. Drop the parameter and answer `getPadded()` from the marks. That also fixes `computeStructDataSize`, which had read the bool as "the last member is tail padding" and so dropped a real member when padding sat between two data members. It now drops the trailing run, so an all-pad record sizes to zero. Assisted-by: Cursor / claude-opus-5 Added: clang/test/CIR/Lowering/copy-skip-tail-padding.cir Modified: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td clang/include/clang/CIR/Dialect/IR/CIROps.td clang/include/clang/CIR/Dialect/IR/CIRTypes.h clang/include/clang/CIR/Dialect/IR/CIRTypes.td clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h clang/lib/CIR/CodeGen/CIRGenAsm.cpp clang/lib/CIR/CodeGen/CIRGenBuilder.cpp clang/lib/CIR/CodeGen/CIRGenBuilder.h clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp clang/lib/CIR/CodeGen/CIRGenBuiltinNVPTX.cpp clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenRecordLayout.h clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp clang/lib/CIR/CodeGen/CIRGenTypes.cpp clang/lib/CIR/CodeGen/CIRGenVTables.cpp clang/lib/CIR/Dialect/IR/CIRTypes.cpp clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp clang/test/CIR/CodeGen/atomic.c clang/test/CIR/CodeGen/bitfields.c clang/test/CIR/CodeGen/cleanup.cpp clang/test/CIR/CodeGen/dumb-record.cpp clang/test/CIR/CodeGen/empty-union.cpp clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp clang/test/CIR/CodeGen/member-functions.cpp clang/test/CIR/CodeGen/no-unique-address.cpp clang/test/CIR/CodeGen/paren-list-agg-init.cpp clang/test/CIR/CodeGen/pointer-to-empty-data-member.cpp clang/test/CIR/CodeGen/record-member-kinds.c clang/test/CIR/CodeGen/record-member-kinds.cpp clang/test/CIR/CodeGen/record-type-metadata.cpp clang/test/CIR/CodeGen/struct.c clang/test/CIR/CodeGen/template-specialization.cpp clang/test/CIR/CodeGen/vtt.cpp clang/test/CIR/CodeGenCXX/zero_init_bases.cpp clang/test/CIR/CodeGenCoroutines/coro-task.cpp clang/test/CIR/IR/array-ctor.cir clang/test/CIR/IR/array-dtor.cir clang/test/CIR/IR/construct-catch-param.cir clang/test/CIR/IR/func-attrs.cir clang/test/CIR/IR/global-init.cir clang/test/CIR/IR/invalid-array-structor.cir clang/test/CIR/IR/invalid-construct-catch-param.cir clang/test/CIR/IR/invalid-delete-array.cir clang/test/CIR/IR/invalid-loop-cleanup.cir clang/test/CIR/IR/loop-cleanup.cir clang/test/CIR/IR/struct.cir clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir clang/test/CIR/Transforms/flatten-cleanup-scope-eh.cir clang/test/CIR/Transforms/flatten-loop-cleanup.cir clang/test/CIR/Transforms/mem2reg.cir clang/unittests/CIR/PointerLikeTest.cpp clang/unittests/CIR/RecordMemberKindTest.cpp clang/unittests/CIR/RecordTypeMetadataTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 29e82b9392b82..0871d48506cf8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1563,8 +1563,8 @@ def CIR_BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { The CIR representation of the struct `S` might look like: ``` - !rec_S = !cir.record<struct "S" packed padded {!u64i, !u16i, - !cir.array<!u8i x 2>}> + !rec_S = !cir.struct<"S" packed {!u64i, !u16i, + pad !cir.array<!u8i x 2>}> ``` And the bitfield info attribute for member `a` would be: ``` diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 8f8159a356b5a..ccf0a21d56e04 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3761,8 +3761,8 @@ def CIR_SetBitfieldOp : CIR_Op<"set_bitfield"> { ``` // 'e' is in the storage with the index 1 - !record_type = !cir.record<struct "S" packed padded {!u64i, !u16i, - !cir.array<!u8i x 2>} #cir.record.decl.ast> + !record_type = !cir.struct<"S" packed {!u64i, !u16i, + pad !cir.array<!u8i x 2>}> #bfi_e = #cir.bitfield_info<name = "e", storage_type = !u16i, size = 15, offset = 0, is_signed = true> @@ -3852,7 +3852,8 @@ def CIR_GetBitfieldOp : CIR_Op<"get_bitfield"> { ``` // 'e' is in the storage with the index 1 - !cir.record<struct "S" packed padded {!u64i, !u16i, !cir.array<!u8i x 2>}> + !cir.struct<"S" packed {!u64i, !u16i, + pad !cir.array<!u8i x 2>}> #bfi_e = #cir.bitfield_info<name = "e", storage_type = !u16i, size = 15, offset = 0, is_signed = true> diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index c3a513dbbda66..9b5b3957f6453 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -144,7 +144,9 @@ class RecordType : public mlir::Type { std::string getKindAsStr() const; std::string getPrefixedName() const; - void complete(llvm::ArrayRef<mlir::Type> members, bool packed, bool padded, + /// \p padding is union-only. A struct carries its padding as a member + /// marked pad. + void complete(llvm::ArrayRef<mlir::Type> members, bool packed, mlir::Type padding, llvm::ArrayRef<RecordMemberKind> memberKinds); uint64_t getElementOffset(const mlir::DataLayout &dataLayout, diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 975d2a4304c42..2d8d7abe9b404 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -698,7 +698,6 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ !rec_incomplete = !cir.struct<"incomplete" incomplete> !anonymous = !cir.struct<{data !u8i}> !rec_packed = !cir.struct<"p1" packed {data !u8i, data !u8i}> - !rec_padded = !cir.struct<"p2" padded {data !u8i, data !u8i}> !rec_pad = !cir.struct<"p3" {data !u8i, pad !cir.array<!u8i x 3>}> !rec_empty = !cir.struct<"e" {empty !u8i}> !recursive = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">>}> @@ -710,7 +709,6 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ OptionalParameter<"mlir::StringAttr">:$name, "bool":$incomplete, "bool":$packed, - "bool":$padded, ArrayRefParameter<"cir::RecordMemberKind">:$member_kinds, "bool":$is_class ); @@ -728,11 +726,10 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ "llvm::ArrayRef<mlir::Type>":$members, "mlir::StringAttr":$name, "bool":$packed, - "bool":$padded, "bool":$is_class, "llvm::ArrayRef<cir::RecordMemberKind>":$member_kinds ), [{ - return $_get($_ctxt, members, name, /*incomplete=*/false, packed, padded, + return $_get($_ctxt, members, name, /*incomplete=*/false, packed, member_kinds, is_class); }]>, @@ -742,7 +739,7 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ "bool":$is_class ), [{ return $_get($_ctxt, /*members=*/llvm::ArrayRef<mlir::Type>{}, name, - /*incomplete=*/true, /*packed=*/false, /*padded=*/false, + /*incomplete=*/true, /*packed=*/false, /*member_kinds=*/llvm::ArrayRef<cir::RecordMemberKind>{}, is_class); }]>, @@ -751,12 +748,11 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ TypeBuilder<(ins "llvm::ArrayRef<mlir::Type>":$members, "bool":$packed, - "bool":$padded, "bool":$is_class, "llvm::ArrayRef<cir::RecordMemberKind>":$member_kinds ), [{ return $_get($_ctxt, members, mlir::StringAttr{}, /*incomplete=*/false, - packed, padded, member_kinds, is_class); + packed, member_kinds, is_class); }]> ]; @@ -780,9 +776,11 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ } void complete(llvm::ArrayRef<mlir::Type> members, bool packed, - bool isPadded, llvm::ArrayRef<cir::RecordMemberKind> memberKinds); + /// Whether any member is marked pad. + bool getPadded() const; + uint64_t getElementOffset(const mlir::DataLayout &dataLayout, unsigned idx) const; @@ -806,7 +804,9 @@ def CIR_StructType : CIR_Type<"Struct", "struct", [ bool isSized() const { return isComplete(); } - /// Returns the data size (excluding tail padding) for this struct type. + /// Returns the data size for this struct type. Tail padding is the + /// trailing run of pad members, so interior padding and a trailing empty + /// member stay inside the data size. unsigned computeStructDataSize(const mlir::DataLayout &dataLayout) const; private: @@ -914,9 +914,7 @@ def CIR_UnionType : CIR_Type<"Union", "union", [ bool isComplete() const { return !isIncomplete(); } bool isIncomplete() const; - /// Returns true when this union carries a tail-padding type. - /// Derived from getPadding(): a union is padded iff it has a non-null - /// padding type. + /// Whether this union carries a tail-padding type. bool getPadded() const; size_t getNumElements() const { return getMembers().size(); } diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h b/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h index 7a451698f4b23..4176fc8900c58 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h @@ -32,68 +32,64 @@ struct StructTypeStorage : public mlir::TypeStorage { mlir::StringAttr name; bool incomplete; bool packed; - bool padded; llvm::ArrayRef<RecordMemberKind> member_kinds; bool is_class; KeyTy(llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, - bool incomplete, bool packed, bool padded, + bool incomplete, bool packed, llvm::ArrayRef<RecordMemberKind> member_kinds, bool is_class) : members(members), name(name), incomplete(incomplete), packed(packed), - padded(padded), member_kinds(member_kinds), is_class(is_class) {} + member_kinds(member_kinds), is_class(is_class) {} }; llvm::ArrayRef<mlir::Type> members; mlir::StringAttr name; bool incomplete; bool packed; - bool padded; llvm::ArrayRef<RecordMemberKind> member_kinds; bool is_class; StructTypeStorage(llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, - bool incomplete, bool packed, bool padded, + bool incomplete, bool packed, llvm::ArrayRef<RecordMemberKind> member_kinds, bool is_class) : members(members), name(name), incomplete(incomplete), packed(packed), - padded(padded), member_kinds(member_kinds), is_class(is_class) { + member_kinds(member_kinds), is_class(is_class) { assert((name || !incomplete) && "Incomplete records must have a name"); assert(member_kinds.size() == members.size() && "every member must say what it holds"); } KeyTy getAsKey() const { - return KeyTy(members, name, incomplete, packed, padded, member_kinds, - is_class); + return KeyTy(members, name, incomplete, packed, member_kinds, is_class); } bool operator==(const KeyTy &key) const { if (name) return (name == key.name) && (is_class == key.is_class); - return std::tie(members, name, incomplete, packed, padded, member_kinds, + return std::tie(members, name, incomplete, packed, member_kinds, is_class) == std::tie(key.members, key.name, key.incomplete, - key.packed, key.padded, - key.member_kinds, key.is_class); + key.packed, key.member_kinds, + key.is_class); } static llvm::hash_code hashKey(const KeyTy &key) { if (key.name) return llvm::hash_combine(key.name, key.is_class); return llvm::hash_combine(key.members, key.incomplete, key.packed, - key.padded, key.member_kinds, key.is_class); + key.member_kinds, key.is_class); } static StructTypeStorage *construct(mlir::TypeStorageAllocator &allocator, const KeyTy &key) { return new (allocator.allocate<StructTypeStorage>()) StructTypeStorage( allocator.copyInto(key.members), key.name, key.incomplete, key.packed, - key.padded, allocator.copyInto(key.member_kinds), key.is_class); + allocator.copyInto(key.member_kinds), key.is_class); } /// Mutates the members and attributes of an identified struct/class. llvm::LogicalResult mutate(mlir::TypeStorageAllocator &allocator, llvm::ArrayRef<mlir::Type> members, bool packed, - bool padded, llvm::ArrayRef<RecordMemberKind> memberKinds) { if (!name) return llvm::failure(); @@ -102,9 +98,9 @@ struct StructTypeStorage : public mlir::TypeStorage { // including the kinds: otherwise it silently keeps the kinds it was given // the first time. if (!incomplete) - return mlir::success( - (this->members == members) && (this->packed == packed) && - (this->padded == padded) && (this->member_kinds == memberKinds)); + return mlir::success((this->members == members) && + (this->packed == packed) && + (this->member_kinds == memberKinds)); // mutate is the one entrance verify() never sees, so check the length here // rather than leave it to an assert. @@ -113,7 +109,6 @@ struct StructTypeStorage : public mlir::TypeStorage { this->members = allocator.copyInto(members); this->packed = packed; - this->padded = padded; this->member_kinds = allocator.copyInto(memberKinds); incomplete = false; return llvm::success(); diff --git a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp index 9ad09ca95f73a..cfc5cb52584ae 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp @@ -539,7 +539,7 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) { else if (resultRegTypes.size() > 1) resultType = builder.getAnonRecordTy( resultRegTypes, /*packed=*/false, - /*padded=*/false, cir::RecordType::getAllDataKinds(resultRegTypes)); + cir::RecordType::getAllDataKinds(resultRegTypes)); bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index f521fd2a6936e..e342625d2b1f3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -195,33 +195,8 @@ uint64_t CIRGenBuilderTy::computeOffsetFromGlobalViewIndices( return offset; } -cir::RecordType clang::CIRGen::CIRGenBuilderTy::getCompleteRecordType( - mlir::ArrayAttr fields, bool packed, bool padded, llvm::StringRef name) { - assert(!cir::MissingFeatures::astRecordDeclAttr()); - llvm::SmallVector<mlir::Type> members; - members.reserve(fields.size()); - llvm::transform(fields, std::back_inserter(members), - [](mlir::Attribute attr) { - return mlir::cast<mlir::TypedAttr>(attr).getType(); - }); - - if (name.empty()) - return getAnonRecordTy(members, packed, padded, - cir::RecordType::getAllDataKinds(members)); - - return getCompleteNamedRecordType(members, packed, padded, name, - cir::RecordType::getAllDataKinds(members)); -} - mlir::Attribute clang::CIRGen::CIRGenBuilderTy::getConstRecordOrZeroAttr( - mlir::ArrayAttr arrayAttr, bool packed, bool padded, mlir::Type type) { - auto recordTy = mlir::cast_or_null<cir::RecordType>(type); - - // Record type not specified: create anon record type from members. - if (!recordTy) { - recordTy = getCompleteRecordType(arrayAttr, packed, padded); - } - + mlir::ArrayAttr arrayAttr, cir::RecordType recordTy) { // Return zero or anonymous constant record. const bool isZero = llvm::all_of( arrayAttr, [&](mlir::Attribute a) { return isNullValue(a); }); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index f8a152c0e4c30..dc4fbf5c64f97 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -79,25 +79,17 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { } mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr, - bool packed = false, - bool padded = false, - mlir::Type type = {}); - - cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr, - bool packed = false, - bool padded = false, - mlir::Type ty = {}) { - llvm::SmallVector<mlir::Type, 4> members; + cir::RecordType recordTy); + + cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr) { + llvm::SmallVector<mlir::Type> members; for (auto &f : arrayAttr) { auto ta = mlir::cast<mlir::TypedAttr>(f); members.push_back(ta.getType()); } - if (!ty) - ty = getAnonRecordTy(members, packed, padded, - cir::RecordType::getAllDataKinds(members)); - - auto sTy = mlir::cast<cir::RecordType>(ty); + auto sTy = getAnonRecordTy(members, /*packed=*/false, + cir::RecordType::getAllDataKinds(members)); return cir::ConstRecordAttr::get(sTy, arrayAttr); } @@ -156,34 +148,27 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { /// If a record already exists and is complete, but the client tries to fetch /// it with a diff erent set of attributes, this method will crash. cir::RecordType getCompleteNamedRecordType( - llvm::ArrayRef<mlir::Type> members, bool packed, bool padded, - llvm::StringRef name, llvm::ArrayRef<cir::RecordMemberKind> memberKinds) { + llvm::ArrayRef<mlir::Type> members, bool packed, llvm::StringRef name, + llvm::ArrayRef<cir::RecordMemberKind> memberKinds) { const auto nameAttr = getStringAttr(name); assert(!cir::MissingFeatures::astRecordDeclAttr()); - // Create or get the struct type (named anonymous struct helper — always - // struct, never class or union at this call site). + // Always a struct at this call site, never a class or a union. auto type = cir::StructType::get(getContext(), members, nameAttr, packed, - padded, /*is_class=*/false, memberKinds); + /*is_class=*/false, memberKinds); // If we found an existing type, verify that either it is incomplete or // it matches the requested attributes. assert(!type.isIncomplete() || - (type.getMembers() == members && type.getPacked() == packed && - type.getPadded() == padded)); + (type.getMembers() == members && type.getPacked() == packed)); // Complete an incomplete record or ensure the existing complete record // matches the requested attributes. - type.complete(members, packed, padded, memberKinds); + type.complete(members, packed, memberKinds); return type; } - cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields, - bool packed = false, - bool padded = false, - llvm::StringRef name = ""); - /// Get an incomplete CIR record type. If we have a complete record /// declaration, we may create an incomplete type and then add the /// members, so \p rd here may be complete. @@ -405,10 +390,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { /// Get a CIR anonymous struct type. cir::StructType - getAnonRecordTy(llvm::ArrayRef<mlir::Type> members, bool packed, bool padded, + getAnonRecordTy(llvm::ArrayRef<mlir::Type> members, bool packed, llvm::ArrayRef<cir::RecordMemberKind> memberKinds) { assert(!cir::MissingFeatures::astRecordDeclAttr()); - return cir::StructType::get(getContext(), members, packed, padded, + return cir::StructType::get(getContext(), members, packed, /*is_class=*/false, memberKinds); } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp index 0c025e40e07ea..ef40039eb6800 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp @@ -78,7 +78,7 @@ static mlir::Value emitLogbBuiltin(CIRGenFunction &cgf, const CallExpr *e, mlir::Type frExpResMembers[] = {srcTy, int32Ty}; cir::RecordType frExpResTy = builder.getAnonRecordTy( - frExpResMembers, /*packed=*/false, /*padded=*/false, + frExpResMembers, /*packed=*/false, cir::RecordType::getAllDataKinds(frExpResMembers)); mlir::Value frExpResult = builder.emitIntrinsicCallOp( @@ -178,7 +178,7 @@ CIRGenFunction::emitAMDGPUBuiltinExpr(unsigned builtinId, auto i1Ty = builder.getUIntNTy(1); mlir::Type resMembers[] = {x.getType(), i1Ty}; cir::RecordType resTy = - builder.getAnonRecordTy(resMembers, /*packed=*/false, /*padded=*/false, + builder.getAnonRecordTy(resMembers, /*packed=*/false, cir::RecordType::getAllDataKinds(resMembers)); mlir::Value structResult = diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinNVPTX.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinNVPTX.cpp index f0ee735e8bc94..2220639876695 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinNVPTX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinNVPTX.cpp @@ -1042,9 +1042,8 @@ static mlir::Value packArgsIntoNVPTXFormatBuffer(CIRGenFunction &cgf, // We can directly store the arguments into a struct, and the alignment // would automatically be correct. That's because vprintf does not // accept aggregates. - mlir::Type allocaTy = - builder.getAnonRecordTy(argTypes, /*packed=*/false, /*padded=*/false, - cir::RecordType::getAllDataKinds(argTypes)); + mlir::Type allocaTy = builder.getAnonRecordTy( + argTypes, /*packed=*/false, cir::RecordType::getAllDataKinds(argTypes)); auto allocaAlign = clang::CharUnits::fromQuantity( dataLayout.getABITypeAlign(allocaTy).value()); Address allocaAddr = diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 18f464b750140..09c60b4d21f7a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -208,10 +208,9 @@ emitEncodeKey(mlir::MLIRContext *context, CIRGenBuilderTy &builder, llvm::SmallVector<mlir::Type> members{builder.getUInt32Ty()}; llvm::append_range(members, llvm::SmallVector<mlir::Type>(vecOutputCount, resVector)); - cir::StructType resRecord = - cir::StructType::get(context, members, /*packed=*/false, - /*padded=*/false, /*is_class=*/false, - cir::RecordType::getAllDataKinds(members)); + cir::StructType resRecord = cir::StructType::get( + context, members, /*packed=*/false, + /*is_class=*/false, cir::RecordType::getAllDataKinds(members)); mlir::Value outputPtr = builder.createBitcast(outputOperand, cir::PointerType::get(resVector)); @@ -696,7 +695,7 @@ static mlir::Value emitX86Aes(CIRGenBuilderTy &builder, mlir::Location loc, mlir::cast<cir::PointerType>(ops[0].getType()).getPointee(); mlir::Type rstMembers[] = {retType, vecType}; cir::RecordType rstRecTy = - builder.getAnonRecordTy(rstMembers, /*packed=*/false, /*padded=*/false, + builder.getAnonRecordTy(rstMembers, /*packed=*/false, cir::RecordType::getAllDataKinds(rstMembers)); mlir::Value rstValueRec = builder.emitIntrinsicCallOp( loc, intrinsicName, rstRecTy, mlir::ValueRange{ops[1], ops[2]}); @@ -754,9 +753,8 @@ static mlir::Value emitX86Aeswide(CIRGenBuilderTy &builder, mlir::Location loc, builder.createAlignedLoad(loc, vecType, nextInElePtr, /*align=*/CharUnits::fromQuantity(16)); } - cir::RecordType rstRecTy = - builder.getAnonRecordTy(recTypes, /*packed=*/false, /*padded=*/false, - cir::RecordType::getAllDataKinds(recTypes)); + cir::RecordType rstRecTy = builder.getAnonRecordTy( + recTypes, /*packed=*/false, cir::RecordType::getAllDataKinds(recTypes)); mlir::Value rstValueRec = builder.emitIntrinsicCallOp(loc, intrinsicName, rstRecTy, arguments); @@ -934,9 +932,8 @@ cir::GetGlobalOp CIRGenFunction::createGetCpuModel(mlir::Location loc) { // unsigned int __cpu_subtype; // unsigned int __cpu_features[1]; mlir::Type tys[] = {u32, u32, u32, cir::ArrayType::get(u32, 1)}; - mlir::Type modelTy = - builder.getAnonRecordTy(tys, /*packed=*/false, /*padded=*/false, - cir::RecordType::getAllDataKinds(tys)); + mlir::Type modelTy = builder.getAnonRecordTy( + tys, /*packed=*/false, cir::RecordType::getAllDataKinds(tys)); cpuModel = cgm.createGlobalOp(loc, "__cpu_model", modelTy, /*isConstant=*/false); cpuModel.setDsoLocal(true); @@ -1142,9 +1139,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { mlir::Type i64Ty = builder.getUInt64Ty(); mlir::Type i32Ty = builder.getUInt32Ty(); mlir::Type members[] = {i64Ty, i32Ty}; - mlir::Type structTy = - builder.getAnonRecordTy(members, /*packed=*/false, /*padded=*/false, - cir::RecordType::getAllDataKinds(members)); + mlir::Type structTy = builder.getAnonRecordTy( + members, /*packed=*/false, cir::RecordType::getAllDataKinds(members)); mlir::Value result = builder.emitIntrinsicCallOp(loc, "x86.rdtscp", structTy); @@ -2504,10 +2500,9 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { mlir::Type randTy = cast<cir::PointerType>(ops[0].getType()).getPointee(); llvm::SmallVector<mlir::Type, 2> resultTypes = {randTy, builder.getUInt32Ty()}; - cir::StructType resRecord = - cir::StructType::get(&getMLIRContext(), resultTypes, /*packed=*/false, - /*padded=*/false, /*is_class=*/false, - cir::RecordType::getAllDataKinds(resultTypes)); + cir::StructType resRecord = cir::StructType::get( + &getMLIRContext(), resultTypes, /*packed=*/false, + /*is_class=*/false, cir::RecordType::getAllDataKinds(resultTypes)); mlir::Value call = builder.emitIntrinsicCallOp(loc, intrinsicName, resRecord); @@ -2576,8 +2571,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { mlir::Type resMembers[] = {resVector, resVector}; cir::StructType resRecord = cir::StructType::get( - &getMLIRContext(), resMembers, /*packed=*/false, /*padded=*/false, - /*is_class=*/false, cir::RecordType::getAllDataKinds(resMembers)); + &getMLIRContext(), resMembers, /*packed=*/false, /*is_class=*/false, + cir::RecordType::getAllDataKinds(resMembers)); mlir::Value call = builder.emitIntrinsicCallOp( getLoc(expr->getExprLoc()), intrinsicName, resRecord, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index 93d4fee235bad..9e3097e2bba27 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -400,8 +400,6 @@ mlir::Attribute buildRecordHelper(ConstantEmitter &emitter, } return builder.getConstRecordOrZeroAttr(builder.getArrayAttr(elements), - /*packed=*/recordTy.getPacked(), - /*padded=*/recordTy.getPadded(), recordTy); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 98f6ab9755501..e3e2b89cad310 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1121,8 +1121,7 @@ static mlir::Attribute getNewInitValue(CIRGenModule &cgm, cir::GlobalOp newGlob, if (auto oldRecord = mlir::dyn_cast<cir::ConstRecordAttr>(oldInit)) { mlir::ArrayAttr newMembers = getNewInitElements(oldRecord.getMembers()); auto recordTy = mlir::cast<cir::RecordType>(oldRecord.getType()); - return cgm.getBuilder().getConstRecordOrZeroAttr( - newMembers, recordTy.getPacked(), recordTy.getPadded(), recordTy); + return cgm.getBuilder().getConstRecordOrZeroAttr(newMembers, recordTy); } // This may be unreachable in practice, but keep it as errorNYI while CIR diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h index 9733d18f52ce8..992dfa95e40cf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h @@ -45,8 +45,8 @@ namespace clang::CIRGen { /// represented by one !u16i value, and the array provides padding to align the /// struct to a 4-byte alignment. /// -/// !rec_S = !cir.record<struct "S" padded {!s8i, !s8i, !s8i, !u16i, -/// !cir.array<!u8i x 3>}> +/// !rec_S = !cir.struct<"S" packed {!s8i, !s8i, !s8i, !u16i, +/// pad !cir.array<!u8i x 3>}> /// /// When generating code to access more_bits, we'll generate something /// essentially like this: diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index 8e3d7b5f254c4..1ce70091d9f4b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -222,7 +222,6 @@ struct CIRRecordLowering final { if (size.isZero()) return; mlir::Type padTy = getByteArrayType(size); - padded = true; if (recordDecl->isUnion()) { assert(!unionPadding && "at most one union tail-padding type"); unionPadding = padTy; @@ -267,8 +266,6 @@ struct CIRRecordLowering final { unsigned zeroInitializableAsBase : 1; LLVM_PREFERRED_TYPE(bool) unsigned packed : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned padded : 1; private: // Output fields, consumed by CIRGenTypes::computeRecordLayout. Private so @@ -290,8 +287,7 @@ CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes, astRecordLayout{ cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)}, dataLayout{cirGenTypes.getCGModule().getModule()}, - zeroInitializable{true}, zeroInitializableAsBase{true}, packed{packed}, - padded{false} {} + zeroInitializable{true}, zeroInitializableAsBase{true}, packed{packed} {} void CIRRecordLowering::setBitFieldInfo(const FieldDecl *fd, CharUnits startOffset, @@ -753,7 +749,6 @@ void CIRRecordLowering::insertPadding() { } if (padding.empty()) return; - padded = true; // Add the padding to the Members list and sort it. for (const std::pair<CharUnits, CharUnits> &paddingPair : padding) members.push_back(makeStorageInfo(paddingPair.first, @@ -814,8 +809,8 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) { baseLowering.lower(/*nonVirtualBaseType=*/true); std::string baseIdentifier = getRecordTypeName(rd, ".base"); baseTy = builder.getCompleteNamedRecordType( - baseLowering.getFieldTypes(), baseLowering.packed, - baseLowering.padded, baseIdentifier, baseLowering.getFieldKinds()); + baseLowering.getFieldTypes(), baseLowering.packed, baseIdentifier, + baseLowering.getFieldKinds()); // TODO(cir): add something like addRecordTypeName // BaseTy and Ty must agree on their packedness for getCIRFieldNo to work @@ -839,8 +834,8 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) { // signifies that the type is no longer opaque and record layout is complete, // but we may need to recursively layout rd while laying D out as a base type. assert(!cir::MissingFeatures::astRecordDeclAttr()); - ty->complete(lowering.getFieldTypes(), lowering.packed, lowering.padded, - lowering.unionPadding, lowering.getFieldKinds()); + ty->complete(lowering.getFieldTypes(), lowering.packed, lowering.unionPadding, + lowering.getFieldKinds()); // The marks exist so that emptiness can be read off the type, so check that // answer against the AST predicate on every record CIRGen lays out. This @@ -1008,10 +1003,8 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) { clearFields(); addField(storageType, storageKind); CharUnits padding = layoutSize - getSize(storageType); - if (!padding.isZero()) { + if (!padding.isZero()) addField(getByteArrayType(padding), cir::RecordMemberKind::Pad); - padded = true; - } } else { // Else we just add padding normally. appendPaddingBytes(layoutSize - getSize(storageType)); diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 346542134470a..f1834d8fc7f37 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -662,9 +662,9 @@ mlir::Type CIRGenTypes::convertType(QualType type) { mlir::Type elements[] = {resultType, paddingArray}; cir::RecordMemberKind kinds[] = {cir::RecordMemberKind::Data, cir::RecordMemberKind::Pad}; - resultType = cir::StructType::get(&getMLIRContext(), /*members=*/elements, - /*packed=*/false, /*padded=*/true, - /*is_class=*/false, kinds); + resultType = + cir::StructType::get(&getMLIRContext(), /*members=*/elements, + /*packed=*/false, /*is_class=*/false, kinds); } break; diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index 1926c2657454b..97f4b5b2c2c48 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -70,8 +70,7 @@ cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) { // FIXME(cir): should VTableLayout be encoded like we do for some // AST nodes? return cgm.getBuilder().getAnonRecordTy( - tys, /*packed=*/false, - /*padded=*/false, cir::RecordType::getAllDataKinds(tys)); + tys, /*packed=*/false, cir::RecordType::getAllDataKinds(tys)); } /// At this point in the translation unit, does it appear that can we diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 997bc29b48ab4..4a26f970b5bc5 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -209,16 +209,15 @@ parseRecordBody(mlir::AsmParser &parser, bool &incomplete, } /// Print a complete CIR record body: -/// '<' ['class '] [name] ['packed '] ['padded '] body '>' -/// where body is "incomplete" or "{[mark] members[, padding = {type}]}". +/// '<' ['class '] [name] ['packed '] body '>' +/// where body is "incomplete" or "{[mark] members}[, padding = {type}]". /// RecordTy must be a mutable MLIR type (StructType or UnionType). template <typename RecordTy> -static void printRecordBody(mlir::AsmPrinter &printer, RecordTy self, - mlir::StringAttr name, bool hasClassPrefix, - bool isPacked, bool isPadded, bool isIncomplete, - llvm::ArrayRef<mlir::Type> members, - mlir::Type padding, - llvm::ArrayRef<RecordMemberKind> memberKinds) { +static void +printRecordBody(mlir::AsmPrinter &printer, RecordTy self, mlir::StringAttr name, + bool hasClassPrefix, bool isPacked, bool isIncomplete, + llvm::ArrayRef<mlir::Type> members, mlir::Type padding, + llvm::ArrayRef<RecordMemberKind> memberKinds) { printer << '<'; if (hasClassPrefix) printer << "class "; @@ -236,8 +235,6 @@ static void printRecordBody(mlir::AsmPrinter &printer, RecordTy self, printer << ' '; if (isPacked) printer << "packed "; - if (isPadded) - printer << "padded "; if (isIncomplete) { printer << "incomplete"; } else { @@ -264,7 +261,6 @@ Type StructType::parse(mlir::AsmParser &parser) { const llvm::SMLoc loc = parser.getCurrentLocation(); const mlir::Location eLoc = parser.getEncodedSourceLoc(loc); bool packed = false; - bool padded = false; mlir::MLIRContext *context = parser.getContext(); if (parser.parseLess()) @@ -299,9 +295,6 @@ Type StructType::parse(mlir::AsmParser &parser) { if (parser.parseOptionalKeyword("packed").succeeded()) packed = true; - if (parser.parseOptionalKeyword("padded").succeeded()) - padded = true; - bool incomplete = true; llvm::SmallVector<mlir::Type> members; llvm::SmallVector<RecordMemberKind> memberKinds; @@ -317,18 +310,18 @@ Type StructType::parse(mlir::AsmParser &parser) { if (name && incomplete) { type = StructType::getChecked(eLoc, context, name, is_class); } else if (!name && !incomplete) { - type = StructType::getChecked(eLoc, context, membersRef, packed, padded, - is_class, kindsRef); + type = StructType::getChecked(eLoc, context, membersRef, packed, is_class, + kindsRef); if (!type) return {}; } else if (!incomplete) { type = StructType::getChecked(eLoc, context, membersRef, name, packed, - padded, is_class, kindsRef); + is_class, kindsRef); if (!type) return {}; if (auto structTy = mlir::dyn_cast<StructType>(type)) if (structTy.isIncomplete()) - structTy.complete(membersRef, packed, padded, kindsRef); + structTy.complete(membersRef, packed, kindsRef); assert(!cir::MissingFeatures::astRecordDeclAttr()); } else { parser.emitError(loc, "anonymous records must be complete"); @@ -340,16 +333,14 @@ Type StructType::parse(mlir::AsmParser &parser) { void StructType::print(mlir::AsmPrinter &printer) const { printRecordBody(printer, *this, getName(), isClass(), getPacked(), - getPadded(), isIncomplete(), getMembers(), /*padding=*/{}, + isIncomplete(), getMembers(), /*padding=*/{}, getMemberKinds()); } -mlir::LogicalResult -StructType::verify(function_ref<mlir::InFlightDiagnostic()> emitError, - llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, - bool incomplete, bool packed, bool padded, - llvm::ArrayRef<RecordMemberKind> member_kinds, - bool is_class) { +mlir::LogicalResult StructType::verify( + function_ref<mlir::InFlightDiagnostic()> emitError, + llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name, bool incomplete, + bool packed, llvm::ArrayRef<RecordMemberKind> member_kinds, bool is_class) { if (name && name.getValue().empty()) return emitError() << "identified records cannot have an empty name"; return verifyRecordMemberKinds(emitError, members.size(), member_kinds); @@ -364,12 +355,15 @@ mlir::StringAttr StructType::getName() const { return getImpl()->name; } bool StructType::isIncomplete() const { return getImpl()->incomplete; } bool StructType::getIncomplete() const { return getImpl()->incomplete; } bool StructType::getPacked() const { return getImpl()->packed; } -bool StructType::getPadded() const { return getImpl()->padded; } llvm::ArrayRef<RecordMemberKind> StructType::getMemberKinds() const { return getImpl()->member_kinds; } bool StructType::getIsClass() const { return getImpl()->is_class; } +bool StructType::getPadded() const { + return llvm::is_contained(getMemberKinds(), RecordMemberKind::Pad); +} + bool StructType::isABIConvertedRecord() const { return getName() && getName().getValue().starts_with(abi_conversion_prefix); } @@ -388,10 +382,10 @@ void StructType::removeABIConversionNamePrefix() { recordName.getType()); } -void StructType::complete(ArrayRef<Type> members, bool packed, bool padded, +void StructType::complete(ArrayRef<Type> members, bool packed, ArrayRef<RecordMemberKind> memberKinds) { assert(!cir::MissingFeatures::astRecordDeclAttr()); - if (mutate(members, packed, padded, memberKinds).failed()) + if (mutate(members, packed, memberKinds).failed()) llvm_unreachable("failed to complete struct"); } @@ -504,8 +498,8 @@ Type UnionType::parse(mlir::AsmParser &parser) { void UnionType::print(mlir::AsmPrinter &printer) const { printRecordBody(printer, *this, getName(), /*hasClassPrefix=*/false, - getPacked(), /*isPadded=*/false, isIncomplete(), getMembers(), - getPadding(), getMemberKinds()); + getPacked(), isIncomplete(), getMembers(), getPadding(), + getMemberKinds()); } mlir::LogicalResult @@ -641,14 +635,13 @@ std::string RecordType::getKindAsStr() const { std::string RecordType::getPrefixedName() const { return getKindAsStr() + "." + getName().getValue().str(); } -void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded, +void RecordType::complete(ArrayRef<Type> members, bool packed, mlir::Type padding, ArrayRef<RecordMemberKind> memberKinds) { - if (auto s = mlir::dyn_cast<StructType>(*this)) - return s.complete(members, packed, padded, memberKinds); - // Unions derive padded from padding; assert the caller is consistent. - assert((!padded || padding) && - "padded=true requires a non-null padding type"); + if (auto s = mlir::dyn_cast<StructType>(*this)) { + assert(!padding && "only a union takes a separate padding slot"); + return s.complete(members, packed, memberKinds); + } return mlir::cast<UnionType>(*this).complete(members, packed, padding, memberKinds); } @@ -875,17 +868,20 @@ unsigned StructType::computeStructDataSize(const mlir::DataLayout &dataLayout) const { assert(isComplete() && "Cannot get layout of incomplete records"); - // Compute the data size (excluding tail padding) for this record type. For - // padded records, the last member is the tail padding array added by - // CIRGenRecordLayoutBuilder::appendPaddingBytes, so we exclude it. For - // non-padded records, data size equals the full struct size without - // alignment. - auto members = getMembers(); - unsigned numMembers = - getPadded() && members.size() > 1 ? members.size() - 1 : members.size(); + // Tail padding is the trailing run of pad members. An empty member stays + // inside the data size: it is storage the source declared, which a derived + // class may not reuse. + llvm::ArrayRef<mlir::Type> members = getMembers(); + llvm::ArrayRef<RecordMemberKind> kinds = getMemberKinds(); + assert(kinds.size() == members.size() && + "the two drop_back calls below must stay in step"); + while (!kinds.empty() && kinds.back() == RecordMemberKind::Pad) { + kinds = kinds.drop_back(); + members = members.drop_back(); + } + unsigned recordSize = 0; - for (unsigned i = 0; i < numMembers; ++i) { - mlir::Type ty = members[i]; + for (mlir::Type ty : members) { const uint64_t tyAlign = (getPacked() ? 1 : dataLayout.getTypeABIAlignment(ty)); recordSize = llvm::alignTo(recordSize, tyAlign); @@ -1262,7 +1258,7 @@ static mlir::Type getMethodLayoutType(mlir::MLIRContext *ctx) { auto voidPtrTy = cir::PointerType::get(cir::VoidType::get(ctx)); mlir::Type fields[2]{voidPtrTy, voidPtrTy}; return cir::StructType::get(ctx, fields, /*packed=*/false, - /*padded=*/false, /*is_class=*/false, + /*is_class=*/false, cir::RecordType::getAllDataKinds(fields)); } diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index e8e7f4d87346c..32ff223a671a4 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -866,8 +866,8 @@ class CIRABITypeConverter : public mlir::TypeConverter { } auto s = mlir::cast<cir::StructType>(type); return cir::StructType::get(type.getContext(), converted, - type.getPacked(), type.getPadded(), - s.getIsClass(), s.getMemberKinds()); + type.getPacked(), s.getIsClass(), + s.getMemberKinds()); } assert(!type.isIncomplete() || type.getMembers().empty()); @@ -914,8 +914,8 @@ class CIRABITypeConverter : public mlir::TypeConverter { if (auto u = mlir::dyn_cast<cir::UnionType>(type)) if (mlir::Type pad = u.getPadding()) loweredPadding = convertType(pad); - convertedType.complete(convertedMembers, type.getPacked(), type.getPadded(), - loweredPadding, type.getMemberKinds()); + convertedType.complete(convertedMembers, type.getPacked(), loweredPadding, + type.getMemberKinds()); addConvertedRecordType(convertedType); return convertedType; } diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp index 52932f6a20dd0..6d3249ef9e5b6 100644 --- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp @@ -246,8 +246,7 @@ static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx) { // Coercion types are plain register tuples, not the source record. return cir::StructType::get( ctx, fieldTypes, /*packed=*/false, - /*padded=*/false, /*is_class=*/false, - cir::RecordType::getAllDataKinds(fieldTypes)); + /*is_class=*/false, cir::RecordType::getAllDataKinds(fieldTypes)); }) .Default([](const llvm::abi::Type *) -> mlir::Type { return nullptr; }); } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 28ba14962cc7b..42ab14aba338e 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -2444,8 +2444,7 @@ void LoweringPreparePass::buildCUDAModuleCtor() { // struct { int magic; int version; void *fatbin; void *unused; }; mlir::Type fatbinWrapperMembers[] = {intTy, intTy, voidPtrTy, voidPtrTy}; auto fatbinWrapperType = cir::StructType::get( - &getContext(), fatbinWrapperMembers, /*packed=*/false, /*padded=*/false, - /*is_class=*/false, + &getContext(), fatbinWrapperMembers, /*packed=*/false, /*is_class=*/false, cir::RecordType::getAllDataKinds(fatbinWrapperMembers)); std::string fatbinWrapperName = addUnderscoredPrefix(cudaPrefix, "_fatbin_wrapper"); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 458f87f2b8c07..fdfbea028926a 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -192,7 +192,7 @@ mlir::Type LowerItaniumCXXABI::lowerMethodType( // function pointers. Let's follow this approach. mlir::Type members[] = {ptr diff CIRTy, ptr diff CIRTy}; return cir::StructType::get(type.getContext(), members, /*packed=*/false, - /*padded=*/false, /*is_class=*/false, + /*is_class=*/false, cir::RecordType::getAllDataKinds(members)); } diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 34669bf492e58..96a84eeac4929 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -9,7 +9,7 @@ struct S1 { short x, y, z; }; -// CIR: !rec_anon_struct = !cir.struct<padded {data !rec_S1, pad !cir.array<!s8i x 2>}> +// CIR: !rec_anon_struct = !cir.struct<{data !rec_S1, pad !cir.array<!s8i x 2>}> _Atomic int g1; _Atomic int g2 = 42; diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index 330c31989ff70..2ed9c6147212b 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -12,7 +12,7 @@ typedef struct { unsigned still_more_bits : 7; } A; -// CIR-DAG: !rec_A = !cir.struct<"A" packed padded {data !s8i, data !s8i, data !s8i, data !u16i, pad !cir.array<!u8i x 3>}> +// CIR-DAG: !rec_A = !cir.struct<"A" packed {data !s8i, data !s8i, data !s8i, data !u16i, pad !cir.array<!u8i x 3>}> // CIR-DAG: #bfi_more_bits = #cir.bitfield_info<name = "more_bits", storage_type = !u16i, size = 4, offset = 3, is_signed = false> // LLVM-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }> // OGCG-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }> diff --git a/clang/test/CIR/CodeGen/cleanup.cpp b/clang/test/CIR/CodeGen/cleanup.cpp index 4644c50a15a35..a2e4104fcc61e 100644 --- a/clang/test/CIR/CodeGen/cleanup.cpp +++ b/clang/test/CIR/CodeGen/cleanup.cpp @@ -7,7 +7,7 @@ struct Struk { ~Struk(); }; -// CHECK: !rec_Struk = !cir.struct<"Struk" padded {pad !u8i}> +// CHECK: !rec_Struk = !cir.struct<"Struk" {pad !u8i}> // CHECK: cir.func{{.*}} @_ZN5StrukD1Ev(!cir.ptr<!rec_Struk> {{.*}}) diff --git a/clang/test/CIR/CodeGen/dumb-record.cpp b/clang/test/CIR/CodeGen/dumb-record.cpp index 75d442f28aee2..10870124bd019 100644 --- a/clang/test/CIR/CodeGen/dumb-record.cpp +++ b/clang/test/CIR/CodeGen/dumb-record.cpp @@ -15,8 +15,8 @@ struct Empty { } empty; // CHECK: Layout: <CIRecordLayout -// CHECK: CIR Type:!cir.struct<"Empty" padded {pad !cir.int<u, 8>}> -// CHECK: NonVirtualBaseCIRType:!cir.struct<"Empty" padded {pad !cir.int<u, 8>}> +// CHECK: CIR Type:!cir.struct<"Empty" {pad !cir.int<u, 8>}> +// CHECK: NonVirtualBaseCIRType:!cir.struct<"Empty" {pad !cir.int<u, 8>}> // CHECK: IsZeroInitializable:1 // CHECK: BitFields:[ // CHECK: ]> diff --git a/clang/test/CIR/CodeGen/empty-union.cpp b/clang/test/CIR/CodeGen/empty-union.cpp index c543b25253625..a608eefbc77aa 100644 --- a/clang/test/CIR/CodeGen/empty-union.cpp +++ b/clang/test/CIR/CodeGen/empty-union.cpp @@ -86,7 +86,7 @@ Leading leadArr[2]; // CIR-DAG: !rec_Leading = !cir.struct<"Leading" {data !rec_Empty, data !s32i}> // CIR-DAG: !rec_Trailing = !cir.struct<"Trailing" {data !s32i, data !rec_Empty}> // CIR-DAG: !rec_Middle = !cir.struct<"Middle" {data !s32i, data !rec_Empty, data !s32i}> -// CIR-DAG: !rec_LeadingOver = !cir.struct<"LeadingOver" padded {data !rec_EmptyAligned, data !s32i, pad !cir.array<!u8i x 12>}> +// CIR-DAG: !rec_LeadingOver = !cir.struct<"LeadingOver" {data !rec_EmptyAligned, data !s32i, pad !cir.array<!u8i x 12>}> // CIR-DAG: !rec_LeadingZeroBitfield = !cir.struct<"LeadingZeroBitfield" {data !rec_OnlyZeroBitfield, data !s32i}> // CIR keeps the union's own named type as the record's field and leaves the diff --git a/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp b/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp index 01512d910b12b..db97c97342ec8 100644 --- a/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp +++ b/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp @@ -23,7 +23,7 @@ struct S2 { unsigned long f3:6; }; -// CIR-DAG: !rec_S2 = !cir.struct<"S2" padded {data !u16i, data !u16i, data !u8i, pad !cir.array<!u8i x 3>}> +// CIR-DAG: !rec_S2 = !cir.struct<"S2" {data !u16i, data !u16i, data !u8i, pad !cir.array<!u8i x 3>}> // LLVM-DAG: %struct.S2 = type { i16, i16, i8, [3 x i8] } // OGCG-DAG: %struct.S2 = type { i16, i16, i8, [3 x i8] } diff --git a/clang/test/CIR/CodeGen/member-functions.cpp b/clang/test/CIR/CodeGen/member-functions.cpp index e365f5312e479..4fc39390b6eb9 100644 --- a/clang/test/CIR/CodeGen/member-functions.cpp +++ b/clang/test/CIR/CodeGen/member-functions.cpp @@ -6,7 +6,7 @@ struct C { void f2(int a, int b); }; -// CIR: !rec_C = !cir.struct<"C" padded {pad !u8i}> +// CIR: !rec_C = !cir.struct<"C" {pad !u8i}> void C::f() {} diff --git a/clang/test/CIR/CodeGen/no-unique-address.cpp b/clang/test/CIR/CodeGen/no-unique-address.cpp index da507405c3321..54514d5f18b20 100644 --- a/clang/test/CIR/CodeGen/no-unique-address.cpp +++ b/clang/test/CIR/CodeGen/no-unique-address.cpp @@ -30,7 +30,7 @@ struct Outer { // Middle's tail padding. // CIR: !rec_Middle2Ebase = !cir.struct<"Middle.base" packed {data !rec_Base, data !s8i}> -// CIR: !rec_Outer = !cir.struct<"Outer" padded {data !rec_Middle2Ebase, data !s8i, pad !cir.array<!u8i x 2>}> +// CIR: !rec_Outer = !cir.struct<"Outer" {data !rec_Middle2Ebase, data !s8i, pad !cir.array<!u8i x 2>}> // CIR-LABEL: cir.func {{.*}} @_ZN5OuterC2ERK6Middlec( // CIR: %[[THIS:.*]] = cir.load %{{.+}} : !cir.ptr<!cir.ptr<!rec_Outer>>, !cir.ptr<!rec_Outer> @@ -192,8 +192,8 @@ OuterUnionPadAfterStorage oupas; // CIR-NUA-DAG: !rec_OuterUnionPad = !cir.struct<"OuterUnionPad" {data !rec_UnionWithPadding2Ebase, data !cir.bool}> // CIR-NUA-DAG: !rec_FinalUnionWithPadding2Ebase = !cir.struct<"FinalUnionWithPadding.base" {data !u8i}> // CIR-NUA-DAG: !rec_OuterFinalUnionPad = !cir.struct<"OuterFinalUnionPad" {data !rec_FinalUnionWithPadding2Ebase, data !cir.bool}> -// CIR-NUA-DAG: !rec_TailBig = !cir.struct<"TailBig" packed padded {data !s16i, data !cir.array<!s8i x 5>, pad !u8i}> -// CIR-NUA-DAG: !rec_UnionPadAfterStorage2Ebase = !cir.struct<"UnionPadAfterStorage.base" packed padded {data !s32i, pad !cir.array<!u8i x 3>}> +// CIR-NUA-DAG: !rec_TailBig = !cir.struct<"TailBig" packed {data !s16i, data !cir.array<!s8i x 5>, pad !u8i}> +// CIR-NUA-DAG: !rec_UnionPadAfterStorage2Ebase = !cir.struct<"UnionPadAfterStorage.base" packed {data !s32i, pad !cir.array<!u8i x 3>}> // CIR-NUA-DAG: !rec_OuterUnionPadAfterStorage = !cir.struct<"OuterUnionPadAfterStorage" {data !rec_UnionPadAfterStorage2Ebase, data !cir.bool}> // CIR-NUA-DAG: cir.global external @ou = #cir.zero : !rec_OuterUnion // CIR-NUA-DAG: cir.global external @of = #cir.zero : !rec_OuterFinal diff --git a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp index f960254c288b4..74541056ea8c8 100644 --- a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp +++ b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp @@ -38,7 +38,7 @@ struct B { }; // LLVM-DAG: [[STRUCT_C:%.*]] = type <{ [[STRUCT_B]], [[STRUCT_A]], i32, [4 x i8] }> -// CIR-DAG: ![[STRUCT_C:.*]] = !cir.struct<"C" packed padded {data ![[STRUCT_B]], data ![[STRUCT_A]], data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-DAG: ![[STRUCT_C:.*]] = !cir.struct<"C" packed {data ![[STRUCT_B]], data ![[STRUCT_A]], data !s32i, pad !cir.array<!u8i x 4>}> struct C : public B, public A { int c; }; @@ -60,7 +60,7 @@ struct E { ~E() {}; }; -// CIR-DAG: ![[STRUCT_F:.*]] = !cir.struct<"F" padded {pad !u8i}> +// CIR-DAG: ![[STRUCT_F:.*]] = !cir.struct<"F" {pad !u8i}> struct F { F (int i = 1); F (const F &f) = delete; @@ -69,7 +69,7 @@ struct F { // LLVMCIR-DAG: [[STRUCT_G:%.*]] = type <{ i32, %struct.F, [3 x i8] }> // OGCG-DAG: [[STRUCT_G:%.*]] = type <{ i32, [4 x i8] }> -// CIR-DAG: ![[STRUCT_G:.*]] = !cir.struct<"G" packed padded {data !s32i, data !rec_F, pad !cir.array<!u8i x 3>}> +// CIR-DAG: ![[STRUCT_G:.*]] = !cir.struct<"G" packed {data !s32i, data !rec_F, pad !cir.array<!u8i x 3>}> struct G { int a; F f; @@ -87,7 +87,7 @@ union U { namespace gh61145 { // LLVM-DAG: [[STRUCT_VEC:%.*Vec.*]] = type { i8 } - // CIR-DAG: ![[STRUCT_VEC:.*]] = !cir.struct<"gh61145::Vec" padded {pad !u8i}> + // CIR-DAG: ![[STRUCT_VEC:.*]] = !cir.struct<"gh61145::Vec" {pad !u8i}> struct Vec { Vec(); Vec(Vec&&); diff --git a/clang/test/CIR/CodeGen/pointer-to-empty-data-member.cpp b/clang/test/CIR/CodeGen/pointer-to-empty-data-member.cpp index cd1cdd358e9d0..3c1d59223c9ad 100644 --- a/clang/test/CIR/CodeGen/pointer-to-empty-data-member.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-empty-data-member.cpp @@ -7,7 +7,7 @@ // RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s struct Empty {}; -// CIR-DAG: !rec_Empty = !cir.struct<"Empty" padded {pad !u8i}> +// CIR-DAG: !rec_Empty = !cir.struct<"Empty" {pad !u8i}> // LLVMCIR-DAG: %struct.Empty = type { i8 } struct HasEmpty { @@ -38,7 +38,7 @@ const HasEmpty2 globalHE2 = {{}, 1}; // Not referenced enough to be emitted in 'after'. struct EmptyBase{}; -// CIR-BEFORE-DAG: !rec_EmptyBase = !cir.struct<"EmptyBase" padded {pad !u8i}> +// CIR-BEFORE-DAG: !rec_EmptyBase = !cir.struct<"EmptyBase" {pad !u8i}> struct Base { int i; }; // CIR-DAG: !rec_Base = !cir.struct<"Base" {data !s32i}> @@ -87,7 +87,7 @@ struct hasNUA { [[no_unique_address]] EmptyBase eb6; int i; }; -// CIR-DAG: !rec_hasNUA = !cir.struct<"hasNUA" padded {data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-DAG: !rec_hasNUA = !cir.struct<"hasNUA" {data !s32i, pad !cir.array<!u8i x 4>}> // LLVM-DAG: %struct.hasNUA = type { i32, [4 x i8] } const hasNUA nua = {{},{},{},{},{},{}, 1}; diff --git a/clang/test/CIR/CodeGen/record-member-kinds.c b/clang/test/CIR/CodeGen/record-member-kinds.c index 3c6140d60a7fa..1e46153862a49 100644 --- a/clang/test/CIR/CodeGen/record-member-kinds.c +++ b/clang/test/CIR/CodeGen/record-member-kinds.c @@ -79,7 +79,7 @@ union ContainsEmptyUnion { struct E e; }; // CIR-DAG: !rec_ContainsEmptyUnion = !cir.union<"ContainsEmptyUnion" {empty !rec_E}> struct AlignedTail { char c; int i __attribute__((aligned(8))); }; -// CIR-DAG: !rec_AlignedTail = !cir.struct<"AlignedTail" padded {data !s8i, pad !cir.array<!u8i x 7>, data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-DAG: !rec_AlignedTail = !cir.struct<"AlignedTail" {data !s8i, pad !cir.array<!u8i x 7>, data !s32i, pad !cir.array<!u8i x 4>}> // LLVM-DAG: %struct.AlignedTail = type { i8, [7 x i8], i32, [4 x i8] } // Name every record so that its CIR type reaches the output. diff --git a/clang/test/CIR/CodeGen/record-member-kinds.cpp b/clang/test/CIR/CodeGen/record-member-kinds.cpp index 5da943fb32d5b..98be5496e7040 100644 --- a/clang/test/CIR/CodeGen/record-member-kinds.cpp +++ b/clang/test/CIR/CodeGen/record-member-kinds.cpp @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM struct Empty {}; -// CIR-DAG: !rec_Empty = !cir.struct<"Empty" padded {pad !u8i}> +// CIR-DAG: !rec_Empty = !cir.struct<"Empty" {pad !u8i}> // LLVM-DAG: %struct.Empty = type { i8 } // A C++ empty member is not empty for the ABI without [[no_unique_address]]. @@ -44,7 +44,7 @@ struct DerivesBitFieldBase : BitFieldBase { int i; }; // A virtual base is marked the same way a non-virtual one is. struct HasBitFieldVBase : virtual BitFieldBase { int i; }; -// CIR-DAG: !rec_HasBitFieldVBase = !cir.struct<"HasBitFieldVBase" packed padded {data !cir.vptr, data !s32i, empty !rec_BitFieldBase, pad !cir.array<!u8i x 3>}> +// CIR-DAG: !rec_HasBitFieldVBase = !cir.struct<"HasBitFieldVBase" packed {data !cir.vptr, data !s32i, empty !rec_BitFieldBase, pad !cir.array<!u8i x 3>}> struct ZeroLenEmptyArr { Empty e[0]; }; // CIR-DAG: !rec_ZeroLenEmptyArr = !cir.struct<"ZeroLenEmptyArr" {empty !cir.array<!rec_Empty x 0>}> @@ -59,7 +59,7 @@ struct NuaEmptyArr { [[no_unique_address]] Empty e[2]; int i; }; // CIR-DAG: !rec_NuaEmptyArr = !cir.struct<"NuaEmptyArr" {data !cir.array<!rec_Empty x 2>, data !s32i}> struct AlignasTail { char c; alignas(8) int i; }; -// CIR-DAG: !rec_AlignasTail = !cir.struct<"AlignasTail" padded {data !s8i, pad !cir.array<!u8i x 7>, data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-DAG: !rec_AlignasTail = !cir.struct<"AlignasTail" {data !s8i, pad !cir.array<!u8i x 7>, data !s32i, pad !cir.array<!u8i x 4>}> // LLVM-DAG: %struct.AlignasTail = type { i8, [7 x i8], i32, [4 x i8] } // An unnamed bit-field unit is declared storage that holds no ABI data. @@ -80,10 +80,10 @@ struct UnnamedFirst { int : 16; int a : 8; }; // A zero-length bit-field separates one span into two units, and a record can // carry a data unit and an empty unit at once, in either order. struct SpanMixed { int a : 3; int : 0; int : 3; }; -// CIR-DAG: !rec_SpanMixed = !cir.struct<"SpanMixed" padded {data !u8i, pad !cir.array<!u8i x 3>, empty !u8i, pad !cir.array<!u8i x 3>}> +// CIR-DAG: !rec_SpanMixed = !cir.struct<"SpanMixed" {data !u8i, pad !cir.array<!u8i x 3>, empty !u8i, pad !cir.array<!u8i x 3>}> struct SpanEmptyFirst { int : 3; int : 0; int b : 3; }; -// CIR-DAG: !rec_SpanEmptyFirst = !cir.struct<"SpanEmptyFirst" padded {empty !u8i, pad !cir.array<!u8i x 3>, data !u8i, pad !cir.array<!u8i x 3>}> +// CIR-DAG: !rec_SpanEmptyFirst = !cir.struct<"SpanEmptyFirst" {empty !u8i, pad !cir.array<!u8i x 3>, data !u8i, pad !cir.array<!u8i x 3>}> // One unit covering both of these would need more than one register, so they // split into two units that are marked independently. @@ -110,13 +110,13 @@ struct NearlyEmptyVBase { virtual ~NearlyEmptyVBase(); }; // CIR-DAG: !rec_NearlyEmptyVBase = !cir.struct<"NearlyEmptyVBase" {data !cir.vptr}> struct HasNearlyEmptyVBase : virtual NearlyEmptyVBase { int i; }; -// CIR-DAG: !rec_HasNearlyEmptyVBase = !cir.struct<"HasNearlyEmptyVBase" packed padded {data !rec_NearlyEmptyVBase, data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-DAG: !rec_HasNearlyEmptyVBase = !cir.struct<"HasNearlyEmptyVBase" packed {data !rec_NearlyEmptyVBase, data !s32i, pad !cir.array<!u8i x 4>}> // Both marks appear on one record: the byte array is storage the source // declared for its unnamed bit-field, while the byte after it is inserted by // the compiler. The storage keeps its mark in the base subobject type. struct Clipped { Clipped(const Clipped &); int i; int : 24; }; -// CIR-DAG: !rec_Clipped = !cir.struct<"Clipped" packed padded {data !s32i, empty !cir.array<!u8i x 3>, pad !u8i}> +// CIR-DAG: !rec_Clipped = !cir.struct<"Clipped" packed {data !s32i, empty !cir.array<!u8i x 3>, pad !u8i}> // CIR-DAG: !rec_Clipped2Ebase = !cir.struct<"Clipped.base" packed {data !s32i, empty !cir.array<!u8i x 3>}> struct DerivedClipped : Clipped { char c; }; diff --git a/clang/test/CIR/CodeGen/record-type-metadata.cpp b/clang/test/CIR/CodeGen/record-type-metadata.cpp index 156e69c55713e..8bc0ce148080c 100644 --- a/clang/test/CIR/CodeGen/record-type-metadata.cpp +++ b/clang/test/CIR/CodeGen/record-type-metadata.cpp @@ -21,8 +21,8 @@ void takesNTD(NonTrivialDtor n) {} // Record types should NOT contain ABI metadata keywords. // CIR-DAG: !rec_Trivial = !cir.struct<"Trivial" {data !s32i, data !s32i}> -// CIR-DAG: !rec_Empty = !cir.struct<"Empty" padded {pad !u8i}> -// CIR-DAG: !rec_Aligned = !cir.struct<"Aligned" padded {data !s32i, data !s32i, pad !cir.array<!u8i x 8>}> +// CIR-DAG: !rec_Empty = !cir.struct<"Empty" {pad !u8i}> +// CIR-DAG: !rec_Aligned = !cir.struct<"Aligned" {data !s32i, data !s32i, pad !cir.array<!u8i x 8>}> // CIR-DAG: !rec_NonTrivialDtor = !cir.struct<class "NonTrivialDtor" {data !s32i}> // ABI metadata lives in module-level cir.record_layouts attribute. diff --git a/clang/test/CIR/CodeGen/struct.c b/clang/test/CIR/CodeGen/struct.c index e43f20bef56f1..09f4fc4e26266 100644 --- a/clang/test/CIR/CodeGen/struct.c +++ b/clang/test/CIR/CodeGen/struct.c @@ -12,7 +12,7 @@ // CIR-DAG: !rec_OuterS = !cir.struct<"OuterS" {data !rec_InnerS, data !s32i}> // CIR-DAG: !rec_InnerS = !cir.struct<"InnerS" {data !s32i, data !s8i}> // CIR-DAG: !rec_PackedS = !cir.struct<"PackedS" packed {data !s32i, data !s8i}> -// CIR-DAG: !rec_PackedAndPaddedS = !cir.struct<"PackedAndPaddedS" packed padded {data !s32i, data !s8i, pad !u8i}> +// CIR-DAG: !rec_PackedAndPaddedS = !cir.struct<"PackedAndPaddedS" packed {data !s32i, data !s8i, pad !u8i}> // CIR-DAG: !rec_NodeS = !cir.struct<"NodeS" {data !cir.ptr<!cir.struct<"NodeS">>}> // CIR-DAG: !rec_RightS = !cir.struct<"RightS" {data !cir.ptr<!cir.struct<"LeftS" {data !cir.ptr<!cir.struct<"RightS">>}>>}> // CIR-DAG: !rec_LeftS = !cir.struct<"LeftS" {data !cir.ptr<!rec_RightS>}> diff --git a/clang/test/CIR/CodeGen/template-specialization.cpp b/clang/test/CIR/CodeGen/template-specialization.cpp index 66f81baf51f60..06fc834a4dcdf 100644 --- a/clang/test/CIR/CodeGen/template-specialization.cpp +++ b/clang/test/CIR/CodeGen/template-specialization.cpp @@ -13,7 +13,7 @@ class Templ<T, int>{}; Templ<int, int> t; -// CIR: !rec_Templ3Cint2C_int3E = !cir.struct<class "Templ<int, int>" padded {pad !u8i}> +// CIR: !rec_Templ3Cint2C_int3E = !cir.struct<class "Templ<int, int>" {pad !u8i}> // CIR: cir.global external @t = #cir.zero : !rec_Templ3Cint2C_int3E // LLVM: %"class.Templ<int, int>" = type { i8 } diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp index 62fc27d4949b6..c4d22f2091b28 100644 --- a/clang/test/CIR/CodeGen/vtt.cpp +++ b/clang/test/CIR/CodeGen/vtt.cpp @@ -49,8 +49,8 @@ void D::y() {} // CIR-COMMON: !rec_A2Ebase = !cir.struct<"A.base" packed {data !cir.vptr, data !s32i}> // CIR-COMMON: !rec_B2Ebase = !cir.struct<"B.base" packed {data !cir.vptr, data !s32i}> // CIR-COMMON: !rec_C2Ebase = !cir.struct<"C.base" {data !cir.vptr, data !s64i}> -// CIR-COMMON: !rec_A = !cir.struct<class "A" packed padded {data !cir.vptr, data !s32i, pad !cir.array<!u8i x 4>}> -// CIR-COMMON: !rec_B = !cir.struct<class "B" packed padded {data !cir.vptr, data !s32i, pad !cir.array<!u8i x 4>, data !rec_A2Ebase, pad !cir.array<!u8i x 4>}> +// CIR-COMMON: !rec_A = !cir.struct<class "A" packed {data !cir.vptr, data !s32i, pad !cir.array<!u8i x 4>}> +// CIR-COMMON: !rec_B = !cir.struct<class "B" packed {data !cir.vptr, data !s32i, pad !cir.array<!u8i x 4>, data !rec_A2Ebase, pad !cir.array<!u8i x 4>}> // CIR-COMMON: !rec_C = !cir.struct<class "C" {data !cir.vptr, data !s64i, data !rec_A2Ebase}> // CIR-COMMON: !rec_D = !cir.struct<class "D" {data !rec_B2Ebase, data !rec_C2Ebase, data !s64i, data !rec_A2Ebase}> diff --git a/clang/test/CIR/CodeGenCXX/zero_init_bases.cpp b/clang/test/CIR/CodeGenCXX/zero_init_bases.cpp index 98078212c53e3..2827c655444e5 100644 --- a/clang/test/CIR/CodeGenCXX/zero_init_bases.cpp +++ b/clang/test/CIR/CodeGenCXX/zero_init_bases.cpp @@ -25,7 +25,7 @@ struct VirtualInherits : virtual Base1, virtual Base2 { // CIR: !rec_Base2 = !cir.struct<"Base2" {data !cir.float, data !cir.float, data !cir.float}> // CIR: !rec_Base1 = !cir.struct<"Base1" {data !s32i, data !s32i, data !s32i}> // CIR: !rec_Inherits = !cir.struct<"Inherits" {data !rec_Base1, data !rec_Base2, data !s32i, data !s32i, data !s32i}> -// CIR: !rec_VirtualInherits = !cir.struct<"VirtualInherits" packed padded {data !cir.vptr, data !s32i, data !s32i, data !s32i, data !rec_Base1, data !rec_Base2, pad !cir.array<!u8i x 4>}> +// CIR: !rec_VirtualInherits = !cir.struct<"VirtualInherits" packed {data !cir.vptr, data !s32i, data !s32i, data !s32i, data !rec_Base1, data !rec_Base2, pad !cir.array<!u8i x 4>}> // // LLVM: %struct.Inherits = type { %struct.Base1, %struct.Base2, i32, i32, i32 } // LLVM: %struct.Base1 = type { i32, i32, i32 } diff --git a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp index bfa205e97e3de..a337cd8569a88 100644 --- a/clang/test/CIR/CodeGenCoroutines/coro-task.cpp +++ b/clang/test/CIR/CodeGenCoroutines/coro-task.cpp @@ -7,15 +7,15 @@ #include "Inputs/coroutine.h" -// CIR-DAG: ![[VoidTask:.*]] = !cir.struct<"folly::coro::Task<void>" padded {pad !u8i}> -// CIR-DAG: ![[IntTask:.*]] = !cir.struct<"folly::coro::Task<int>" padded {pad !u8i}> -// CIR-DAG: ![[VoidPromisse:.*]] = !cir.struct<"folly::coro::Task<void>::promise_type" padded {pad !u8i}> -// CIR-DAG: ![[IntPromisse:.*]] = !cir.struct<"folly::coro::Task<int>::promise_type" padded {pad !u8i}> -// CIR-DAG: ![[StdString:.*]] = !cir.struct<"std::string" padded {pad !u8i}> -// CIR-DAG: ![[CoroHandleVoid:.*]] = !cir.struct<"std::coroutine_handle<void>" padded {pad !u8i}> -// CIR-DAG: ![[CoroHandlePromiseVoid:rec_.*]] = !cir.struct<"std::coroutine_handle<folly::coro::Task<void>::promise_type>" padded {pad !u8i}> -// CIR-DAG: ![[CoroHandlePromiseInt:rec_.*]] = !cir.struct<"std::coroutine_handle<folly::coro::Task<int>::promise_type>" padded {pad !u8i}> -// CIR-DAG: ![[SuspendAlways:.*]] = !cir.struct<"std::suspend_always" padded {pad !u8i}> +// CIR-DAG: ![[VoidTask:.*]] = !cir.struct<"folly::coro::Task<void>" {pad !u8i}> +// CIR-DAG: ![[IntTask:.*]] = !cir.struct<"folly::coro::Task<int>" {pad !u8i}> +// CIR-DAG: ![[VoidPromisse:.*]] = !cir.struct<"folly::coro::Task<void>::promise_type" {pad !u8i}> +// CIR-DAG: ![[IntPromisse:.*]] = !cir.struct<"folly::coro::Task<int>::promise_type" {pad !u8i}> +// CIR-DAG: ![[StdString:.*]] = !cir.struct<"std::string" {pad !u8i}> +// CIR-DAG: ![[CoroHandleVoid:.*]] = !cir.struct<"std::coroutine_handle<void>" {pad !u8i}> +// CIR-DAG: ![[CoroHandlePromiseVoid:rec_.*]] = !cir.struct<"std::coroutine_handle<folly::coro::Task<void>::promise_type>" {pad !u8i}> +// CIR-DAG: ![[CoroHandlePromiseInt:rec_.*]] = !cir.struct<"std::coroutine_handle<folly::coro::Task<int>::promise_type>" {pad !u8i}> +// CIR-DAG: ![[SuspendAlways:.*]] = !cir.struct<"std::suspend_always" {pad !u8i}> // OGCG-DAG: %[[VoidPromisse:"struct.folly::coro::Task<void>::promise_type"]] = type { i8 } // OGCG-DAG: %[[VoidTask:"struct.folly::coro::Task"]] = type { i8 } diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir index 7e122adb3dda1..45d4d8fdb4a21 100644 --- a/clang/test/CIR/IR/array-ctor.cir +++ b/clang/test/CIR/IR/array-ctor.cir @@ -3,7 +3,7 @@ !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) diff --git a/clang/test/CIR/IR/array-dtor.cir b/clang/test/CIR/IR/array-dtor.cir index f7f835881ec38..ac884f5899d2e 100644 --- a/clang/test/CIR/IR/array-dtor.cir +++ b/clang/test/CIR/IR/array-dtor.cir @@ -1,7 +1,7 @@ // RUN: cir-opt %s --verify-roundtrip | FileCheck %s !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @_ZN1SD1Ev(!cir.ptr<!rec_S>) diff --git a/clang/test/CIR/IR/construct-catch-param.cir b/clang/test/CIR/IR/construct-catch-param.cir index 7a77b81308126..b72eee2e8d028 100644 --- a/clang/test/CIR/IR/construct-catch-param.cir +++ b/clang/test/CIR/IR/construct-catch-param.cir @@ -3,7 +3,7 @@ !s8i = !cir.int<s, 8> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { diff --git a/clang/test/CIR/IR/func-attrs.cir b/clang/test/CIR/IR/func-attrs.cir index a96d88bf53cee..17a5ae905e5fe 100644 --- a/clang/test/CIR/IR/func-attrs.cir +++ b/clang/test/CIR/IR/func-attrs.cir @@ -5,7 +5,7 @@ !s8i = !cir.int<s, 8> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_Struct = !cir.struct<"Struct" padded {data !u8i}> +!rec_Struct = !cir.struct<"Struct" {pad !u8i}> !rec_anon_struct = !cir.struct<{data !s64i, data !s64i}> cir.func no_inline dso_local @Func1(%arg0: !s32i {llvm.noundef}, %arg1: !cir.float {llvm.noundef}) -> (!cir.float {llvm.noundef}) { diff --git a/clang/test/CIR/IR/global-init.cir b/clang/test/CIR/IR/global-init.cir index a393005bcadb0..3e0387ed52594 100644 --- a/clang/test/CIR/IR/global-init.cir +++ b/clang/test/CIR/IR/global-init.cir @@ -2,9 +2,9 @@ !u8i = !cir.int<u, 8> -!rec_NeedsCtor = !cir.struct<"NeedsCtor" padded {data !u8i}> -!rec_NeedsDtor = !cir.struct<"NeedsDtor" padded {data !u8i}> -!rec_NeedsCtorDtor = !cir.struct<"NeedsCtorDtor" padded {data !u8i}> +!rec_NeedsCtor = !cir.struct<"NeedsCtor" {pad !u8i}> +!rec_NeedsDtor = !cir.struct<"NeedsDtor" {pad !u8i}> +!rec_NeedsCtorDtor = !cir.struct<"NeedsCtorDtor" {pad !u8i}> module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { cir.func private @_ZN9NeedsCtorC1Ev(!cir.ptr<!rec_NeedsCtor>) diff --git a/clang/test/CIR/IR/invalid-array-structor.cir b/clang/test/CIR/IR/invalid-array-structor.cir index 5527670af2ab2..aad53dc5e5ed3 100644 --- a/clang/test/CIR/IR/invalid-array-structor.cir +++ b/clang/test/CIR/IR/invalid-array-structor.cir @@ -3,7 +3,7 @@ !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func dso_local @bad_static_array_ctor_with_num_elements(%p: !cir.ptr<!cir.array<!rec_S x 10>>, %n: !u64i) { @@ -19,7 +19,7 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) @@ -38,7 +38,7 @@ module { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @construct_int(!cir.ptr<!u8i>) @@ -58,8 +58,8 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> -!rec_T = !cir.struct<"T" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> +!rec_T = !cir.struct<"T" {pad !u8i}> module { cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) @@ -78,8 +78,8 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> -!rec_T = !cir.struct<"T" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> +!rec_T = !cir.struct<"T" {pad !u8i}> module { cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) @@ -99,7 +99,7 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func dso_local @bad_static_array_dtor_with_num_elements(%p: !cir.ptr<!cir.array<!rec_S x 10>>, %n: !u64i) { @@ -114,7 +114,7 @@ module { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @_ZN1SD1Ev(!cir.ptr<!rec_S>) @@ -131,7 +131,7 @@ module { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @destroy_int(!cir.ptr<!u8i>) @@ -150,8 +150,8 @@ module { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> -!rec_T = !cir.struct<"T" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> +!rec_T = !cir.struct<"T" {pad !u8i}> module { cir.func private @_ZN1SD1Ev(!cir.ptr<!rec_S>) @@ -169,8 +169,8 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> -!rec_T = !cir.struct<"T" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> +!rec_T = !cir.struct<"T" {pad !u8i}> module { cir.func private @_ZN1SD1Ev(!cir.ptr<!rec_S>) @@ -189,8 +189,8 @@ module { !u8i = !cir.int<u, 8> !u64i = !cir.int<u, 64> -!rec_S = !cir.struct<"S" padded {data !u8i}> -!rec_T = !cir.struct<"T" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> +!rec_T = !cir.struct<"T" {pad !u8i}> module { cir.func private @_ZN1SD1Ev(!cir.ptr<!rec_S>) diff --git a/clang/test/CIR/IR/invalid-construct-catch-param.cir b/clang/test/CIR/IR/invalid-construct-catch-param.cir index 375801a131a10..86c4c6d6612aa 100644 --- a/clang/test/CIR/IR/invalid-construct-catch-param.cir +++ b/clang/test/CIR/IR/invalid-construct-catch-param.cir @@ -3,7 +3,7 @@ !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -34,7 +34,7 @@ cir.func @copy_fn_missing() { !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -68,7 +68,7 @@ cir.func @copy_fn_missing_thunk_attr() { !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -104,7 +104,7 @@ cir.func @copy_fn_wrong_arity() { !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -141,7 +141,7 @@ cir.func @copy_fn_non_void_return() { !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -179,7 +179,7 @@ cir.func @copy_fn_first_arg_mismatch() { !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { @@ -216,7 +216,7 @@ cir.func @copy_fn_second_arg_mismatch() { !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module { diff --git a/clang/test/CIR/IR/invalid-delete-array.cir b/clang/test/CIR/IR/invalid-delete-array.cir index eaffbdfb2923a..7d6ce8be0951f 100644 --- a/clang/test/CIR/IR/invalid-delete-array.cir +++ b/clang/test/CIR/IR/invalid-delete-array.cir @@ -2,7 +2,7 @@ !void = !cir.void !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @_ZdaPvm(!cir.ptr<!void>) diff --git a/clang/test/CIR/IR/invalid-loop-cleanup.cir b/clang/test/CIR/IR/invalid-loop-cleanup.cir index 02519dfdaf33e..ea07513bde788 100644 --- a/clang/test/CIR/IR/invalid-loop-cleanup.cir +++ b/clang/test/CIR/IR/invalid-loop-cleanup.cir @@ -1,7 +1,7 @@ // RUN: cir-opt %s -verify-diagnostics -split-input-file !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> cir.func private @ctor(!cir.ptr<!rec_S>) cir.func private @operatorBool(!cir.ptr<!rec_S>) -> !cir.bool @@ -28,7 +28,7 @@ cir.func @while_cleanup_missing_kind() { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> cir.func private @ctor(!cir.ptr<!rec_S>) cir.func private @operatorBool(!cir.ptr<!rec_S>) -> !cir.bool @@ -57,7 +57,7 @@ cir.func @for_cleanup_missing_kind() { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> cir.func private @ctor(!cir.ptr<!rec_S>) cir.func private @operatorBool(!cir.ptr<!rec_S>) -> !cir.bool @@ -83,7 +83,7 @@ cir.func @while_cleanup_eh() { // ----- !u8i = !cir.int<u, 8> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> cir.func private @ctor(!cir.ptr<!rec_S>) cir.func private @operatorBool(!cir.ptr<!rec_S>) -> !cir.bool diff --git a/clang/test/CIR/IR/loop-cleanup.cir b/clang/test/CIR/IR/loop-cleanup.cir index 666709399d100..84267a33105f7 100644 --- a/clang/test/CIR/IR/loop-cleanup.cir +++ b/clang/test/CIR/IR/loop-cleanup.cir @@ -2,7 +2,7 @@ !u8i = !cir.int<u, 8> #true = #cir.bool<true> : !cir.bool -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @ctor(!cir.ptr<!rec_S>) diff --git a/clang/test/CIR/IR/struct.cir b/clang/test/CIR/IR/struct.cir index 30e278efcec8c..cf22833e211b4 100644 --- a/clang/test/CIR/IR/struct.cir +++ b/clang/test/CIR/IR/struct.cir @@ -25,24 +25,26 @@ // CHECK-DAG: !rec_S1 = !cir.struct<"S1" {data !s32i, data !s32i}> // CHECK-DAG: !rec_Sc = !cir.struct<"Sc" {data !u8i, data !u16i, data !u32i}> -// Packed and padded structs +// A packed struct, and a packed and unpacked pair with the same members !rec_P1 = !cir.struct<"P1" packed {data !s32i, data !s32i}> -!rec_P2 = !cir.struct<"P2" padded {data !u8i, data !u16i, data !u32i}> -!rec_P3 = !cir.struct<"P3" packed padded {data !u8i, data !u16i, data !u32i}> +!rec_P2 = !cir.struct<"P2" {data !u8i, pad !u8i, data !u16i, data !u32i}> +!rec_P3 = !cir.struct<"P3" packed {data !u8i, pad !u8i, data !u16i, data !u32i}> // Members marked pad or empty !rec_P4 = !cir.struct<"P4" {pad !u8i}> !rec_P5 = !cir.struct<"P5" {empty !u8i}> !rec_P6 = !cir.struct<"P6" {data !u32i, empty !cir.array<!u8i x 3>, pad !u8i}> -!rec_P7 = !cir.struct<"P7" packed padded {data !u8i, pad !u8i}> +!rec_P7 = !cir.struct<"P7" packed {data !u8i, pad !u8i}> +!rec_P8 = !cir.struct<"P8" {data !u16i, pad !u8i, pad !u8i}> // CHECK-DAG: !rec_P1 = !cir.struct<"P1" packed {data !s32i, data !s32i}> -// CHECK-DAG: !rec_P2 = !cir.struct<"P2" padded {data !u8i, data !u16i, data !u32i}> -// CHECK-DAG: !rec_P3 = !cir.struct<"P3" packed padded {data !u8i, data !u16i, data !u32i}> +// CHECK-DAG: !rec_P2 = !cir.struct<"P2" {data !u8i, pad !u8i, data !u16i, data !u32i}> +// CHECK-DAG: !rec_P3 = !cir.struct<"P3" packed {data !u8i, pad !u8i, data !u16i, data !u32i}> // CHECK-DAG: !rec_P4 = !cir.struct<"P4" {pad !u8i}> // CHECK-DAG: !rec_P5 = !cir.struct<"P5" {empty !u8i}> // CHECK-DAG: !rec_P6 = !cir.struct<"P6" {data !u32i, empty !cir.array<!u8i x 3>, pad !u8i}> -// CHECK-DAG: !rec_P7 = !cir.struct<"P7" packed padded {data !u8i, pad !u8i}> +// CHECK-DAG: !rec_P7 = !cir.struct<"P7" packed {data !u8i, pad !u8i}> +// CHECK-DAG: !rec_P8 = !cir.struct<"P8" {data !u16i, pad !u8i, pad !u8i}> // Records with identical member types, spelled apart by their kinds. !rec_M1 = !cir.struct<"M1" {data !u8i, pad !u8i}> @@ -124,7 +126,8 @@ module { %arg20: !rec_PadNode, %arg21: !rec_P7, %arg22: !rec_anon_u_empty, - %arg23: !rec_anon_u_plain) { + %arg23: !rec_anon_u_plain, + %arg24: !rec_P8) { cir.return } diff --git a/clang/test/CIR/Lowering/copy-skip-tail-padding.cir b/clang/test/CIR/Lowering/copy-skip-tail-padding.cir new file mode 100644 index 0000000000000..e8146a522cab1 --- /dev/null +++ b/clang/test/CIR/Lowering/copy-skip-tail-padding.cir @@ -0,0 +1,140 @@ +// RUN: cir-opt %s --cir-to-llvm -o %t.mlir +// RUN: FileCheck --input-file=%t.mlir %s + +!s8i = !cir.int<s, 8> +!u8i = !cir.int<u, 8> +!u16i = !cir.int<u, 16> +!s32i = !cir.int<s, 32> + +!rec_Plain = !cir.struct<"Plain" {data !s32i, data !s32i}> +!rec_Trail = + !cir.struct<"Trail" {data !s32i, data !u8i, pad !cir.array<!u8i x 3>}> +!rec_MultiPad = !cir.struct<"MultiPad" {data !u16i, pad !u8i, pad !u8i}> +!rec_Interior = + !cir.struct<"Interior" {data !u8i, pad !cir.array<!u8i x 3>, data !s32i}> +!rec_TailEmpty = !cir.struct<"TailEmpty" {data !u8i, empty !u8i}> +!rec_Packed = !cir.struct<"Packed" packed {data !u8i, data !s32i, pad !u8i}> +!rec_AllPad = !cir.struct<"AllPad" {pad !u8i}> +!rec_InteriorPacked = + !cir.struct<"InteriorPacked" packed {data !u8i, pad !cir.array<!u8i x 3>, + data !s32i}> +!rec_Nest = + !cir.struct<"Nest" {data !rec_Trail, data !u8i, pad !cir.array<!u8i x 3>}> +!rec_AlignasTail = + !cir.struct<"AlignasTail" {data !s8i, pad !cir.array<!u8i x 7>, data !s32i, + pad !cir.array<!u8i x 4>}> +!rec_SpanMixed = + !cir.struct<"SpanMixed" {data !u8i, pad !cir.array<!u8i x 3>, empty !u8i, + pad !cir.array<!u8i x 3>}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu", + dlti.dl_spec = #dlti.dl_spec<>} { + // A record with no pad member has no tail padding to skip. + // CHECK-LABEL: llvm.func @plain + // CHECK: %[[N:.*]] = llvm.mlir.constant(8 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @plain(%arg0: !cir.ptr<!rec_Plain>, %arg1: !cir.ptr<!rec_Plain>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_Plain> + cir.return + } + + // CHECK-LABEL: llvm.func @trail + // CHECK: %[[N:.*]] = llvm.mlir.constant(5 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @trail(%arg0: !cir.ptr<!rec_Trail>, %arg1: !cir.ptr<!rec_Trail>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_Trail> + cir.return + } + + // Every member of the trailing run drops, not only the last one. + // CHECK-LABEL: llvm.func @multi_pad + // CHECK: %[[N:.*]] = llvm.mlir.constant(2 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @multi_pad(%arg0: !cir.ptr<!rec_MultiPad>, + %arg1: !cir.ptr<!rec_MultiPad>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_MultiPad> + cir.return + } + + // Padding before a data member is not tail padding, so nothing drops. + // CHECK-LABEL: llvm.func @interior_pad + // CHECK: %[[N:.*]] = llvm.mlir.constant(8 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @interior_pad(%arg0: !cir.ptr<!rec_Interior>, + %arg1: !cir.ptr<!rec_Interior>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_Interior> + cir.return + } + + // An empty member is declared storage a derived class may not reuse, so it + // stays inside the data size. + // CHECK-LABEL: llvm.func @tail_empty + // CHECK: %[[N:.*]] = llvm.mlir.constant(2 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @tail_empty(%arg0: !cir.ptr<!rec_TailEmpty>, + %arg1: !cir.ptr<!rec_TailEmpty>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_TailEmpty> + cir.return + } + + // A packed record sums its members at alignment one. + // CHECK-LABEL: llvm.func @packed + // CHECK: %[[N:.*]] = llvm.mlir.constant(5 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @packed(%arg0: !cir.ptr<!rec_Packed>, %arg1: !cir.ptr<!rec_Packed>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_Packed> + cir.return + } + + // An empty C++ class lays out as one padding byte and has no data at all. + // CHECK-LABEL: llvm.func @all_pad + // CHECK: %[[N:.*]] = llvm.mlir.constant(0 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @all_pad(%arg0: !cir.ptr<!rec_AllPad>, + %arg1: !cir.ptr<!rec_AllPad>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_AllPad> + cir.return + } + + // Interior padding again, packed so that no realignment refills the hole. + // Dropping the pad here would change the answer. + // CHECK-LABEL: llvm.func @interior_pad_packed + // CHECK: %[[N:.*]] = llvm.mlir.constant(8 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @interior_pad_packed(%arg0: !cir.ptr<!rec_InteriorPacked>, + %arg1: !cir.ptr<!rec_InteriorPacked>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_InteriorPacked> + cir.return + } + + // Only the outermost object's tail padding is skippable, so a record member + // contributes its full size. + // CHECK-LABEL: llvm.func @nested + // CHECK: %[[N:.*]] = llvm.mlir.constant(9 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @nested(%arg0: !cir.ptr<!rec_Nest>, %arg1: !cir.ptr<!rec_Nest>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_Nest> + cir.return + } + + // Interior and trailing padding together: the run stops at the data member. + // CHECK-LABEL: llvm.func @alignas_tail + // CHECK: %[[N:.*]] = llvm.mlir.constant(12 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @alignas_tail(%arg0: !cir.ptr<!rec_AlignasTail>, + %arg1: !cir.ptr<!rec_AlignasTail>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_AlignasTail> + cir.return + } + + // The run stops at the empty member: the pad after it drops, the pad + // before it does not. + // CHECK-LABEL: llvm.func @span_mixed + // CHECK: %[[N:.*]] = llvm.mlir.constant(5 : i64) : i64 + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %[[N]]) + cir.func @span_mixed(%arg0: !cir.ptr<!rec_SpanMixed>, + %arg1: !cir.ptr<!rec_SpanMixed>) { + cir.copy %arg0 to %arg1 skip_tail_padding : !cir.ptr<!rec_SpanMixed> + cir.return + } +} diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir index ff7eacbe3f608..73153a9a596c3 100644 --- a/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir +++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir @@ -11,10 +11,10 @@ !rec_SWrapsOverAligned = !cir.struct<"SWrapsOverAligned" {data !cir.double, data !rec_UOverAligned}> !rec_UEmptyLarge = !cir.union<"UEmptyLarge" {}, padding = {!cir.array<!u8i x 32>}> !rec_P = !cir.struct<"P" packed {data !s8i, data !s32i}> -!rec_Ov = !cir.struct<"Ov" padded {data !s32i, data !cir.array<!u8i x 12>}> -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_Ov = !cir.struct<"Ov" {data !s32i, pad !cir.array<!u8i x 12>}> +!rec_E = !cir.struct<"E" {pad !u8i}> !rec_S1 = !cir.struct<"S1" {data !s16i, data !s16i, data !s16i}> -!rec_AtomicWrapper = !cir.struct<padded {data !rec_S1, pad !cir.array<!s8i x 2>}> +!rec_AtomicWrapper = !cir.struct<{data !rec_S1, pad !cir.array<!s8i x 2>}> module attributes { dlti.dl_spec = #dlti.dl_spec< @@ -93,7 +93,7 @@ module attributes { cir.return } - // CHECK: not yet implemented for type '!cir.struct<"Ov" padded + // CHECK: not yet implemented for type '!cir.struct<"Ov" {data !cir.int<s, 32>, pad // An empty C++ class is laid out as a single padded byte, so it is rejected // by the padded check; its Ignore classification is deferred. @@ -101,7 +101,7 @@ module attributes { cir.return } - // CHECK: not yet implemented for type '!cir.struct<"E" padded + // CHECK: not yet implemented for type '!cir.struct<"E" {pad // CIRGen wraps an atomic whose value is narrower than its lock-free size in // an anonymous record with a trailing pad member, which the padded check @@ -110,7 +110,7 @@ module attributes { cir.return } - // CHECK: not yet implemented for type '!cir.struct<padded {{.*}}pad !cir.array<!cir.int<s, 8> x 2>}>' + // CHECK: not yet implemented for type '!cir.struct<{{.*}}pad !cir.array<!cir.int<s, 8> x 2>}>' // A scalable vector has no size the eightbyte rules can read. cir.func @take_scalable(%arg0: !cir.vector<[4] x !cir.float>) { diff --git a/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir b/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir index ebc54e9875dea..569b1f6a87ab1 100644 --- a/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir +++ b/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir @@ -3,7 +3,7 @@ !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> -!rec_Other = !cir.struct<"Other" padded {data !u8i}> +!rec_Other = !cir.struct<"Other" {pad !u8i}> !rec_Struct = !cir.struct<"Struct" {data !cir.data_member<!s32i in !rec_Other>}> // CHECK: !rec_Struct = !cir.struct<"Struct" {data !s64i}> diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir index 25e1365b59da1..8d191bb05c8ac 100644 --- a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir +++ b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch-invalid.cir @@ -7,7 +7,7 @@ !s32i = !cir.int<s, 32> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { @@ -65,7 +65,7 @@ cir.func @bad_kind() { !s32i = !cir.int<s, 32> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { @@ -118,7 +118,7 @@ cir.func @copy_fn_no_body() { !s32i = !cir.int<s, 32> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir index 81c17ae8f64c3..25c8e5695c0d5 100644 --- a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir +++ b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir @@ -22,7 +22,7 @@ !u32i = !cir.int<u, 32> !u8i = !cir.int<u, 8> !void = !cir.void -!rec_E = !cir.struct<"E" padded {data !u8i}> +!rec_E = !cir.struct<"E" {pad !u8i}> !rec_anon_struct = !cir.struct<{data !cir.ptr<!u8i>, data !cir.ptr<!u8i>}> module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { diff --git a/clang/test/CIR/Transforms/flatten-cleanup-scope-eh.cir b/clang/test/CIR/Transforms/flatten-cleanup-scope-eh.cir index 5fc9f4fdbe42f..93b3f99188562 100644 --- a/clang/test/CIR/Transforms/flatten-cleanup-scope-eh.cir +++ b/clang/test/CIR/Transforms/flatten-cleanup-scope-eh.cir @@ -4,7 +4,7 @@ !s32i = !cir.int<s, 32> !u8i = !cir.int<u, 8> !rec_SomeClass = !cir.struct<"SomeClass" {data !s32i}> -!rec_NonTrivial = !cir.struct<"NonTrivial" padded {data !u8i}> +!rec_NonTrivial = !cir.struct<"NonTrivial" {pad !u8i}> #false = #cir.bool<false> : !cir.bool #true = #cir.bool<true> : !cir.bool diff --git a/clang/test/CIR/Transforms/flatten-loop-cleanup.cir b/clang/test/CIR/Transforms/flatten-loop-cleanup.cir index b0dded0f931a2..0db66822ad4aa 100644 --- a/clang/test/CIR/Transforms/flatten-loop-cleanup.cir +++ b/clang/test/CIR/Transforms/flatten-loop-cleanup.cir @@ -3,7 +3,7 @@ !u8i = !cir.int<u, 8> !s32i = !cir.int<s, 32> -!rec_S = !cir.struct<"S" padded {data !u8i}> +!rec_S = !cir.struct<"S" {pad !u8i}> module { cir.func private @ctor(!cir.ptr<!rec_S>) diff --git a/clang/test/CIR/Transforms/mem2reg.cir b/clang/test/CIR/Transforms/mem2reg.cir index 84f83595f1c6c..3162a3f5e09a5 100644 --- a/clang/test/CIR/Transforms/mem2reg.cir +++ b/clang/test/CIR/Transforms/mem2reg.cir @@ -1,6 +1,10 @@ // RUN: cir-opt %s -cir-flatten-cfg -mem2reg -o - | FileCheck %s !s32i = !cir.int<s, 32> +!u8i = !cir.int<u, 8> +!u16i = !cir.int<u, 16> +!rec_Whole = !cir.struct<"Whole" {data !u16i, data !u16i}> +!rec_AllPad = !cir.struct<"AllPad" {pad !u8i}> module { // Promote CIR stack slots through the generic mem2reg pass after CFG flattening. @@ -67,4 +71,27 @@ module { %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i cir.return %2 : !s32i } + + // A skip_tail_padding copy that covers the whole slot still promotes. + // CHECK-LABEL: cir.func @promote_copy_covering_slot + cir.func @promote_copy_covering_slot(%src: !cir.ptr<!rec_Whole>) -> !rec_Whole { + // CHECK-NOT: cir.alloca + // CHECK-NOT: cir.copy + %slot = cir.alloca "s" align(2) init : !cir.ptr<!rec_Whole> + cir.copy %src to %slot skip_tail_padding : !cir.ptr<!rec_Whole> + %v = cir.load %slot : !cir.ptr<!rec_Whole>, !rec_Whole + cir.return %v : !rec_Whole + } + + // An all-pad record has a data size of zero, so the copy leaves the slot's + // byte untouched and the slot cannot be promoted. + // CHECK-LABEL: cir.func @do_not_promote_partial_copy + cir.func @do_not_promote_partial_copy(%src: !cir.ptr<!rec_AllPad>) -> !rec_AllPad { + // CHECK: %[[SLOT:.*]] = cir.alloca "s" align(1) init : !cir.ptr<!rec_AllPad> + // CHECK: cir.copy %{{.+}} to %[[SLOT]] skip_tail_padding : !cir.ptr<!rec_AllPad> + %slot = cir.alloca "s" align(1) init : !cir.ptr<!rec_AllPad> + cir.copy %src to %slot skip_tail_padding : !cir.ptr<!rec_AllPad> + %v = cir.load %slot : !cir.ptr<!rec_AllPad>, !rec_AllPad + cir.return %v : !rec_AllPad + } } diff --git a/clang/unittests/CIR/PointerLikeTest.cpp b/clang/unittests/CIR/PointerLikeTest.cpp index af0faa4a866cb..8e5dc6636e01e 100644 --- a/clang/unittests/CIR/PointerLikeTest.cpp +++ b/clang/unittests/CIR/PointerLikeTest.cpp @@ -170,8 +170,7 @@ class CIROpenACCPointerLikeTest : public ::testing::Test { structTy = cir::StructType::get(&context, getUniqueRecordName("S"), /*is_class=*/false); mlir::Type members[] = {ty1, ty2}; - structTy.complete(members, /*packed=*/false, /*padded=*/false, - /*padding=*/{}, + structTy.complete(members, /*packed=*/false, /*padding=*/{}, cir::RecordType::getAllDataKinds(members)); mlir::Type ptrTy = cir::PointerType::get(structTy); @@ -255,8 +254,7 @@ class CIROpenACCPointerLikeTest : public ::testing::Test { cir::StructType::get(&context, getUniqueRecordName("S"), /*is_class=*/false); mlir::Type members[] = {ptrTy, ptrTy}; - structTy.complete(members, /*packed=*/false, /*padded=*/false, - /*padding=*/{}, + structTy.complete(members, /*packed=*/false, /*padding=*/{}, cir::RecordType::getAllDataKinds(members)); mlir::Type structPptrTy = cir::PointerType::get(structTy); @@ -368,7 +366,7 @@ TEST_F(CIROpenACCPointerLikeTest, testPointerToStructMember) { cir::StructType::get(&context, getUniqueRecordName("S"), /*is_class=*/false); mlir::Type members[] = {i32Ty, i32Ty}; - structTy.complete(members, /*packed=*/false, /*padded=*/false, - /*padding=*/{}, cir::RecordType::getAllDataKinds(members)); + structTy.complete(members, /*packed=*/false, /*padding=*/{}, + cir::RecordType::getAllDataKinds(members)); testPointerToMemberType(structTy, mlir::acc::VariableTypeCategory::composite); } diff --git a/clang/unittests/CIR/RecordMemberKindTest.cpp b/clang/unittests/CIR/RecordMemberKindTest.cpp index fd6de7a4296d4..9bbaf39c2ca17 100644 --- a/clang/unittests/CIR/RecordMemberKindTest.cpp +++ b/clang/unittests/CIR/RecordMemberKindTest.cpp @@ -53,7 +53,7 @@ class RecordMemberKindTest : public ::testing::Test { llvm::ArrayRef<mlir::Type> members, llvm::ArrayRef<RecordMemberKind> kinds) { auto ty = StructType::get(&context, getName(name), /*is_class=*/false); - ty.complete(members, /*packed=*/false, /*isPadded=*/false, kinds); + ty.complete(members, /*packed=*/false, kinds); return ty; } }; @@ -75,6 +75,42 @@ TEST_F(RecordMemberKindTest, EmptyForTheABIWhenNoMemberHoldsData) { .isEmptyForABI()); } +TEST_F(RecordMemberKindTest, PaddedFollowsThePadKinds) { + IntType u8 = getU8(); + EXPECT_FALSE(makeStruct("d", {u8}, {RecordMemberKind::Data}).getPadded()); + EXPECT_FALSE(makeStruct("e", {u8}, {RecordMemberKind::Empty}).getPadded()); + EXPECT_TRUE(makeStruct("p", {u8}, {RecordMemberKind::Pad}).getPadded()); + // Interior padding counts too, not just a trailing run. + EXPECT_TRUE(makeStruct("dpd", {u8, u8, u8}, + {RecordMemberKind::Data, RecordMemberKind::Pad, + RecordMemberKind::Data}) + .getPadded()); + // An incomplete struct has no members to read a kind from. + EXPECT_FALSE(StructType::get(&context, getName("inc"), /*is_class=*/false) + .getPadded()); +} + +TEST_F(RecordMemberKindTest, AUnionsPaddingComesFromItsPaddingSlot) { + IntType u8 = getU8(); + llvm::SmallVector<mlir::Type> members{u8}; + llvm::SmallVector<RecordMemberKind> empty{RecordMemberKind::Empty}; + llvm::ArrayRef<mlir::Type> membersRef(members); + + EXPECT_FALSE(UnionType::get(&context, membersRef, getName("ub"), + /*packed=*/false, /*padding=*/mlir::Type{}, + RecordType::getAllDataKinds(membersRef)) + .getPadded()); + EXPECT_TRUE(UnionType::get(&context, membersRef, getName("up"), + /*packed=*/false, /*padding=*/u8, + RecordType::getAllDataKinds(membersRef)) + .getPadded()); + // An empty kind on a member is not padding. + EXPECT_FALSE(UnionType::get(&context, membersRef, getName("ue"), + /*packed=*/false, /*padding=*/mlir::Type{}, + llvm::ArrayRef<RecordMemberKind>(empty)) + .getPadded()); +} + TEST_F(RecordMemberKindTest, RejectsAKindListThatDoesNotNameEveryMember) { // The assembly syntax cannot express either of these, since it builds one // kind per member, but a C++ caller can. @@ -85,15 +121,14 @@ TEST_F(RecordMemberKindTest, RejectsAKindListThatDoesNotNameEveryMember) { llvm::ArrayRef<mlir::Type> membersRef(members); llvm::ArrayRef<RecordMemberKind> kindsRef(tooFew); EXPECT_FALSE(StructType::getChecked(getLoc(), &context, membersRef, - /*packed=*/false, /*padded=*/false, - /*is_class=*/false, kindsRef)); + /*packed=*/false, /*is_class=*/false, + kindsRef)); EXPECT_EQ(diags.count, 1u); EXPECT_EQ(diags.lastMessage, "expected 2 member kinds, got 1"); // An omitted list is not shorthand for all-data. EXPECT_FALSE(StructType::getChecked(getLoc(), &context, membersRef, - /*packed=*/false, /*padded=*/false, - /*is_class=*/false, + /*packed=*/false, /*is_class=*/false, llvm::ArrayRef<RecordMemberKind>{})); EXPECT_EQ(diags.count, 2u); EXPECT_EQ(diags.lastMessage, "expected 2 member kinds, got 0"); @@ -146,12 +181,12 @@ TEST_F(RecordMemberKindTest, AUnionsTailPaddingSlotIsNotAMember) { TEST_F(RecordMemberKindTest, KindsTakePartInAnonymousTypeIdentity) { IntType u8 = getU8(); - auto kindsPad = StructType::get( - &context, {u8, u8}, /*packed=*/false, /*padded=*/false, - /*is_class=*/false, {RecordMemberKind::Data, RecordMemberKind::Pad}); - auto kindsEmpty = StructType::get( - &context, {u8, u8}, /*packed=*/false, /*padded=*/false, - /*is_class=*/false, {RecordMemberKind::Data, RecordMemberKind::Empty}); + auto kindsPad = + StructType::get(&context, {u8, u8}, /*packed=*/false, /*is_class=*/false, + {RecordMemberKind::Data, RecordMemberKind::Pad}); + auto kindsEmpty = + StructType::get(&context, {u8, u8}, /*packed=*/false, /*is_class=*/false, + {RecordMemberKind::Data, RecordMemberKind::Empty}); EXPECT_NE(kindsPad, kindsEmpty); // Kinds are provenance rather than layout. diff --git a/clang/unittests/CIR/RecordTypeMetadataTest.cpp b/clang/unittests/CIR/RecordTypeMetadataTest.cpp index b96f7ad36874a..3e7b0d9054970 100644 --- a/clang/unittests/CIR/RecordTypeMetadataTest.cpp +++ b/clang/unittests/CIR/RecordTypeMetadataTest.cpp @@ -64,8 +64,7 @@ TEST_F(RecordLayoutAttrTest, RecordTypeUnchanged) { IntType i32 = IntType::get(&context, 32, true); auto ty = StructType::get(&context, getName("Foo"), /*is_class=*/false); mlir::Type members[] = {i32, i32}; - ty.complete(members, /*packed=*/false, /*padded=*/false, - RecordType::getAllDataKinds(members)); + ty.complete(members, /*packed=*/false, RecordType::getAllDataKinds(members)); EXPECT_TRUE(ty.isComplete()); EXPECT_EQ(ty.getMembers().size(), 2u); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
