Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][CIRGen] Refactor StructType builders #294

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,37 @@ def CIR_StructType : CIR_Type<"Struct", "struct",
"ASTRecordDeclInterface":$ast
);

let skipDefaultBuilders = 1;
let builders = [
// Build an identified and complete struct.
TypeBuilder<(ins
"ArrayRef<Type>":$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<Type>{}, name,
/*incomplete=*/true, /*packed=*/false, kind,
/*ast=*/nullptr);
}]>,
// Build an anonymous struct.
TypeBuilder<(ins
"ArrayRef<Type>":$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 = [{
Expand All @@ -138,18 +169,21 @@ def CIR_StructType : CIR_Type<"Struct", "struct",
bool isComplete() const { return !getIncomplete(); }
bool isPadded(const ::mlir::DataLayout &dataLayout) const;

std::string getPrefixedName() {
const auto name = getName().getValue().str();
std::string getKindAsStr() {
switch (getKind()) {
case RecordKind::Class:
return "class." + name;
return "class";
case RecordKind::Union:
return "union." + name;
return "union";
case RecordKind::Struct:
return "struct." + name;
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;

Expand Down
43 changes: 29 additions & 14 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,11 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
isZero &= isNullValue(typedAttr);
}

// Struct type not specified: create type from members.
// Struct type not specified: create anon struct type from members.
if (!structTy)
structTy = getType<mlir::cir::StructType>(
members, mlir::StringAttr::get(getContext()),
/*incomplete=*/false, packed, mlir::cir::StructType::Struct,
/*ast=*/nullptr);
structTy = getType<mlir::cir::StructType>(members, packed,
mlir::cir::StructType::Struct,
/*ast=*/nullptr);

// Return zero or anonymous constant struct.
if (isZero)
Expand All @@ -200,7 +199,7 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
}

if (!ty)
ty = getAnonStructTy(members, /*incomplete=*/false, packed);
ty = getAnonStructTy(members, packed);

auto sTy = ty.dyn_cast<mlir::cir::StructType>();
assert(sTy && "expected struct type");
Expand Down Expand Up @@ -397,9 +396,15 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {

/// Get a CIR anonymous struct type.
mlir::cir::StructType
getAnonStructTy(llvm::ArrayRef<mlir::Type> members, bool incomplete,
bool packed = false, const clang::RecordDecl *ast = nullptr) {
return getStructTy(members, "", incomplete, packed, ast);
getAnonStructTy(llvm::ArrayRef<mlir::Type> members, bool packed = false,
const clang::RecordDecl *ast = nullptr) {
mlir::cir::ASTRecordDeclAttr astAttr = nullptr;
auto kind = mlir::cir::StructType::RecordKind::Struct;
if (ast) {
astAttr = getAttr<mlir::cir::ASTRecordDeclAttr>(ast);
kind = getRecordKind(ast->getTagKind());
}
return getType<mlir::cir::StructType>(members, packed, kind, astAttr);
}

/// Get a CIR record kind from a AST declaration tag.
Expand All @@ -419,19 +424,29 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
}
}

/// Get a incomplete CIR struct type.
mlir::cir::StructType getIncompleteStructTy(llvm::StringRef name,
const clang::RecordDecl *ast) {
const auto nameAttr = getStringAttr(name);
auto kind = mlir::cir::StructType::RecordKind::Struct;
if (ast)
kind = getRecordKind(ast->getTagKind());
return getType<mlir::cir::StructType>(nameAttr, kind);
}

/// Get a CIR named struct type.
mlir::cir::StructType getStructTy(llvm::ArrayRef<mlir::Type> members,
llvm::StringRef name, bool incomplete,
bool packed, const clang::RecordDecl *ast) {
mlir::cir::StructType getCompleteStructTy(llvm::ArrayRef<mlir::Type> members,
llvm::StringRef name, bool packed,
const clang::RecordDecl *ast) {
const auto nameAttr = getStringAttr(name);
mlir::cir::ASTRecordDeclAttr astAttr = nullptr;
auto kind = mlir::cir::StructType::RecordKind::Struct;
if (ast) {
astAttr = getAttr<mlir::cir::ASTRecordDeclAttr>(ast);
kind = getRecordKind(ast->getTagKind());
}
return mlir::cir::StructType::get(getContext(), members, nameAttr,
incomplete, packed, kind, astAttr);
return getType<mlir::cir::StructType>(members, nameAttr, packed, kind,
astAttr);
}

//
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *RD) {
// Handle forward decl / incomplete types.
if (!entry) {
auto name = getRecordTypeName(RD, "");
entry = Builder.getStructTy({}, name, /*incomplete=*/true, /*packed=*/false,
RD);
entry = Builder.getIncompleteStructTy(name, RD);
recordDeclTypes[key] = entry;
}

Expand Down
10 changes: 6 additions & 4 deletions clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,9 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *D,
builder.astRecordLayout.getSize()) {
CIRRecordLowering baseBuilder(*this, D, /*Packed=*/builder.isPacked);
auto baseIdentifier = getRecordTypeName(D, ".base");
*BaseTy = Builder.getStructTy(baseBuilder.fieldTypes, baseIdentifier,
/*incomplete=*/false, /*packed=*/false, D);
*BaseTy =
Builder.getCompleteStructTy(baseBuilder.fieldTypes, baseIdentifier,
/*packed=*/false, D);
// TODO(cir): add something like addRecordTypeName

// BaseTy and Ty must agree on their packedness for getCIRFieldNo to work
Expand All @@ -622,8 +623,9 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *D,
// Fill in the struct *after* computing the base type. Filling in the body
// signifies that the type is no longer opaque and record layout is complete,
// but we may need to recursively layout D while laying D out as a base type.
*Ty = Builder.getStructTy(builder.fieldTypes, getRecordTypeName(D, ""),
/*incomplete=*/false, /*packed=*/false, D);
*Ty =
Builder.getCompleteStructTy(builder.fieldTypes, getRecordTypeName(D, ""),
/*packed=*/false, D);

auto RL = std::make_unique<CIRGenRecordLayout>(
Ty ? *Ty : mlir::cir::StructType{},
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface {

AliasResult getAlias(Type type, raw_ostream &os) const final {
if (auto structType = type.dyn_cast<StructType>()) {
// TODO(cir): generate unique alias names for anonymous records.
if (!structType.getName())
return AliasResult::NoAlias;
if (!structType.getName()) {
os << "ty_anon_" << structType.getKindAsStr();
return AliasResult::OverridableAlias;
}
os << "ty_" << structType.getName();
return AliasResult::OverridableAlias;
}
Expand Down
17 changes: 15 additions & 2 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Type StructType::parse(mlir::AsmParser &parser) {
const auto loc = parser.getCurrentLocation();
bool packed = false;
RecordKind kind;
auto *context = parser.getContext();

if (parser.parseLess())
return {};
Expand Down Expand Up @@ -152,8 +153,20 @@ Type StructType::parse(mlir::AsmParser &parser) {
if (parser.parseGreater())
return {};

return StructType::get(parser.getContext(), members, name, incomplete, packed,
kind, nullptr);
// Try to create the proper type.
mlir::Type type = {};
if (name && incomplete) { // Identified & incomplete
type = StructType::get(context, name, kind);
} else if (name && !incomplete) { // Identified & complete
type = StructType::get(context, members, name, packed, kind);
} else if (!name && !incomplete) { // anonymous
type = StructType::get(context, members, packed, kind);
} else {
parser.emitError(loc, "anonymous structs must be complete");
return {};
}

return type;
}

void StructType::print(mlir::AsmPrinter &printer) const {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void baz(void) {
struct Foo f;
}

// CHECK-DAG: !ty_22Node22 = !cir.struct<struct "Node" incomplete #cir.record.decl.ast>
// CHECK-DAG: !ty_22Node22 = !cir.struct<struct "Node" incomplete>
// CHECK-DAG: !ty_22Node221 = !cir.struct<struct "Node" {!cir.ptr<!ty_22Node22>} #cir.record.decl.ast>
// CHECK-DAG: !ty_22Bar22 = !cir.struct<struct "Bar" {!s32i, !s8i}>
// CHECK-DAG: !ty_22Foo22 = !cir.struct<struct "Foo" {!s32i, !s8i, !ty_22Bar22}>
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CIR/CodeGen/vtable-rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class B : public A
};

// Type info B.
bcardosolopes marked this conversation as resolved.
Show resolved Hide resolved
// CHECK: ![[TypeInfoB:ty_.*]] = !cir.struct<struct "" {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>
// CHECK: ![[TypeInfoB:ty_.*]] = !cir.struct<struct {!cir.ptr<!u8i>, !cir.ptr<!u8i>, !cir.ptr<!u8i>}>

// vtable for A type
// CHECK: ![[VTableTypeA:ty_.*]] = !cir.struct<struct "" {!cir.array<!cir.ptr<!u8i> x 5>}>
// CHECK: ![[VTableTypeA:ty_.*]] = !cir.struct<struct {!cir.array<!cir.ptr<!u8i> x 5>}>

// Class A
// CHECK: ![[ClassA:ty_.*]] = !cir.struct<class "A" {!cir.ptr<!cir.ptr<!cir.func<!u32i ()>>>} #cir.record.decl.ast>
Expand Down Expand Up @@ -57,7 +57,7 @@ class B : public A
// CHECK: }

// Vtable definition for A
// cir.global "private" external @_ZTV1A : ![[VTableTypeA]] {alignment = 8 : i64}
// CHECK: cir.global "private" external @_ZTV1A : ![[VTableTypeA]] {alignment = 8 : i64}

// A ctor => @A::A()
// Calls @A::A() and initialize __vptr with address of A's vtable
Expand Down
11 changes: 8 additions & 3 deletions clang/test/CIR/IR/aliases.cir
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// RUN: cir-opt %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s

!s32i = !cir.int<s, 32>
module {
// CHECK: cir.func @shouldNotUseAliasWithAnonStruct(%arg0: !cir.struct<struct {!s32i}>)
cir.func @shouldNotUseAliasWithAnonStruct(%arg0 : !cir.struct<struct {!s32i}>) {
// CHECK: @testAnonRecordsAlias
cir.func @testAnonRecordsAlias() {
// CHECK: cir.alloca !ty_anon_struct, cir.ptr <!ty_anon_struct>
%0 = cir.alloca !cir.struct<struct {!cir.int<s, 32>}>, cir.ptr <!cir.struct<struct {!cir.int<s, 32>}>>, ["A"]
// CHECK: cir.alloca !ty_anon_struct1, cir.ptr <!ty_anon_struct1>
%1 = cir.alloca !cir.struct<struct {!cir.int<u, 8>}>, cir.ptr <!cir.struct<struct {!cir.int<u, 8>}>>, ["B"]
// CHECK: cir.alloca !ty_anon_union, cir.ptr <!ty_anon_union>
%2 = cir.alloca !cir.struct<union {!cir.int<s, 32>}>, cir.ptr <!cir.struct<union {!cir.int<s, 32>}>>, ["C"]
cir.return
}
}
7 changes: 7 additions & 0 deletions clang/test/CIR/IR/invalid.cir
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,10 @@ module {
cir.return
}
}


// -----

!u16i = !cir.int<u, 16>
// expected-error@+1 {{anonymous structs must be complete}}
!struct = !cir.struct<struct incomplete>