Skip to content

[CIR][CIRGen] Add padding to unions #1289

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

Merged
merged 6 commits into from
Jan 31, 2025
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
20 changes: 11 additions & 9 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ class StructType
/// Create a identified and complete struct type.
static StructType get(mlir::MLIRContext *context,
llvm::ArrayRef<mlir::Type> members,
mlir::StringAttr name, bool packed, RecordKind kind,
ASTRecordDeclInterface ast = {});
mlir::StringAttr name, bool packed, bool padded,
RecordKind kind, ASTRecordDeclInterface ast = {});
static StructType
getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
mlir::MLIRContext *context, llvm::ArrayRef<mlir::Type> members,
mlir::StringAttr name, bool packed, RecordKind kind,
mlir::StringAttr name, bool packed, bool padded, RecordKind kind,
ASTRecordDeclInterface ast = {});

/// Create a identified and incomplete struct type.
Expand All @@ -105,18 +105,20 @@ class StructType
/// Create a anonymous struct type (always complete).
static StructType get(mlir::MLIRContext *context,
llvm::ArrayRef<mlir::Type> members, bool packed,
RecordKind kind, ASTRecordDeclInterface ast = {});
bool padded, RecordKind kind,
ASTRecordDeclInterface ast = {});
static StructType
getChecked(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
mlir::MLIRContext *context, llvm::ArrayRef<mlir::Type> members,
bool packed, RecordKind kind, ASTRecordDeclInterface ast = {});
bool packed, bool padded, RecordKind kind,
ASTRecordDeclInterface ast = {});

/// Validate the struct about to be constructed.
static llvm::LogicalResult
verifyInvariants(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
bool incomplete, bool packed, StructType::RecordKind kind,
ASTRecordDeclInterface ast);
bool incomplete, bool packed, bool padded,
StructType::RecordKind kind, ASTRecordDeclInterface ast);

// Parse/print methods.
static constexpr llvm::StringLiteral getMnemonic() { return {"struct"}; }
Expand All @@ -130,6 +132,7 @@ class StructType
StructType::RecordKind getKind() const;
bool getIncomplete() const;
bool getPacked() const;
bool getPadded() const;
void dropAst();

// Predicates
Expand Down Expand Up @@ -157,7 +160,7 @@ class StructType
}

/// Complete the struct type by mutating its members and attributes.
void complete(llvm::ArrayRef<mlir::Type> members, bool packed,
void complete(llvm::ArrayRef<mlir::Type> members, bool packed, bool isPadded,
ASTRecordDeclInterface ast = {});

/// DataLayoutTypeInterface methods.
Expand All @@ -178,7 +181,6 @@ class StructType
// from CIRAttrs.h. The implementation operates in terms of StructLayoutAttr
// instead.
mutable mlir::Attribute layoutInfo;
bool isPadded(const mlir::DataLayout &dataLayout) const;
void computeSizeAndAlignment(const mlir::DataLayout &dataLayout) const;
};

Expand Down
34 changes: 19 additions & 15 deletions clang/include/clang/CIR/Dialect/IR/CIRTypesDetails.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,53 +32,55 @@ struct StructTypeStorage : public mlir::TypeStorage {
mlir::StringAttr name;
bool incomplete;
bool packed;
bool padded;
StructType::RecordKind kind;
ASTRecordDeclInterface ast;

KeyTy(llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
bool incomplete, bool packed, StructType::RecordKind kind,
ASTRecordDeclInterface ast)
bool incomplete, bool packed, bool padded,
StructType::RecordKind kind, ASTRecordDeclInterface ast)
: members(members), name(name), incomplete(incomplete), packed(packed),
kind(kind), ast(ast) {}
padded(padded), kind(kind), ast(ast) {}
};

llvm::ArrayRef<mlir::Type> members;
mlir::StringAttr name;
bool incomplete;
bool packed;
bool padded;
StructType::RecordKind kind;
ASTRecordDeclInterface ast;

