diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 1286225f04aa..7f09e9fcf973 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -20,10 +20,125 @@ #include "clang/CIR/Interfaces/ASTAttrInterfaces.h" //===----------------------------------------------------------------------===// -// CIR Dialect Types +// CIR Dialect Tablegen'd Types //===----------------------------------------------------------------------===// #define GET_TYPEDEF_CLASSES #include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc" +//===----------------------------------------------------------------------===// +// CIR StructType +// +// The base type for all RecordDecls. +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace cir { + +namespace detail { +struct StructTypeStorage; +} // namespace detail + +/// Each unique clang::RecordDecl is mapped to a `cir.struct` and any object in +/// C/C++ that has a struct type will have a `cir.struct` in CIR. +class StructType + : public Type::TypeBase { + // FIXME(cir): migrate this type to Tablegen once mutable types are supported. +public: + using Base::Base; + using Base::getChecked; + using Base::verify; + + enum RecordKind : uint32_t { Class, Union, Struct }; + + /// Create a identified and complete struct type. + static StructType get(MLIRContext *context, ArrayRef members, + StringAttr name, bool packed, RecordKind kind, + ASTRecordDeclInterface ast = {}); + static StructType getChecked(function_ref emitError, + MLIRContext *context, ArrayRef members, + StringAttr name, bool packed, RecordKind kind, + ASTRecordDeclInterface ast = {}); + + /// Create a identified and incomplete struct type. + static StructType get(MLIRContext *context, StringAttr name, RecordKind kind); + static StructType getChecked(function_ref emitError, + MLIRContext *context, StringAttr name, + RecordKind kind); + + /// Create a anonymous struct type (always complete). + static StructType get(MLIRContext *context, ArrayRef members, + bool packed, RecordKind kind, + ASTRecordDeclInterface ast = {}); + static StructType getChecked(function_ref emitError, + MLIRContext *context, ArrayRef members, + bool packed, RecordKind kind, + ASTRecordDeclInterface ast = {}); + + /// Validate the struct about to be constructed. + static LogicalResult verify(function_ref emitError, + ArrayRef members, StringAttr name, + bool incomplete, bool packed, + StructType::RecordKind kind, + ASTRecordDeclInterface ast); + + // Parse/print methods. + static constexpr StringLiteral getMnemonic() { return {"struct"}; } + static Type parse(AsmParser &odsParser); + void print(AsmPrinter &odsPrinter) const; + + // Accessors + ASTRecordDeclInterface getAst() const; + ArrayRef getMembers() const; + StringAttr getName() const; + StructType::RecordKind getKind() const; + bool getIncomplete() const; + bool getPacked() const; + void dropAst(); + + // Predicates + bool isClass() const { return getKind() == RecordKind::Class; }; + bool isStruct() const { return getKind() == RecordKind::Struct; }; + bool isUnion() const { return getKind() == RecordKind::Union; }; + bool isComplete() const { return !isIncomplete(); }; + bool isIncomplete() const; + + // Utilities + Type getLargestMember(const DataLayout &dataLayout) const; + size_t getNumElements() const { return getMembers().size(); }; + std::string getKindAsStr() { + switch (getKind()) { + case RecordKind::Class: + return "class"; + case RecordKind::Union: + return "union"; + case RecordKind::Struct: + return "struct"; + } + } + std::string getPrefixedName() { + return getKindAsStr() + "." + getName().getValue().str(); + } + + /// DataLayoutTypeInterface methods. + unsigned getTypeSizeInBits(const DataLayout &dataLayout, + DataLayoutEntryListRef params) const; + unsigned getABIAlignment(const DataLayout &dataLayout, + DataLayoutEntryListRef params) const; + unsigned getPreferredAlignment(const DataLayout &dataLayout, + DataLayoutEntryListRef params) const; + + // Utilities for lazily computing and cacheing data layout info. +private: + mutable Type largestMember{}; + mutable std::optional padded{}; + mutable std::optional size{}, align{}; + bool isPadded(const DataLayout &dataLayout) const; + void computeSizeAndAlignment(const DataLayout &dataLayout) const; +}; + +} // namespace cir +} // namespace mlir + #endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 0e6670bf18c6..bcbb63218e22 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -90,121 +90,6 @@ def CIR_BoolType : let hasCustomAssemblyFormat = 1; } -//===----------------------------------------------------------------------===// -// StructType -// -// The base type for all RecordDecls. -// -//===----------------------------------------------------------------------===// - -def CIR_StructType : CIR_Type<"Struct", "struct", - [DeclareTypeInterfaceMethods]> { - - let summary = "CIR struct type"; - let description = [{ - Each unique clang::RecordDecl is mapped to a `cir.struct` and any object in - C/C++ that has a struct type will have a `cir.struct` in CIR. - }]; - - let parameters = (ins - ArrayRefParameter<"mlir::Type", "members">:$members, - "mlir::StringAttr":$name, - "bool":$incomplete, - "bool":$packed, - "mlir::cir::StructType::RecordKind":$kind, - "ASTRecordDeclInterface":$ast - ); - - let skipDefaultBuilders = 1; - let genVerifyDecl = 1; - let builders = [ - // Build an identified and complete struct. - TypeBuilder<(ins - "ArrayRef":$members, - "StringAttr":$name, - "bool":$packed, - "RecordKind":$kind, - CArg<"ASTRecordDeclInterface", "nullptr">:$ast), [{ - return $_get(context, members, name, /*incomplete=*/false, - packed, kind, ast); - }]>, - // Build an incomplete struct. - TypeBuilder<(ins - "StringAttr":$name, - "RecordKind":$kind), [{ - return $_get(context, /*members=*/ArrayRef{}, name, - /*incomplete=*/true, /*packed=*/false, kind, - /*ast=*/nullptr); - }]>, - // Build an anonymous struct. - TypeBuilder<(ins - "ArrayRef":$members, - "bool":$packed, - "RecordKind":$kind, - CArg<"ASTRecordDeclInterface", "nullptr">:$ast), [{ - return $_get(context, members, /*name=*/nullptr, - /*incomplete=*/false, packed, kind, ast); - }]> - ]; - - let hasCustomAssemblyFormat = 1; - - let extraClassDeclaration = [{ - enum RecordKind : uint32_t { - Class, - Union, - Struct - }; - - private: - // All these support lazily computation and storage - // for the struct size and alignment. - mutable std::optional size{}, align{}; - mutable std::optional padded{}; - mutable mlir::Type largestMember{}; - void computeSizeAndAlignment(const ::mlir::DataLayout &dataLayout) const; - public: - void dropAst(); - size_t getNumElements() const { return getMembers().size(); } - bool isIncomplete() const { return getIncomplete(); } - bool isComplete() const { return !getIncomplete(); } - bool isPadded(const ::mlir::DataLayout &dataLayout) const; - - std::string getKindAsStr() { - switch (getKind()) { - case RecordKind::Class: - return "class"; - case RecordKind::Union: - return "union"; - case RecordKind::Struct: - return "struct"; - } - } - - std::string getPrefixedName() { - return getKindAsStr() + "." + getName().getValue().str(); - } - - /// Return the member with the largest bit-length. - mlir::Type getLargestMember(const ::mlir::DataLayout &dataLayout) const; - - /// Return whether this is a class declaration. - bool isClass() const { return getKind() == RecordKind::Class; } - - /// Return whether this is a union declaration. - bool isUnion() const { return getKind() == RecordKind::Union; } - - /// Return whether this is a struct declaration. - bool isStruct() const { return getKind() == RecordKind::Struct; } - }]; - - let extraClassDefinition = [{ - void $cppClass::dropAst() { - getImpl()->ast = nullptr; - } - }]; -} - //===----------------------------------------------------------------------===// // ArrayType //===----------------------------------------------------------------------===// @@ -295,11 +180,4 @@ def CIR_VoidType : CIR_Type<"Void", "void"> { }]; } -//===----------------------------------------------------------------------===// -// One type to bind them all -//===----------------------------------------------------------------------===// - -def CIR_AnyCIRType : AnyTypeOf<[CIR_PointerType, CIR_BoolType, CIR_StructType, - CIR_ArrayType, CIR_FuncType, CIR_VoidType]>; - #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h b/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h new file mode 100644 index 000000000000..d33d43c346d5 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h @@ -0,0 +1,83 @@ +//===- CIRTypesDetails.h - Details of CIR dialect types -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains implementation details, such as storage structures, of +// CIR dialect types. +// +//===----------------------------------------------------------------------===// +#ifndef CIR_DIALECT_IR_CIRTYPESDETAILS_H +#define CIR_DIALECT_IR_CIRTYPESDETAILS_H + +#include "mlir/IR/BuiltinAttributes.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +namespace mlir { +namespace cir { +namespace detail { + +//===----------------------------------------------------------------------===// +// CIR StructTypeStorage +//===----------------------------------------------------------------------===// + +/// Type storage for CIR record types. +struct StructTypeStorage : public TypeStorage { + struct KeyTy { + ArrayRef members; + StringAttr name; + bool incomplete; + bool packed; + StructType::RecordKind kind; + ASTRecordDeclInterface ast; + + KeyTy(ArrayRef members, StringAttr name, bool incomplete, bool packed, + StructType::RecordKind kind, ASTRecordDeclInterface ast) + : members(members), name(name), incomplete(incomplete), packed(packed), + kind(kind), ast(ast) {} + }; + + ArrayRef members; + StringAttr name; + bool incomplete; + bool packed; + StructType::RecordKind kind; + ASTRecordDeclInterface ast; + + StructTypeStorage(ArrayRef members, StringAttr name, bool incomplete, + bool packed, StructType::RecordKind kind, + ASTRecordDeclInterface ast) + : members(members), name(name), incomplete(incomplete), packed(packed), + kind(kind), ast(ast) {} + + KeyTy getAsKey() const { + return KeyTy(members, name, incomplete, packed, kind, ast); + } + + bool operator==(const KeyTy &key) const { + return (members == key.members) && (name == key.name) && + (incomplete == key.incomplete) && (packed == key.packed) && + (kind == key.kind) && (ast == key.ast); + } + + static llvm::hash_code hashKey(const KeyTy &key) { + return hash_combine(key.members, key.name, key.incomplete, key.packed, + key.kind, key.ast); + } + + static StructTypeStorage *construct(TypeStorageAllocator &allocator, + const KeyTy &key) { + return new (allocator.allocate()) + StructTypeStorage(allocator.copyInto(key.members), key.name, + key.incomplete, key.packed, key.kind, key.ast); + } +}; + +} // namespace detail +} // namespace cir +} // namespace mlir + +#endif // CIR_DIALECT_IR_CIRTYPESDETAILS_H diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index cf297de6f0bf..4a6829f45402 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -13,6 +13,7 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypesDetails.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/BuiltinAttributes.h" @@ -58,17 +59,36 @@ Type CIRDialect::parseType(DialectAsmParser &parser) const { llvm::SMLoc typeLoc = parser.getCurrentLocation(); StringRef mnemonic; Type genType; + + // Try to parse as a tablegen'd type. OptionalParseResult parseResult = generatedTypeParser(parser, &mnemonic, genType); if (parseResult.has_value()) return genType; - parser.emitError(typeLoc, "unknown type in CIR dialect"); - return Type(); + + // Type is not tablegen'd: try to parse as a raw C++ type. + return StringSwitch>(mnemonic) + .Case("struct", [&] { return StructType::parse(parser); }) + .Default([&] { + parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic; + return Type(); + })(); } void CIRDialect::printType(Type type, DialectAsmPrinter &os) const { - if (failed(generatedTypePrinter(type, os))) - llvm_unreachable("unexpected CIR type kind"); + // Try to print as a tablegen'd type. + if (generatedTypePrinter(type, os).succeeded()) + return; + + // Type is not tablegen'd: try printing as a raw C++ type. + TypeSwitch(type) + .Case([&](StructType type) { + os << type.getMnemonic(); + type.print(os); + }) + .Default([](Type) { + llvm::report_fatal_error("printer is missing a handler for this type"); + }); } Type PointerType::parse(mlir::AsmParser &parser) { @@ -224,6 +244,70 @@ StructType::verify(llvm::function_ref emitError, return mlir::success(); } +void StructType::dropAst() { getImpl()->ast = nullptr; } +StructType StructType::get(::mlir::MLIRContext *context, ArrayRef members, + StringAttr name, bool packed, RecordKind kind, + ASTRecordDeclInterface ast) { + return Base::get(context, members, name, /*incomplete=*/false, packed, kind, + ast); +} + +StructType StructType::getChecked( + ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, + ::mlir::MLIRContext *context, ArrayRef members, StringAttr name, + bool packed, RecordKind kind, ASTRecordDeclInterface ast) { + return Base::getChecked(emitError, context, members, name, + /*incomplete=*/false, packed, kind, ast); +} + +StructType StructType::get(::mlir::MLIRContext *context, StringAttr name, + RecordKind kind) { + return Base::get(context, /*members=*/ArrayRef{}, name, + /*incomplete=*/true, /*packed=*/false, kind, + /*ast=*/ASTRecordDeclInterface{}); +} + +StructType StructType::getChecked( + ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, + ::mlir::MLIRContext *context, StringAttr name, RecordKind kind) { + return Base::getChecked(emitError, context, ArrayRef{}, name, + /*incomplete=*/true, /*packed=*/false, kind, + ASTRecordDeclInterface{}); +} + +StructType StructType::get(::mlir::MLIRContext *context, ArrayRef members, + bool packed, RecordKind kind, + ASTRecordDeclInterface ast) { + return Base::get(context, members, StringAttr{}, /*incomplete=*/false, packed, + kind, ast); +} + +StructType StructType::getChecked( + ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, + ::mlir::MLIRContext *context, ArrayRef members, bool packed, + RecordKind kind, ASTRecordDeclInterface ast) { + return Base::getChecked(emitError, context, members, StringAttr{}, + /*incomplete=*/false, packed, kind, ast); +} + +::llvm::ArrayRef StructType::getMembers() const { + return getImpl()->members; +} + +bool StructType::isIncomplete() const { return getImpl()->incomplete; } + +mlir::StringAttr StructType::getName() const { return getImpl()->name; } + +bool StructType::getIncomplete() const { return getImpl()->incomplete; } + +bool StructType::getPacked() const { return getImpl()->packed; } + +mlir::cir::StructType::RecordKind StructType::getKind() const { + return getImpl()->kind; +} + +ASTRecordDeclInterface StructType::getAst() const { return getImpl()->ast; } + //===----------------------------------------------------------------------===// // Data Layout information for types //===----------------------------------------------------------------------===// @@ -534,8 +618,12 @@ bool FuncType::isVoid() const { return getReturnType().isa(); } //===----------------------------------------------------------------------===// void CIRDialect::registerTypes() { + // Register tablegen'd types. addTypes< #define GET_TYPEDEF_LIST #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" >(); + + // Register raw C++ types. + addTypes(); }