Skip to content

Commit a468e26

Browse files
el-evLancernAmrDeveloperbruteforceboyAdUhTkJm
authored andcommitted
[CIR] Refactor StructType with TableGen (#1504)
Closes #1367 --------- Co-authored-by: Sirui Mu <[email protected]> Co-authored-by: Amr Hesham <[email protected]> Co-authored-by: Chibuoyim (Wilson) Ogbonna <[email protected]> Co-authored-by: Yue Huang <[email protected]> Co-authored-by: Morris Hafner <[email protected]> Co-authored-by: Morris Hafner <[email protected]> Co-authored-by: Sharp-Edged <[email protected]> Co-authored-by: Bruno Cardoso Lopes <[email protected]> Co-authored-by: Letu Ren <[email protected]>
1 parent 3af8b3f commit a468e26

File tree

4 files changed

+166
-219
lines changed

4 files changed

+166
-219
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,7 +2918,7 @@ def ExtractMemberOp : CIR_Op<"extract_member", [Pure]> {
29182918
```
29192919
}];
29202920

2921-
let arguments = (ins CIR_StructType:$record, IndexAttr:$index_attr);
2921+
let arguments = (ins CIRStructType:$record, IndexAttr:$index_attr);
29222922
let results = (outs CIR_AnyType:$result);
29232923

29242924
let assemblyFormat = [{
@@ -2982,9 +2982,9 @@ def InsertMemberOp : CIR_Op<"insert_member",
29822982
```
29832983
}];
29842984

