diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 898c26d22f6d1..37c32d9889e8b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -509,9 +509,12 @@ def CIR_RecordType : CIR_Type<"Record", "record", [ A few examples: ```mlir - !complete = !cir.record}> - !incomplete = !cir.record - !anonymous = !cir.record}> + !rec_complete = !cir.record + !rec_incomplete = !cir.record + !anonymous_struct = !cir.record + !rec_p1 = !cir.record + !rec_p2 = !cir.record + !rec_p3 = !cir.record ``` Incomplete records are mutable, meaning they can be later completed with a @@ -552,7 +555,7 @@ def CIR_RecordType : CIR_Type<"Record", "record", [ "bool":$padded, "RecordKind":$kind ), [{ - return $_get($_ctxt, members, name, /*complete=*/true, packed, padded, + return $_get($_ctxt, members, name, /*incomplete=*/false, packed, padded, kind); }]>, @@ -564,6 +567,17 @@ def CIR_RecordType : CIR_Type<"Record", "record", [ return $_get($_ctxt, /*members=*/llvm::ArrayRef{}, name, /*incomplete=*/true, /*packed=*/false, /*padded=*/false, kind); + }]>, + + // Create an anonymous record type (always complete). + TypeBuilder<(ins + "llvm::ArrayRef":$members, + "bool":$packed, + "bool":$padded, + "RecordKind":$kind + ), [{ + return $_get($_ctxt, members, mlir::StringAttr{}, /*incomplete=*/false, + packed, padded, kind); }]>]; let extraClassDeclaration = [{ diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index c6760cf1618cb..40da5e60a93f9 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -96,6 +96,8 @@ Type RecordType::parse(mlir::AsmParser &parser) { FailureOr cyclicParseGuard; const llvm::SMLoc loc = parser.getCurrentLocation(); const mlir::Location eLoc = parser.getEncodedSourceLoc(loc); + bool packed = false; + bool padded = false; RecordKind kind; mlir::MLIRContext *context = parser.getContext(); @@ -138,6 +140,12 @@ Type RecordType::parse(mlir::AsmParser &parser) { } } + if (parser.parseOptionalKeyword("packed").succeeded()) + packed = true; + + if (parser.parseOptionalKeyword("padded").succeeded()) + padded = true; + // Parse record members or lack thereof. bool incomplete = true; llvm::SmallVector members; @@ -159,8 +167,15 @@ Type RecordType::parse(mlir::AsmParser &parser) { mlir::Type type = {}; if (name && incomplete) { // Identified & incomplete type = getChecked(eLoc, context, name, kind); - } else if (!incomplete) { // complete - parser.emitError(loc, "complete records are not yet supported"); + } else if (!name && !incomplete) { // Anonymous & complete + type = getChecked(eLoc, context, membersRef, packed, padded, kind); + } else if (!incomplete) { // Identified & complete + type = getChecked(eLoc, context, membersRef, name, packed, padded, kind); + // If the record has a self-reference, its type already exists in a + // incomplete state. In this case, we must complete it. + if (mlir::cast(type).isIncomplete()) + mlir::cast(type).complete(membersRef, packed, padded); + assert(!cir::MissingFeatures::astRecordDeclAttr()); } else { // anonymous & incomplete parser.emitError(loc, "anonymous records must be complete"); return {}; diff --git a/clang/test/CIR/IR/struct.cir b/clang/test/CIR/IR/struct.cir index 5ff5ff7cd1f69..85f475f643ee5 100644 --- a/clang/test/CIR/IR/struct.cir +++ b/clang/test/CIR/IR/struct.cir @@ -1,19 +1,74 @@ // RUN: cir-opt %s | FileCheck %s +!u8i = !cir.int +!u16i = !cir.int +!s32i = !cir.int +!u32i = !cir.int + !rec_C = !cir.record !rec_S = !cir.record !rec_U = !cir.record -// CHECK: !rec_C = !cir.record -// CHECK: !rec_S = !cir.record -// CHECK: !rec_U = !cir.record +// CHECK-DAG: !rec_C = !cir.record +// CHECK-DAG: !rec_S = !cir.record +// CHECK-DAG: !rec_U = !cir.record + +!rec_anon_struct = !cir.record x 5>}> +!rec_anon_struct1 = !cir.record, !cir.ptr, !cir.ptr}> +!rec_S1 = !cir.record +!rec_Sc = !cir.record + +// CHECK-DAG: !cir.record x 5>}> +// CHECK-DAG: !cir.record, !cir.ptr, !cir.ptr}> +// CHECK-DAG: !rec_S1 = !cir.record +// CHECK-DAG: !rec_Sc = !cir.record + +// Packed and padded structs +!rec_P1 = !cir.record +!rec_P2 = !cir.record +!rec_P3 = !cir.record + +// CHECK-DAG: !rec_P1 = !cir.record +// CHECK-DAG: !rec_P2 = !cir.record +// CHECK-DAG: !rec_P3 = !cir.record -module { - cir.global external @p1 = #cir.ptr : !cir.ptr - cir.global external @p2 = #cir.ptr : !cir.ptr - cir.global external @p3 = #cir.ptr : !cir.ptr -} +// Complete a previously incomplete record +!rec_A = !cir.record +!rec_Ac = !cir.record +// CHECK-DAG: !rec_A = !cir.record + +// Test recursive struct parsing/printing. +!rec_Node = !cir.record>}> +// CHECK-DAG: !cir.record>}> + +module { + cir.global external @p1 = #cir.ptr : !cir.ptr + cir.global external @p2 = #cir.ptr : !cir.ptr + cir.global external @p3 = #cir.ptr : !cir.ptr // CHECK: cir.global external @p1 = #cir.ptr : !cir.ptr // CHECK: cir.global external @p2 = #cir.ptr : !cir.ptr // CHECK: cir.global external @p3 = #cir.ptr : !cir.ptr + + // Dummy function to use types and force them to be printed. + cir.func @useTypes(%arg0: !rec_Node, + %arg1: !rec_anon_struct1, + %arg2: !rec_anon_struct, + %arg3: !rec_S1, + %arg4: !rec_Ac, + %arg5: !rec_P1, + %arg6: !rec_P2, + %arg7: !rec_P3) { + cir.return + } + + cir.func @structs() { + %0 = cir.alloca !cir.ptr>, !cir.ptr>>, ["sc", init] + %1 = cir.alloca !cir.ptr>, !cir.ptr>>, ["u", init] + cir.return + } + +// CHECK: cir.func @structs() { +// CHECK: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["sc", init] +// CHECK: %1 = cir.alloca !cir.ptr, !cir.ptr>, ["u", init] +}