mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 07:00:46 +03:00
Fix issue 726: Wrong alignment for struct fields on x86_64/amd64
This commit is contained in:
parent
0b180be099
commit
9314fc1c1c
8 changed files with 49 additions and 16 deletions
|
@ -28,7 +28,6 @@
|
||||||
IrAggr::IrAggr(AggregateDeclaration* aggr)
|
IrAggr::IrAggr(AggregateDeclaration* aggr)
|
||||||
: aggrdecl(aggr),
|
: aggrdecl(aggr),
|
||||||
type(aggr->type),
|
type(aggr->type),
|
||||||
packed((type->ty == Tstruct) ? type->alignsize() == 1 : false),
|
|
||||||
// above still need to be looked at
|
// above still need to be looked at
|
||||||
init(0),
|
init(0),
|
||||||
constInit(0),
|
constInit(0),
|
||||||
|
@ -231,9 +230,9 @@ llvm::Constant* IrAggr::createInitializerConstant(
|
||||||
for (itr = constants.begin(); itr != end; ++itr)
|
for (itr = constants.begin(); itr != end; ++itr)
|
||||||
types.push_back((*itr)->getType());
|
types.push_back((*itr)->getType());
|
||||||
if (!initializerType)
|
if (!initializerType)
|
||||||
initializerType = LLStructType::get(gIR->context(), types, packed);
|
initializerType = LLStructType::get(gIR->context(), types, isPacked());
|
||||||
else
|
else
|
||||||
initializerType->setBody(types, packed);
|
initializerType->setBody(types, isPacked());
|
||||||
}
|
}
|
||||||
|
|
||||||
// build constant
|
// build constant
|
||||||
|
@ -258,10 +257,6 @@ void IrAggr::addFieldInitializers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool packed = (type->ty == Tstruct)
|
|
||||||
? type->alignsize() == 1
|
|
||||||
: false;
|
|
||||||
|
|
||||||
// Build up vector with one-to-one mapping to field indices.
|
// Build up vector with one-to-one mapping to field indices.
|
||||||
const size_t n = decl->fields.dim;
|
const size_t n = decl->fields.dim;
|
||||||
llvm::SmallVector<VarInitConst, 16> data(n);
|
llvm::SmallVector<VarInitConst, 16> data(n);
|
||||||
|
@ -342,7 +337,7 @@ void IrAggr::addFieldInitializers(
|
||||||
|
|
||||||
// get next aligned offset for this field
|
// get next aligned offset for this field
|
||||||
size_t alignedoffset = offset;
|
size_t alignedoffset = offset;
|
||||||
if (!packed)
|
if (!isPacked())
|
||||||
{
|
{
|
||||||
alignedoffset = realignOffset(alignedoffset, vd->type);
|
alignedoffset = realignOffset(alignedoffset, vd->type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,6 @@ struct IrAggr
|
||||||
/// Aggregate D type.
|
/// Aggregate D type.
|
||||||
Type* type;
|
Type* type;
|
||||||
|
|
||||||
/// true only for: align(1) struct S { ... }
|
|
||||||
bool packed;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Create the __initZ symbol lazily.
|
/// Create the __initZ symbol lazily.
|
||||||
|
@ -138,6 +135,9 @@ protected:
|
||||||
/// Create the Interface[] interfaces ClassInfo field initializer.
|
/// Create the Interface[] interfaces ClassInfo field initializer.
|
||||||
LLConstant* getClassInfoInterfaces();
|
LLConstant* getClassInfoInterfaces();
|
||||||
|
|
||||||
|
/// Returns true, if the LLVM struct type for the aggregate is declared as packed
|
||||||
|
bool isPacked() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Recursively adds all the initializers for the given aggregate and, in
|
/// Recursively adds all the initializers for the given aggregate and, in
|
||||||
/// case of a class type, all its base classes.
|
/// case of a class type, all its base classes.
|
||||||
|
|
|
@ -401,6 +401,11 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
|
||||||
return GV;
|
return GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IrAggr::isPacked() const
|
||||||
|
{
|
||||||
|
return static_cast<IrTypeAggr*>(type->ctype)->packed;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LLConstant * IrAggr::getClassInfoInterfaces()
|
LLConstant * IrAggr::getClassInfoInterfaces()
|
||||||
|
|
|
@ -245,6 +245,18 @@ IrTypeAggr::IrTypeAggr(AggregateDeclaration * ad)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IrTypeAggr::isPacked(AggregateDeclaration* ad)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < ad->fields.dim; i++)
|
||||||
|
{
|
||||||
|
VarDeclaration* vd = static_cast<VarDeclaration*>(ad->fields.data[i]);
|
||||||
|
unsigned a = vd->type->alignsize() - 1;
|
||||||
|
if (((vd->offset + a) & ~a) != vd->offset)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void IrTypeAggr::getMemberLocation(VarDeclaration* var, unsigned& fieldIndex,
|
void IrTypeAggr::getMemberLocation(VarDeclaration* var, unsigned& fieldIndex,
|
||||||
unsigned& byteOffset) const
|
unsigned& byteOffset) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,10 +68,17 @@ public:
|
||||||
/// used for resolving forward references.
|
/// used for resolving forward references.
|
||||||
llvm::DIType diCompositeType;
|
llvm::DIType diCompositeType;
|
||||||
|
|
||||||
|
/// true, if the LLVM struct type for the aggregate is declared as packed
|
||||||
|
bool packed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
///
|
///
|
||||||
IrTypeAggr(AggregateDeclaration* ad);
|
IrTypeAggr(AggregateDeclaration* ad);
|
||||||
|
|
||||||
|
/// Returns true, if the LLVM struct type for the aggregate must be declared
|
||||||
|
/// as packed.
|
||||||
|
static bool isPacked(AggregateDeclaration* ad);
|
||||||
|
|
||||||
/// AggregateDeclaration this type represents.
|
/// AggregateDeclaration this type represents.
|
||||||
AggregateDeclaration* aggr;
|
AggregateDeclaration* aggr;
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,14 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd)
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
IF_LOG Logger::println("Instance size: %u", cd->structsize);
|
IF_LOG Logger::println("Instance size: %u", cd->structsize);
|
||||||
|
|
||||||
AggrTypeBuilder builder(false);
|
// This class may contain an align declaration. See issue 726.
|
||||||
|
t->packed = false;
|
||||||
|
for (ClassDeclaration *base = cd; base != 0 && !t->packed; base = base->baseClass)
|
||||||
|
{
|
||||||
|
t->packed = isPacked(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
AggrTypeBuilder builder(t->packed);
|
||||||
|
|
||||||
// add vtbl
|
// add vtbl
|
||||||
builder.addType(llvm::PointerType::get(t->vtbl_type, 0), Target::ptrsize);
|
builder.addType(llvm::PointerType::get(t->vtbl_type, 0), Target::ptrsize);
|
||||||
|
@ -127,7 +134,7 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd)
|
||||||
fatal();
|
fatal();
|
||||||
|
|
||||||
// set struct body and copy GEP indices
|
// set struct body and copy GEP indices
|
||||||
isaStruct(t->type)->setBody(builder.defaultTypes(), false);
|
isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed);
|
||||||
t->varGEPIndices = builder.varGEPIndices();
|
t->varGEPIndices = builder.varGEPIndices();
|
||||||
|
|
||||||
// VTBL
|
// VTBL
|
||||||
|
|
|
@ -50,11 +50,18 @@ IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
|
||||||
if (sd->sizeok != SIZEOKdone)
|
if (sd->sizeok != SIZEOKdone)
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
|
t->packed = sd->alignment == 1;
|
||||||
|
if (!t->packed)
|
||||||
|
{
|
||||||
|
// Unfortunately, the previous check is not enough in case the struct
|
||||||
|
// contains an align declaration. See issue 726.
|
||||||
|
t->packed = isPacked(sd);
|
||||||
|
}
|
||||||
|
|
||||||
AggrTypeBuilder builder(sd->alignment == 1);
|
AggrTypeBuilder builder(t->packed);
|
||||||
builder.addAggregate(sd);
|
builder.addAggregate(sd);
|
||||||
builder.addTailPadding(sd->structsize);
|
builder.addTailPadding(sd->structsize);
|
||||||
isaStruct(t->type)->setBody(builder.defaultTypes(), sd->alignment == 1);
|
isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed);
|
||||||
t->varGEPIndices = builder.varGEPIndices();
|
t->varGEPIndices = builder.varGEPIndices();
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl;
|
IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9609c53f2ab74890200b5134b1f45597a2019189
|
Subproject commit 358b9d536f3c412524e8038ed610e3804dd140c9
|
Loading…
Add table
Add a link
Reference in a new issue