2985-
let arguments = (ins CIR_StructType:$record, IndexAttr:$index_attr,
2985+
let arguments = (ins CIRStructType:$record, IndexAttr:$index_attr,
29862986
CIR_AnyType:$value);
2987-
let results = (outs CIR_StructType:$result);
2987+
let results = (outs CIRStructType:$result);
29882988

29892989
let builders = [
29902990
OpBuilder<(ins "mlir::Value":$record, "uint64_t":$index,

clang/include/clang/CIR/Dialect/IR/CIRTypes.h

Lines changed: 2 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -16,173 +16,15 @@
1616
#include "mlir/IR/BuiltinAttributes.h"
1717
#include "mlir/IR/Types.h"
1818
#include "mlir/Interfaces/DataLayoutInterfaces.h"
19-
#include "clang/CIR/Interfaces/CIRFPTypeInterface.h"
20-
21-
#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"
22-
2319
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
24-
25-
//===----------------------------------------------------------------------===//
26-
// CIR StructType
27-
//
28-
// The base type for all RecordDecls.
29-
//===----------------------------------------------------------------------===//
20+
#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"
21+
#include "clang/CIR/Interfaces/CIRFPTypeInterface.h"
3022

3123
namespace cir {
32-
3324
namespace detail {
3425
struct StructTypeStorage;
3526
} // namespace detail
3627

37-
/// Each unique clang::RecordDecl is mapped to a `cir.struct` and any object in
38-
/// C/C++ that has a struct type will have a `cir.struct` in CIR.
39-
///
40-
/// There are three possible formats for this type:
41-
///
42-
/// - Identified and complete structs: unique name and a known body.
43-
/// - Identified and incomplete structs: unique name and unknown body.
44-
/// - Anonymous structs: no name and a known body.
45-
///
46-
/// Identified structs are uniqued by their name, and anonymous structs are
47-
/// uniqued by their body. This means that two anonymous structs with the same
48-
/// body will be the same type, and two identified structs with the same name
49-
/// will be the same type. Attempting to build a struct with an existing name,
50-
/// but a different body will result in an error.
51-
///
52-
/// A few examples:
53-
///
54-
/// ```mlir
55-
/// !complete = !cir.struct<struct "complete" {!cir.int<u, 8>}>
56-
/// !incomplete = !cir.struct<struct "incomplete" incomplete>
57-
/// !anonymous = !cir.struct<struct {!cir.int<u, 8>}>
58-
/// ```
59-
///
60-
/// Incomplete structs are mutable, meaning they can be later completed with a
61-
/// body automatically updating in place every type in the code that uses the
62-
/// incomplete struct. Mutability allows for recursive types to be represented,
63-
/// meaning the struct can have members that refer to itself. This is useful for
64-
/// representing recursive records and is implemented through a special syntax.
65-
/// In the example below, the `Node` struct has a member that is a pointer to a
66-
/// `Node` struct:
67-
///
68-
/// ```mlir
69-
/// !struct = !cir.struct<struct "Node" {!cir.ptr<!cir.struct<struct
70-
/// "Node">>}>
71-
/// ```
72-
class StructType
73-
: public mlir::Type::TypeBase<
74-
StructType, mlir::Type, detail::StructTypeStorage,
75-
mlir::DataLayoutTypeInterface::Trait, mlir::TypeTrait::IsMutable> {
76-
// FIXME(cir): migrate this type to Tablegen once mutable types are supported.
77-
public:
78-
using Base::Base;
79-
using Base::getChecked;
80-
using Base::verifyInvariants;
81-
82-
static constexpr llvm::StringLiteral name = "cir.struct";
83-
84-
enum RecordKind : uint32_t { Class, Union, Struct };
85-
86-
/// Create an identified and complete struct type.
87-
static StructType get(mlir::MLIRContext *context,
88-
llvm::ArrayRef<mlir::Type> members,
89-
mlir::StringAttr name, bool packed, bool padded,
90-
RecordKind kind, ASTRecordDeclInterface ast = {});
91-
static StructType
92-
getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
93-
mlir::MLIRContext *context, llvm::ArrayRef<mlir::Type> members,
94-
mlir::StringAttr name, bool packed, bool padded, RecordKind kind,
95-
ASTRecordDeclInterface ast = {});
96-
97-
/// Create an identified and incomplete struct type.
98-
static StructType get(mlir::MLIRContext *context, mlir::StringAttr name,
99-
RecordKind kind);
100-
static StructType
101-
getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
102-
mlir::MLIRContext *context, mlir::StringAttr name,
103-
RecordKind kind);
104-
105-
/// Create an anonymous struct type (always complete).
106-
static StructType get(mlir::MLIRContext *context,
107-
llvm::ArrayRef<mlir::Type> members, bool packed,
108-
bool padded, RecordKind kind,
109-
ASTRecordDeclInterface ast = {});
110-
static StructType
111-
getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
112-
mlir::MLIRContext *context, llvm::ArrayRef<mlir::Type> members,
113-
bool packed, bool padded, RecordKind kind,
114-
ASTRecordDeclInterface ast = {});
115-
116-
/// Validate the struct about to be constructed.
117-
static llvm::LogicalResult
118-
verifyInvariants(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
119-
llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
120-
bool incomplete, bool packed, bool padded,
121-
StructType::RecordKind kind, ASTRecordDeclInterface ast);
122-
123-
// Parse/print methods.
124-
static constexpr llvm::StringLiteral getMnemonic() { return {"struct"}; }
125-
static mlir::Type parse(mlir::AsmParser &odsParser);
126-
void print(mlir::AsmPrinter &odsPrinter) const;
127-
128-
// Accessors
129-
ASTRecordDeclInterface getAst() const;
130-
llvm::ArrayRef<mlir::Type> getMembers() const;
131-
mlir::StringAttr getName() const;
132-
StructType::RecordKind getKind() const;
133-
bool getIncomplete() const;
134-
bool getPacked() const;
135-
bool getPadded() const;
136-
void dropAst();
137-
138-
// Predicates
139-
bool isClass() const { return getKind() == RecordKind::Class; };
140-
bool isStruct() const { return getKind() == RecordKind::Struct; };
141-
bool isUnion() const { return getKind() == RecordKind::Union; };
142-
bool isComplete() const { return !isIncomplete(); };
143-
bool isIncomplete() const;
144-
145-
// Utilities
146-
mlir::Type getLargestMember(const mlir::DataLayout &dataLayout) const;
147-
size_t getNumElements() const { return getMembers().size(); };
148-
std::string getKindAsStr() {
149-
switch (getKind()) {
150-
case RecordKind::Class:
151-
return "class";
152-
case RecordKind::Union:
153-
return "union";
154-
case RecordKind::Struct:
155-
return "struct";
156-
}
157-
llvm_unreachable("Invalid value for StructType::getKind()");
158-
}
159-
std::string getPrefixedName() {
160-
return getKindAsStr() + "." + getName().getValue().str();
161-
}
162-
163-
/// Complete the struct type by mutating its members and attributes.
164-
void complete(llvm::ArrayRef<mlir::Type> members, bool packed, bool isPadded,
165-
ASTRecordDeclInterface ast = {});
166-
167-
/// DataLayoutTypeInterface methods.
168-
llvm::TypeSize getTypeSizeInBits(const mlir::DataLayout &dataLayout,
169-
mlir::DataLayoutEntryListRef params) const;
170-
uint64_t getABIAlignment(const mlir::DataLayout &dataLayout,
171-
mlir::DataLayoutEntryListRef params) const;
172-
uint64_t getElementOffset(const mlir::DataLayout &dataLayout,
173-
unsigned idx) const;
174-
175-
bool isLayoutIdentical(const StructType &other);
176-
177-
// Utilities for lazily computing and cacheing data layout info.
178-
private:
179-
// FIXME: currently opaque because there's a cycle if CIRTypes.types include
180-
// from CIRAttrs.h. The implementation operates in terms of StructLayoutAttr
181-
// instead.
182-
mutable mlir::Attribute layoutInfo;
183-
void computeSizeAndAlignment(const mlir::DataLayout &dataLayout) const;
184-
};
185-
18628
bool isAnyFloatingPointType(mlir::Type t);
18729
bool isScalarType(mlir::Type t);
18830
bool isFPOrFPVectorTy(mlir::Type);

clang/include/clang/CIR/Dialect/IR/CIRTypes.td

Lines changed: 156 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,164 @@ def FuncPtr : Type<
603603
}
604604