StructTypeStorage(llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
bool incomplete, bool packed, StructType::RecordKind kind,
ASTRecordDeclInterface ast)
bool incomplete, bool packed, bool padded,
StructType::RecordKind kind, ASTRecordDeclInterface ast)
: members(members), name(name), incomplete(incomplete), packed(packed),
kind(kind), ast(ast) {}
padded(padded), kind(kind), ast(ast) {}

KeyTy getAsKey() const {
return KeyTy(members, name, incomplete, packed, kind, ast);
return KeyTy(members, name, incomplete, packed, padded, kind, ast);
}

bool operator==(const KeyTy &key) const {
if (name)
return (name == key.name) && (kind == key.kind);
return (members == key.members) && (name == key.name) &&
(incomplete == key.incomplete) && (packed == key.packed) &&
(kind == key.kind) && (ast == key.ast);
(padded == key.padded) && (kind == key.kind) && (ast == key.ast);
}

static llvm::hash_code hashKey(const KeyTy &key) {
if (key.name)
return llvm::hash_combine(key.name, key.kind);
return llvm::hash_combine(key.members, key.incomplete, key.packed, key.kind,
key.ast);
return llvm::hash_combine(key.members, key.incomplete, key.packed,
key.padded, key.kind, key.ast);
}

static StructTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
const KeyTy &key) {
return new (allocator.allocate<StructTypeStorage>())
StructTypeStorage(allocator.copyInto(key.members), key.name,
key.incomplete, key.packed, key.kind, key.ast);
return new (allocator.allocate<StructTypeStorage>()) StructTypeStorage(
allocator.copyInto(key.members), key.name, key.incomplete, key.packed,
key.padded, key.kind, key.ast);
}

