[CIR] Upstream initial support for complete record types (#135844)
This adds basic support for populating record types. In order to keep the change small, everything non-essential was deferred to a later change set. Only non-recursive structures are handled. Structures padding is not yet implemented. Bitfields are not supported. No attempt is made to handle ABI requirements for passing structure arguments.
This commit is contained in:
parent
ce7466f66c
commit
80c19b3b1d
@ -95,6 +95,8 @@ public:
|
||||
return getZeroAttr(arrTy);
|
||||
if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty))
|
||||
return getConstNullPtrAttr(ptrTy);
|
||||
if (auto recordTy = mlir::dyn_cast<cir::RecordType>(ty))
|
||||
return getZeroAttr(recordTy);
|
||||
if (mlir::isa<cir::BoolType>(ty)) {
|
||||
return getCIRBoolAttr(false);
|
||||
}
|
||||
|
||||
@ -499,6 +499,9 @@ def CIR_RecordType : CIR_Type<"Record", "record",
|
||||
std::string getPrefixedName() {
|
||||
return getKindAsStr() + "." + getName().getValue().str();
|
||||
}
|
||||
|
||||
void complete(llvm::ArrayRef<mlir::Type> members, bool packed,
|
||||
bool isPadded);
|
||||
}];
|
||||
|
||||
let hasCustomAssemblyFormat = 1;
|
||||
|
||||
@ -103,6 +103,14 @@ struct MissingFeatures {
|
||||
|
||||
// RecordType
|
||||
static bool recordTypeLayoutInfo() { return false; }
|
||||
static bool recursiveRecordLayout() { return false; }
|
||||
static bool skippedLayout() { return false; }
|
||||
static bool astRecordDeclAttr() { return false; }
|
||||
static bool cxxSupport() { return false; }
|
||||
static bool packedRecords() { return false; }
|
||||
static bool recordPadding() { return false; }
|
||||
static bool recordZeroInit() { return false; }
|
||||
static bool zeroSizeRecordMembers() { return false; }
|
||||
|
||||
// Misc
|
||||
static bool cxxABI() { return false; }
|
||||
|
||||
54
clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
Normal file
54
clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
Normal file
@ -0,0 +1,54 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H
|
||||
#define LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
|
||||
namespace clang::CIRGen {
|
||||
|
||||
/// This class handles record and union layout info while lowering AST types
|
||||
/// to CIR types.
|
||||
///
|
||||
/// These layout objects are only created on demand as CIR generation requires.
|
||||
class CIRGenRecordLayout {
|
||||
friend class CIRGenTypes;
|
||||
|
||||
CIRGenRecordLayout(const CIRGenRecordLayout &) = delete;
|
||||
void operator=(const CIRGenRecordLayout &) = delete;
|
||||
|
||||
private:
|
||||
/// The CIR type corresponding to this record layout; used when laying it out
|
||||
/// as a complete object.
|
||||
cir::RecordType completeObjectType;
|
||||
|
||||
/// Map from (non-bit-field) record field to the corresponding cir record type
|
||||
/// field no. This info is populated by the record builder.
|
||||
llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldInfo;
|
||||
|
||||
public:
|
||||
CIRGenRecordLayout(cir::RecordType completeObjectType)
|
||||
: completeObjectType(completeObjectType) {}
|
||||
|
||||
/// Return the "complete object" LLVM type associated with
|
||||
/// this record.
|
||||
cir::RecordType getCIRType() const { return completeObjectType; }
|
||||
|
||||
/// Return cir::RecordType element number that corresponds to the field FD.
|
||||
unsigned getCIRFieldNo(const clang::FieldDecl *FD) const {
|
||||
FD = FD->getCanonicalDecl();
|
||||
assert(fieldInfo.count(FD) && "Invalid field for record!");
|
||||
return fieldInfo.lookup(FD);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang::CIRGen
|
||||
|
||||
#endif
|
||||
223
clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
Normal file
223
clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code to compute the layout of a record.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CIRGenBuilder.h"
|
||||
#include "CIRGenModule.h"
|
||||
#include "CIRGenTypes.h"
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang;
|
||||
using namespace clang::CIRGen;
|
||||
|
||||
namespace {
|
||||
/// The CIRRecordLowering is responsible for lowering an ASTRecordLayout to an
|
||||
/// mlir::Type. Some of the lowering is straightforward, some is not.
|
||||
// TODO: Detail some of the complexities and weirdnesses?
|
||||
// (See CGRecordLayoutBuilder.cpp)
|
||||
struct CIRRecordLowering final {
|
||||
|
||||
// MemberInfo is a helper structure that contains information about a record
|
||||
// member. In addition to the standard member types, there exists a sentinel
|
||||
// member type that ensures correct rounding.
|
||||
struct MemberInfo final {
|
||||
CharUnits offset;
|
||||
enum class InfoKind { Field } kind;
|
||||
mlir::Type data;
|
||||
union {
|
||||
const FieldDecl *fieldDecl;
|
||||
// CXXRecordDecl will be used here when base types are supported.
|
||||
};
|
||||
MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
|
||||
const FieldDecl *fieldDecl = nullptr)
|
||||
: offset(offset), kind(kind), data(data), fieldDecl(fieldDecl) {};
|
||||
// MemberInfos are sorted so we define a < operator.
|
||||
bool operator<(const MemberInfo &other) const {
|
||||
return offset < other.offset;
|
||||
}
|
||||
};
|
||||
// The constructor.
|
||||
CIRRecordLowering(CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,
|
||||
bool isPacked);
|
||||
|
||||
void lower();
|
||||
|
||||
void accumulateFields();
|
||||
|
||||
CharUnits bitsToCharUnits(uint64_t bitOffset) {
|
||||
return astContext.toCharUnitsFromBits(bitOffset);
|
||||
}
|
||||
|
||||
CharUnits getSize(mlir::Type Ty) {
|
||||
assert(!cir::MissingFeatures::recordTypeLayoutInfo());
|
||||
return CharUnits::One();
|
||||
}
|
||||
CharUnits getAlignment(mlir::Type Ty) {
|
||||
assert(!cir::MissingFeatures::recordTypeLayoutInfo());
|
||||
return CharUnits::One();
|
||||
}
|
||||
|
||||
mlir::Type getStorageType(const FieldDecl *fieldDecl) {
|
||||
mlir::Type type = cirGenTypes.convertTypeForMem(fieldDecl->getType());
|
||||
if (fieldDecl->isBitField()) {
|
||||
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
|
||||
"getStorageType for bitfields");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
uint64_t getFieldBitOffset(const FieldDecl *fieldDecl) {
|
||||
return astRecordLayout.getFieldOffset(fieldDecl->getFieldIndex());
|
||||
}
|
||||
|
||||
/// Fills out the structures that are ultimately consumed.
|
||||
void fillOutputFields();
|
||||
|
||||
CIRGenTypes &cirGenTypes;
|
||||
CIRGenBuilderTy &builder;
|
||||
const ASTContext &astContext;
|
||||
const RecordDecl *recordDecl;
|
||||
const ASTRecordLayout &astRecordLayout;
|
||||
// Helpful intermediate data-structures
|
||||
std::vector<MemberInfo> members;
|
||||
// Output fields, consumed by CIRGenTypes::computeRecordLayout
|
||||
llvm::SmallVector<mlir::Type, 16> fieldTypes;
|
||||
llvm::DenseMap<const FieldDecl *, unsigned> fields;
|
||||
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned zeroInitializable : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned packed : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned padded : 1;
|
||||
|
||||
private:
|
||||
CIRRecordLowering(const CIRRecordLowering &) = delete;
|
||||
void operator=(const CIRRecordLowering &) = delete;
|
||||
}; // CIRRecordLowering
|
||||
} // namespace
|
||||
|
||||
CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes,
|
||||
const RecordDecl *recordDecl,
|
||||
bool isPacked)
|
||||
: cirGenTypes(cirGenTypes), builder(cirGenTypes.getBuilder()),
|
||||
astContext(cirGenTypes.getASTContext()), recordDecl(recordDecl),
|
||||
astRecordLayout(
|
||||
cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)),
|
||||
zeroInitializable(true), packed(isPacked), padded(false) {}
|
||||
|
||||
void CIRRecordLowering::lower() {
|
||||
if (recordDecl->isUnion()) {
|
||||
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
|
||||
"lower: union");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isa<CXXRecordDecl>(recordDecl)) {
|
||||
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
|
||||
"lower: class");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!cir::MissingFeatures::cxxSupport());
|
||||
|
||||
accumulateFields();
|
||||
|
||||
llvm::stable_sort(members);
|
||||
// TODO: implement clipTailPadding once bitfields are implemented
|
||||
assert(!cir::MissingFeatures::bitfields());
|
||||
// TODO: implemented packed records
|
||||
assert(!cir::MissingFeatures::packedRecords());
|
||||
// TODO: implement padding
|
||||
assert(!cir::MissingFeatures::recordPadding());
|
||||
// TODO: support zeroInit
|
||||
assert(!cir::MissingFeatures::recordZeroInit());
|
||||
|
||||
fillOutputFields();
|
||||
}
|
||||
|
||||
void CIRRecordLowering::fillOutputFields() {
|
||||
for (const MemberInfo &member : members) {
|
||||
if (member.data)
|
||||
fieldTypes.push_back(member.data);
|
||||
if (member.kind == MemberInfo::InfoKind::Field) {
|
||||
if (member.fieldDecl)
|
||||
fields[member.fieldDecl->getCanonicalDecl()] = fieldTypes.size() - 1;
|
||||
// A field without storage must be a bitfield.
|
||||
assert(!cir::MissingFeatures::bitfields());
|
||||
}
|
||||
assert(!cir::MissingFeatures::cxxSupport());
|
||||
}
|
||||
}
|
||||
|
||||
void CIRRecordLowering::accumulateFields() {
|
||||
for (const FieldDecl *field : recordDecl->fields()) {
|
||||
if (field->isBitField()) {
|
||||
cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
|
||||
"accumulate bitfields");
|
||||
++field;
|
||||
} else if (!field->isZeroSize(astContext)) {
|
||||
members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(field)),
|
||||
MemberInfo::InfoKind::Field,
|
||||
getStorageType(field), field));
|
||||
++field;
|
||||
} else {
|
||||
// TODO(cir): do we want to do anything special about zero size members?
|
||||
assert(!cir::MissingFeatures::zeroSizeRecordMembers());
|
||||
++field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<CIRGenRecordLayout>
|
||||
CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
|
||||
CIRRecordLowering lowering(*this, rd, /*packed=*/false);
|
||||
assert(ty->isIncomplete() && "recomputing record layout?");
|
||||
lowering.lower();
|
||||
|
||||
// If we're in C++, compute the base subobject type.
|
||||
if (llvm::isa<CXXRecordDecl>(rd) && !rd->isUnion() &&
|
||||
!rd->hasAttr<FinalAttr>()) {
|
||||
cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: CXXRecordDecl");
|
||||
}
|
||||
|
||||
// Fill in the record *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 rd while laying D out as a base type.
|
||||
assert(!cir::MissingFeatures::astRecordDeclAttr());
|
||||
ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);
|
||||
|
||||
auto rl = std::make_unique<CIRGenRecordLayout>(ty ? *ty : cir::RecordType());
|
||||
|
||||
assert(!cir::MissingFeatures::recordZeroInit());
|
||||
assert(!cir::MissingFeatures::cxxSupport());
|
||||
assert(!cir::MissingFeatures::bitfields());
|
||||
|
||||
// Add all the field numbers.
|
||||
rl->fieldInfo.swap(lowering.fields);
|
||||
|
||||
// Dump the layout, if requested.
|
||||
if (getASTContext().getLangOpts().DumpRecordLayouts) {
|
||||
cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: dump layout");
|
||||
}
|
||||
|
||||
// TODO: implement verification
|
||||
return rl;
|
||||
}
|
||||
@ -112,6 +112,18 @@ std::string CIRGenTypes::getRecordTypeName(const clang::RecordDecl *recordDecl,
|
||||
return builder.getUniqueRecordName(std::string(typeName));
|
||||
}
|
||||
|
||||
// Return true if it is safe to convert the specified record decl to CIR and lay
|
||||
// it out, false if doing so would cause us to get into a recursive compilation
|
||||
// mess.
|
||||
static bool isSafeToConvert(const RecordDecl *RD, CIRGenTypes &CGT) {
|
||||
// If no records are being laid out, we can certainly do this one.
|
||||
if (CGT.noRecordsBeingLaidOut())
|
||||
return true;
|
||||
|
||||
assert(!cir::MissingFeatures::recursiveRecordLayout());
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lay out a tagged decl type like struct or union.
|
||||
mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) {
|
||||
// TagDecl's are not necessarily unique, instead use the (clang) type
|
||||
@ -132,7 +144,40 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *rd) {
|
||||
if (!rd || !rd->isCompleteDefinition() || entry.isComplete())
|
||||
return entry;
|
||||
|
||||
cgm.errorNYI(rd->getSourceRange(), "Complete record type");
|
||||
// If converting this type would cause us to infinitely loop, don't do it!
|
||||
if (!isSafeToConvert(rd, *this)) {
|
||||
cgm.errorNYI(rd->getSourceRange(), "recursive record layout");
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Okay, this is a definition of a type. Compile the implementation now.
|
||||
bool insertResult = recordsBeingLaidOut.insert(key).second;
|
||||
(void)insertResult;
|
||||
assert(insertResult && "isSafeToCovert() should have caught this.");
|
||||
|
||||
// Force conversion of non-virtual base classes recursively.
|
||||
if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(rd)) {
|
||||
cgm.errorNYI(rd->getSourceRange(), "CXXRecordDecl");
|
||||
}
|
||||
|
||||
// Layout fields.
|
||||
std::unique_ptr<CIRGenRecordLayout> layout = computeRecordLayout(rd, &entry);
|
||||
recordDeclTypes[key] = entry;
|
||||
cirGenRecordLayouts[key] = std::move(layout);
|
||||
|
||||
// We're done laying out this record.
|
||||
bool eraseResult = recordsBeingLaidOut.erase(key);
|
||||
(void)eraseResult;
|
||||
assert(eraseResult && "record not in RecordsBeingLaidOut set?");
|
||||
|
||||
// If this record blocked a FunctionType conversion, then recompute whatever
|
||||
// was derived from that.
|
||||
assert(!cir::MissingFeatures::skippedLayout());
|
||||
|
||||
// If we're done converting the outer-most record, then convert any deferred
|
||||
// records as well.
|
||||
assert(!cir::MissingFeatures::recursiveRecordLayout());
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
@ -14,9 +14,10 @@
|
||||
#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
|
||||
|
||||
#include "CIRGenFunctionInfo.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
#include "CIRGenRecordLayout.h"
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
@ -45,12 +46,22 @@ class CIRGenTypes {
|
||||
clang::ASTContext &astContext;
|
||||
CIRGenBuilderTy &builder;
|
||||
|
||||
/// Contains the CIR type for any converted RecordDecl.
|
||||
llvm::DenseMap<const clang::Type *, std::unique_ptr<CIRGenRecordLayout>>
|
||||
cirGenRecordLayouts;
|
||||
|
||||
/// Contains the CIR type for any converted RecordDecl
|
||||
llvm::DenseMap<const clang::Type *, cir::RecordType> recordDeclTypes;
|
||||
|
||||
/// Hold memoized CIRGenFunctionInfo results
|
||||
llvm::FoldingSet<CIRGenFunctionInfo> functionInfos;
|
||||
|
||||
/// This set keeps track of records that we're currently converting to a CIR
|
||||
/// type. For example, when converting:
|
||||
/// struct A { struct B { int x; } } when processing 'x', the 'A' and 'B'
|
||||
/// types will be in this set.
|
||||
llvm::SmallPtrSet<const clang::Type *, 4> recordsBeingLaidOut;
|
||||
|
||||
llvm::SmallPtrSet<const CIRGenFunctionInfo *, 4> functionsBeingProcessed;
|
||||
/// Heper for convertType.
|
||||
mlir::Type convertFunctionTypeInternal(clang::QualType ft);
|
||||
@ -59,6 +70,9 @@ public:
|
||||
CIRGenTypes(CIRGenModule &cgm);
|
||||
~CIRGenTypes();
|
||||
|
||||
CIRGenBuilderTy &getBuilder() const { return builder; }
|
||||
CIRGenModule &getCGModule() const { return cgm; }
|
||||
|
||||
/// Utility to check whether a function type can be converted to a CIR type
|
||||
/// (i.e. doesn't depend on an incomplete tag type).
|
||||
bool isFuncTypeConvertible(const clang::FunctionType *ft);
|
||||
@ -70,12 +84,18 @@ public:
|
||||
TypeCacheTy typeCache;
|
||||
|
||||
mlir::MLIRContext &getMLIRContext() const;
|
||||
clang::ASTContext &getASTContext() const { return astContext; }
|
||||
|
||||
bool noRecordsBeingLaidOut() const { return recordsBeingLaidOut.empty(); }
|
||||
|
||||
/// Convert a Clang type into a mlir::Type.
|
||||
mlir::Type convertType(clang::QualType type);
|
||||
|
||||
mlir::Type convertRecordDeclType(const clang::RecordDecl *recordDecl);
|
||||
|
||||
std::unique_ptr<CIRGenRecordLayout>
|
||||
computeRecordLayout(const clang::RecordDecl *rd, cir::RecordType *ty);
|
||||
|
||||
std::string getRecordTypeName(const clang::RecordDecl *,
|
||||
llvm::StringRef suffix);
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ add_clang_library(clangCIR
|
||||
CIRGenExprScalar.cpp
|
||||
CIRGenFunction.cpp
|
||||
CIRGenModule.cpp
|
||||
CIRGenRecordLayoutBuilder.cpp
|
||||
CIRGenStmt.cpp
|
||||
CIRGenStmtOpenACC.cpp
|
||||
CIRGenTypes.cpp
|
||||
|
||||
@ -212,7 +212,7 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
|
||||
}
|
||||
|
||||
if (isa<cir::ZeroAttr>(attrType)) {
|
||||
if (::mlir::isa<cir::ArrayType>(opType))
|
||||
if (isa<cir::RecordType, cir::ArrayType>(opType))
|
||||
return success();
|
||||
return op->emitOpError("zero expects struct or array type");
|
||||
}
|
||||
|
||||
@ -214,6 +214,12 @@ cir::RecordType::RecordKind RecordType::getKind() const {
|
||||
return getImpl()->kind;
|
||||
}
|
||||
|
||||
void RecordType::complete(ArrayRef<Type> members, bool packed, bool padded) {
|
||||
assert(!cir::MissingFeatures::astRecordDeclAttr());
|
||||
if (mutate(members, packed, padded).failed())
|
||||
llvm_unreachable("failed to complete record");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Data Layout information for types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -1337,6 +1337,35 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
|
||||
converter.addConversion([&](cir::BF16Type type) -> mlir::Type {
|
||||
return mlir::BFloat16Type::get(type.getContext());
|
||||
});
|
||||
converter.addConversion([&](cir::RecordType type) -> mlir::Type {
|
||||
// Convert struct members.
|
||||
llvm::SmallVector<mlir::Type> llvmMembers;
|
||||
switch (type.getKind()) {
|
||||
case cir::RecordType::Struct:
|
||||
for (mlir::Type ty : type.getMembers())
|
||||
llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));
|
||||
break;
|
||||
// Unions are lowered as only the largest member.
|
||||
case cir::RecordType::Union:
|
||||
llvm_unreachable("Lowering of unions is NYI");
|
||||
break;
|
||||
}
|
||||
|
||||
// Record has a name: lower as an identified record.
|
||||
mlir::LLVM::LLVMStructType llvmStruct;
|
||||
if (type.getName()) {
|
||||
llvmStruct = mlir::LLVM::LLVMStructType::getIdentified(
|
||||
type.getContext(), type.getPrefixedName());
|
||||
assert(!cir::MissingFeatures::packedRecords());
|
||||
if (llvmStruct.setBody(llvmMembers, /*isPacked=*/true).failed())
|
||||
llvm_unreachable("Failed to set body of record");
|
||||
} else { // Record has no name: lower as literal record.
|
||||
llvmStruct = mlir::LLVM::LLVMStructType::getLiteral(
|
||||
type.getContext(), llvmMembers, /*isPacked=*/true);
|
||||
}
|
||||
|
||||
return llvmStruct;
|
||||
});
|
||||
}
|
||||
|
||||
// The applyPartialConversion function traverses blocks in the dominance order,
|
||||
|
||||
@ -11,6 +11,15 @@ struct IncompleteS *p;
|
||||
// LLVM: @p = dso_local global ptr null
|
||||
// OGCG: @p = global ptr null, align 8
|
||||
|
||||
struct CompleteS {
|
||||
int a;
|
||||
char b;
|
||||
} cs;
|
||||
|
||||
// CIR: cir.global external @cs = #cir.zero : !cir.record<struct "CompleteS" {!s32i, !s8i}>
|
||||
// LLVM: @cs = dso_local global %struct.CompleteS zeroinitializer
|
||||
// OGCG: @cs = global %struct.CompleteS zeroinitializer, align 4
|
||||
|
||||
void f(void) {
|
||||
struct IncompleteS *p;
|
||||
}
|
||||
@ -28,3 +37,21 @@ void f(void) {
|
||||
// OGCG-NEXT: entry:
|
||||
// OGCG-NEXT: %[[P:.*]] = alloca ptr, align 8
|
||||
// OGCG-NEXT: ret void
|
||||
|
||||
void f2(void) {
|
||||
struct CompleteS s;
|
||||
}
|
||||
|
||||
// CIR: cir.func @f2()
|
||||
// CIR-NEXT: cir.alloca !cir.record<struct "CompleteS" {!s32i, !s8i}>,
|
||||
// CIR-SAME: !cir.ptr<!cir.record<struct "CompleteS" {!s32i, !s8i}>>, ["s"]
|
||||
// CIR-NEXT: cir.return
|
||||
|
||||
// LLVM: define void @f2()
|
||||
// LLVM-NEXT: %[[S:.*]] = alloca %struct.CompleteS, i64 1, align 4
|
||||
// LLVM-NEXT: ret void
|
||||
|
||||
// OGCG: define{{.*}} void @f2()
|
||||
// OGCG-NEXT: entry:
|
||||
// OGCG-NEXT: %[[S:.*]] = alloca %struct.CompleteS, align 4
|
||||
// OGCG-NEXT: ret void
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user