605605
//===----------------------------------------------------------------------===//
606-
// StructType (defined in cpp files)
606+
// StructType
607+
//
608+
// The base type for all RecordDecls.
607609
//===----------------------------------------------------------------------===//
608610

609-
def CIR_StructType : Type<CPred<"::mlir::isa<::cir::StructType>($_self)">,
610-
"CIR struct type">;
611+
def CIR_StructType : CIR_Type<"Struct", "struct",
612+
[
613+
DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
614+
MutableType,
615+
]> {
616+
let summary = "CIR struct type";
617+
let description = [{
618+
Each unique clang::RecordDecl is mapped to a `cir.struct` and any object in
619+
C/C++ that has a struct type will have a `cir.struct` in CIR.
620+
621+
There are three possible formats for this type:
622+
623+
- Identified and complete structs: unique name and a known body.
624+
- Identified and incomplete structs: unique name and unknown body.
625+
- Anonymous structs: no name and a known body.
626+
627+
Identified structs are uniqued by their name, and anonymous structs are
628+
uniqued by their body. This means that two anonymous structs with the same
629+
body will be the same type, and two identified structs with the same name
630+
will be the same type. Attempting to build a struct with an existing name,
631+
but a different body will result in an error.
632+
633+
A few examples:
634+
635+
```mlir
636+
!complete = !cir.struct<struct "complete" {!cir.int<u, 8>}>
637+
!incomplete = !cir.struct<struct "incomplete" incomplete>
638+
!anonymous = !cir.struct<struct {!cir.int<u, 8>}>
639+
```
640+
641+
Incomplete structs are mutable, meaning they can be later completed with a
642+
body automatically updating in place every type in the code that uses the
643+
incomplete struct. Mutability allows for recursive types to be represented,
644+
meaning the struct can have members that refer to itself. This is useful for
645+
representing recursive records and is implemented through a special syntax.
646+
In the example below, the `Node` struct has a member that is a pointer to a
647+
`Node` struct:
648+
649+
```mlir
650+
!struct = !cir.struct<struct "Node" {!cir.ptr<!cir.struct<struct
651+
"Node">>}>
652+
```
653+
}];
654+
655+
let parameters = (ins
656+
OptionalArrayRefParameter<"mlir::Type">:$members,
657+
OptionalParameter<"mlir::StringAttr">:$name,
658+
"bool":$incomplete,
659+
"bool":$packed,
660+
"bool":$padded,
661+
"StructType::RecordKind":$kind,
662+
OptionalParameter<"ASTRecordDeclInterface">:$ast
663+
);
664+
665+
// StorageClass is defined in C++ for mutability.
666+
let storageClass = "StructTypeStorage";
667+
let genStorageClass = 0;
668+
669+
let skipDefaultBuilders = 1;
670+
let genVerifyDecl = 1;
671+
672+
let builders = [
673+
// Create an identified and complete struct type.
674+
TypeBuilder<(ins
675+
"llvm::ArrayRef<mlir::Type>":$members,
676+
"mlir::StringAttr":$name,
677+
"bool":$packed,
678+
"bool":$padded,
679+
"RecordKind":$kind,
680+
CArg<"ASTRecordDeclInterface", "{}">:$ast
681+
), [{
682+
return $_get($_ctxt, members, name, /*incomplete=*/false, packed, padded,
683+
kind, ast);
684+
}]>,
685+
686+
// Create an identified and incomplete struct type.
687+
TypeBuilder<(ins
688+
"mlir::StringAttr":$name,
689+
"RecordKind":$kind
690+
), [{
691+
return $_get($_ctxt, /*members=*/llvm::ArrayRef<Type>{}, name,
692+
/*incomplete=*/true, /*packed=*/false,
693+
/*padded=*/false, kind,
694+
/*ast=*/ASTRecordDeclInterface{});
695+
}]>,
696+
697+
// Create an anonymous struct type (always complete).
698+
TypeBuilder<(ins
699+
"llvm::ArrayRef<mlir::Type>":$members,
700+
"bool":$packed,
701+
"bool":$padded,
702+
"RecordKind":$kind,
703+
CArg<"ASTRecordDeclInterface", "{}">:$ast
704+
), [{
705+
return $_get($_ctxt, members, mlir::StringAttr{}, /*incomplete=*/false,
706+
packed, padded, kind, ast);
707+
}]>];
708+
709+
let extraClassDeclaration = [{
710+
using Base::verifyInvariants;
711+
712+
enum RecordKind : uint32_t { Class, Union, Struct };
713+
714+
bool isClass() const { return getKind() == RecordKind::Class; };
715+
bool isStruct() const { return getKind() == RecordKind::Struct; };
716+
bool isUnion() const { return getKind() == RecordKind::Union; };
717+
bool isComplete() const { return !isIncomplete(); };
718+
bool isIncomplete() const;
719+
720+
void dropAst();
721+
722+
mlir::Type getLargestMember(const mlir::DataLayout &dataLayout) const;
723+
size_t getNumElements() const { return getMembers().size(); };
724+
std::string getKindAsStr() {
725+
switch (getKind()) {
726+
case RecordKind::Class:
727+
return "class";
728+
case RecordKind::Union:
729+
return "union";
730+
case RecordKind::Struct:
731+
return "struct";
732+
}
733+
llvm_unreachable("Invalid value for StructType::getKind()");
734+
}
735+
std::string getPrefixedName() {
736+
return getKindAsStr() + "." + getName().getValue().str();
737+
}
738+
739+
void complete(llvm::ArrayRef<mlir::Type> members, bool packed,
740+
bool isPadded, ASTRecordDeclInterface ast = {});
741+
742+
uint64_t getElementOffset(const mlir::DataLayout &dataLayout,
743+
unsigned idx) const;
744+
745+
bool isLayoutIdentical(const StructType &other);
746+
747+
// Utilities for lazily computing and cacheing data layout info.
748+
// FIXME: currently opaque because there's a cycle if CIRTypes.types include
749+
// from CIRAttrs.h. The implementation operates in terms of StructLayoutAttr
750+
// instead.
751+
private:
752+
mutable mlir::Attribute layoutInfo;
753+
void computeSizeAndAlignment(const mlir::DataLayout &dataLayout) const;
754+
public:
755+
}];
756+
757+
let hasCustomAssemblyFormat = 1;
758+
}
759+
760+
// Note CIRStructType is used instead of CIR_StructType
761+
// because of tablegen conflicts.
762+
def CIRStructType : Type<
763+
CPred<"::mlir::isa<::cir::StructType>($_self)">, "CIR struct type">;
611764

612765
//===----------------------------------------------------------------------===//
613766
// Global type constraints

0 commit comments

Comments
 (0)