/// Mutates the members and attributes an identified struct.
Expand All @@ -89,20 +91,22 @@ struct StructTypeStorage : public mlir::TypeStorage {
/// change the struct.
llvm::LogicalResult mutate(mlir::TypeStorageAllocator &allocator,
llvm::ArrayRef<mlir::Type> members, bool packed,
ASTRecordDeclInterface ast) {
bool padded, ASTRecordDeclInterface ast) {
// Anonymous structs cannot mutate.
if (!name)
return llvm::failure();

// Mutation of complete structs are allowed if they change nothing.
if (!incomplete)
return mlir::success((this->members == members) &&
(this->packed == packed) && (this->ast == ast));
(this->packed == packed) &&
(this->padded == padded) && (this->ast == ast));

// Mutate incomplete struct.
this->members = allocator.copyInto(members);
this->packed = packed;
this->ast = ast;
this->padded = padded;

incomplete = false;
return llvm::success();
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CIR/CodeGen/CIRAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,8 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &S) {
ResultType = ResultRegTypes[0];
else if (ResultRegTypes.size() > 1) {
auto sname = builder.getUniqueAnonRecordName();
ResultType =
builder.getCompleteStructTy(ResultRegTypes, sname, false, nullptr);
ResultType = builder.getCompleteStructTy(ResultRegTypes, sname, false,
false, nullptr);
}

bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
Expand Down
27 changes: 15 additions & 12 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {

mlir::Attribute getConstStructOrZeroAttr(mlir::ArrayAttr arrayAttr,
bool packed = false,
bool padded = false,
mlir::Type type = {}) {
llvm::SmallVector<mlir::Type, 8> members;
auto structTy = mlir::dyn_cast<cir::StructType>(type);
Expand All @@ -193,9 +194,9 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {

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

// Return zero or anonymous constant struct.
if (isZero)
Expand All @@ -205,6 +206,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {

cir::ConstStructAttr getAnonConstStruct(mlir::ArrayAttr arrayAttr,
bool packed = false,
bool padded = false,
mlir::Type ty = {}) {
llvm::SmallVector<mlir::Type, 4> members;
for (auto &f : arrayAttr) {
Expand All @@ -214,7 +216,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
}

if (!ty)
ty = getAnonStructTy(members, packed);
ty = getAnonStructTy(members, packed, padded);

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

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

/// Get a CIR record kind from a AST declaration tag.
Expand Down Expand Up @@ -477,6 +479,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
/// it with a different set of attributes, this method will crash.
cir::StructType getCompleteStructTy(llvm::ArrayRef<mlir::Type> members,
llvm::StringRef name, bool packed,
bool padded,
const clang::RecordDecl *ast) {
const auto nameAttr = getStringAttr(name);
cir::ASTRecordDeclAttr astAttr = nullptr;
Expand All @@ -487,19 +490,19 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
}

// Create or get the struct.
auto type =
getType<cir::StructType>(members, nameAttr, packed, kind, astAttr);
auto type = getType<cir::StructType>(members, nameAttr, packed, padded,
kind, astAttr);

// Complete an incomplete struct or ensure the existing complete struct
// matches the requested attributes.
type.complete(members, packed, astAttr);
type.complete(members, packed, padded, astAttr);

return type;
}

cir::StructType
getCompleteStructType(mlir::ArrayAttr fields, bool packed = false,
llvm::StringRef name = "",
bool padded = false, llvm::StringRef name = "",
const clang::RecordDecl *ast = nullptr) {
llvm::SmallVector<mlir::Type, 8> members;
for (auto &attr : fields) {
Expand All @@ -508,9 +511,9 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
}

if (name.empty())
return getAnonStructTy(members, packed, ast);
return getAnonStructTy(members, packed, padded, ast);
else
return getCompleteStructTy(members, name, packed, ast);
return getCompleteStructTy(members, name, packed, padded, ast);
}

cir::ArrayType getArrayType(mlir::Type eltType, unsigned size) {
Expand Down
25 changes: 23 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
CharUnits AlignedSize = Size.alignTo(Align);

bool Packed = false;
bool Padded = false;
ArrayRef<mlir::Attribute> UnpackedElems = Elems;

llvm::SmallVector<mlir::Attribute, 32> UnpackedElemStorage;
Expand Down Expand Up @@ -435,13 +436,13 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
auto &builder = CGM.getBuilder();
auto arrAttr = mlir::ArrayAttr::get(builder.getContext(),
Packed ? PackedElems : UnpackedElems);
auto strType = builder.getCompleteStructType(arrAttr, Packed);

auto strType = builder.getCompleteStructType(arrAttr, Packed);
if (auto desired = dyn_cast<cir::StructType>(DesiredTy))
if (desired.isLayoutIdentical(strType))
strType = desired;

return builder.getConstStructOrZeroAttr(arrAttr, Packed, strType);
return builder.getConstStructOrZeroAttr(arrAttr, Packed, Padded, strType);
}

void ConstantAggregateBuilder::condense(CharUnits Offset,
Expand Down Expand Up @@ -521,6 +522,9 @@ class ConstStructBuilder {
const FieldDecl &Field, bool AllowOverwrite,
CharUnits &SizeSoFar, bool &ZeroFieldSize);

bool ApplyZeroInitPadding(const ASTRecordLayout &Layout, bool AllowOverwrite,
CharUnits SizeSoFar);

mlir::Attribute Finalize(QualType Ty);
};

Expand Down Expand Up @@ -715,6 +719,10 @@ bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) {
}
}

if (ZeroInitPadding &&
!ApplyZeroInitPadding(Layout, AllowOverwrite, SizeSoFar))
return false;

return true;
}

Expand Down Expand Up @@ -853,6 +861,19 @@ bool ConstStructBuilder::ApplyZeroInitPadding(
return true;
}

bool ConstStructBuilder::ApplyZeroInitPadding(const ASTRecordLayout &Layout,
bool AllowOverwrite,
CharUnits SizeSoFar) {
CharUnits TotalSize = Layout.getSize();
if (SizeSoFar < TotalSize) {
if (!AppendBytes(SizeSoFar, computePadding(CGM, TotalSize - SizeSoFar),
AllowOverwrite))
return false;
}
SizeSoFar = TotalSize;
return true;
}

mlir::Attribute ConstStructBuilder::Finalize(QualType Type) {
Type = Type.getNonReferenceType();
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
Expand Down
Loading