Skip to content

Commit 68a346f

Browse files
authored
[CIR] Introduce cir::RecordKind::Class (#142690)
When cir::RecordType was initially upstreamed, we decided that there was no reason to distinguish between RecordKind::Class and RecordKind::Struct since they are semantically equivalent. I think this was a mistake because classic codegen does preserve the distinction (which is visible in the AST) and preserving the distinction in CIR will aid the possibility of eventually using the classic codegen lit tests with CIR. This change introduces RecordKind::Class, which is already present in the incubator implementation.
1 parent 8a905ba commit 68a346f

File tree

6 files changed

+55
-1
lines changed

6 files changed

+55
-1
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ def CIR_RecordType : CIR_Type<"Record", "record",
431431
will be the same type. Attempting to build a record with an existing name,
432432
but a different body will result in an error.
433433

434+
Each record type will have a `RecordKind` that is either `Class`, `Struct`,
435+
or `Union`, depending on the C/C++ type that it is representing. Note that
436+
`Class` and `Struct` are semantically identical, but the kind preserves the
437+
keyword that was used to declare the type in the original source code.
438+
434439
A few examples:
435440

436441
```mlir
@@ -482,8 +487,9 @@ def CIR_RecordType : CIR_Type<"Record", "record",
482487
let extraClassDeclaration = [{
483488
using Base::verifyInvariants;
484489

485-
enum RecordKind : uint32_t { Struct, Union };
490+
enum RecordKind : uint32_t { Class, Struct, Union };
486491

492+
bool isClass() const { return getKind() == RecordKind::Class; };
487493
bool isStruct() const { return getKind() == RecordKind::Struct; };
488494
bool isUnion() const { return getKind() == RecordKind::Union; };
489495
bool isComplete() const { return !isIncomplete(); };
@@ -493,6 +499,8 @@ def CIR_RecordType : CIR_Type<"Record", "record",
493499
size_t getNumElements() const { return getMembers().size(); };
494500
std::string getKindAsStr() {
495501
switch (getKind()) {
502+
case RecordKind::Class:
503+
return "class";
496504
case RecordKind::Union:
497505
return "union";
498506
case RecordKind::Struct:

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
8383
cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
8484
switch (kind) {
8585
case clang::TagTypeKind::Class:
86+
return cir::RecordType::Class;
8687
case clang::TagTypeKind::Struct:
8788
return cir::RecordType::Struct;
8889
case clang::TagTypeKind::Union:

clang/lib/CIR/Dialect/IR/CIRTypes.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ Type RecordType::parse(mlir::AsmParser &parser) {
9898
kind = RecordKind::Struct;
9999
else if (parser.parseOptionalKeyword("union").succeeded())
100100
kind = RecordKind::Union;
101+
else if (parser.parseOptionalKeyword("class").succeeded())
102+
kind = RecordKind::Class;
101103
else {
102104
parser.emitError(loc, "unknown record type");
103105
return {};
@@ -168,6 +170,9 @@ void RecordType::print(mlir::AsmPrinter &printer) const {
168170
case RecordKind::Union:
169171
printer << "union ";
170172
break;
173+
case RecordKind::Class:
174+
printer << "class ";
175+
break;
171176
}
172177

173178
if (getName())

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,7 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
15841584
// Convert struct members.
15851585
llvm::SmallVector<mlir::Type> llvmMembers;
15861586
switch (type.getKind()) {
1587+
case cir::RecordType::Class:
15871588
case cir::RecordType::Struct:
15881589
for (mlir::Type ty : type.getMembers())
15891590
llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));
@@ -1767,6 +1768,7 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(
17671768
assert(recordTy && "expected record type");
17681769

17691770
switch (recordTy.getKind()) {
1771+
case cir::RecordType::Class:
17701772
case cir::RecordType::Struct: {
17711773
// Since the base address is a pointer to an aggregate, the first offset
17721774
// is always zero. The second offset tell us which member it will access.

clang/test/CIR/CodeGen/class.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
7+
8+
// CIR: !rec_IncompleteC = !cir.record<class "IncompleteC" incomplete>
9+
// CIR: !rec_CompleteC = !cir.record<class "CompleteC" {!s32i, !s8i}>
10+
11+
// Note: LLVM and OGCG do not emit the type for incomplete classes.
12+
13+
// LLVM: %class.CompleteC = type { i32, i8 }
14+
15+
// OGCG: %class.CompleteC = type { i32, i8 }
16+
17+
class IncompleteC;
18+
IncompleteC *p;
19+
20+
// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteC>
21+
// LLVM: @p = global ptr null
22+
// OGCG: @p = global ptr null, align 8
23+
24+
class CompleteC {
25+
public:
26+
int a;
27+
char b;
28+
};
29+
30+
CompleteC cc;
31+
32+
// CIR: cir.global external @cc = #cir.zero : !rec_CompleteC
33+
// LLVM: @cc = global %class.CompleteC zeroinitializer
34+
// OGCG: @cc = global %class.CompleteC zeroinitializer

clang/test/CIR/IR/struct.cir

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
// RUN: cir-opt %s | FileCheck %s
22

3+
!rec_C = !cir.record<class "C" incomplete>
34
!rec_S = !cir.record<struct "S" incomplete>
45
!rec_U = !cir.record<union "U" incomplete>
56

7+
// CHECK: !rec_C = !cir.record<class "C" incomplete>
68
// CHECK: !rec_S = !cir.record<struct "S" incomplete>
79
// CHECK: !rec_U = !cir.record<union "U" incomplete>
810

911
module {
1012
cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
1113
cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
14+
cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>
1215
}
1316

1417
// CHECK: cir.global external @p1 = #cir.ptr<null> : !cir.ptr<!rec_S>
1518
// CHECK: cir.global external @p2 = #cir.ptr<null> : !cir.ptr<!rec_U>
19+
// CHECK: cir.global external @p3 = #cir.ptr<null> : !cir.ptr<!rec_C>

0 commit comments

Comments
 (0)