Merge pull request #556 from klickverbot/padding-fix

Respect type alignment when choosing zero fill types.
This commit is contained in:
David Nadlinger
2013-12-26 03:36:17 -08:00
5 changed files with 70 additions and 45 deletions

View File

@@ -121,9 +121,6 @@ LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
//////////////////////////////////////////////////////////////////////////////////////////
// helper function that adds zero bytes to a vector of constants
extern size_t add_zeros(std::vector<LLConstant*>& values, size_t diff);
/// Return the type returned by DtoUnpaddedStruct called on a value of the
/// specified type.
/// Union types will get expanded into a struct, with a type for each member.

View File

@@ -87,34 +87,50 @@ llvm::Constant * IrAggr::getDefaultInit()
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static bool isAligned(llvm::Type* type, size_t offset) {
return gDataLayout->getABITypeAlignment(type) % offset == 0;
}
// helper function that adds zero bytes to a vector of constants
size_t add_zeros(llvm::SmallVectorImpl<llvm::Constant*>& constants, size_t diff)
size_t add_zeros(llvm::SmallVectorImpl<llvm::Constant*>& constants,
size_t startOffset, size_t endOffset)
{
size_t n = constants.size();
while (diff)
size_t const oldLength = constants.size();
llvm::Type* const eightByte = llvm::Type::getInt64Ty(gIR->context());
llvm::Type* const fourByte = llvm::Type::getInt32Ty(gIR->context());
llvm::Type* const twoByte = llvm::Type::getInt16Ty(gIR->context());
assert(startOffset <= endOffset);
size_t paddingLeft = endOffset - startOffset;
while (paddingLeft)
{
if (global.params.is64bit && diff % 8 == 0)
if (global.params.is64bit && paddingLeft >= 8 && isAligned(eightByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt64Ty(gIR->context())));
diff -= 8;
constants.push_back(llvm::Constant::getNullValue(eightByte));
startOffset += 8;
}
else if (diff % 4 == 0)
else if (paddingLeft >= 4 && isAligned(fourByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt32Ty(gIR->context())));
diff -= 4;
constants.push_back(llvm::Constant::getNullValue(fourByte));
startOffset += 4;
}
else if (diff % 2 == 0)
else if (paddingLeft >= 2 && isAligned(twoByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt16Ty(gIR->context())));
diff -= 2;
constants.push_back(llvm::Constant::getNullValue(twoByte));
startOffset += 2;
}
else
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt8Ty(gIR->context())));
diff -= 1;
constants.push_back(llvm::Constant::getNullValue(
llvm::Type::getInt8Ty(gIR->context())));
startOffset += 1;
}
paddingLeft = endOffset - startOffset;
}
return constants.size() - n;
return constants.size() - oldLength;
}
//////////////////////////////////////////////////////////////////////////////
@@ -263,9 +279,7 @@ llvm::Constant* IrAggr::createInitializerConstant(
const size_t structsize = type->size();
if (offset < structsize)
{
size_t diff = structsize - offset;
IF_LOG Logger::println("adding %zu bytes zero padding", diff);
add_zeros(constants, diff);
add_zeros(constants, offset, structsize);
}
// get initializer type
@@ -386,9 +400,7 @@ void IrAggr::addFieldInitializers(
// insert explicit padding?
if (alignedoffset < vd->offset)
{
size_t diff = vd->offset - alignedoffset;
IF_LOG Logger::println("adding %zu bytes zero padding", diff);
add_zeros(constants, diff);
add_zeros(constants, alignedoffset, vd->offset);
}
IF_LOG Logger::println("adding field %s", vd->toChars());

View File

@@ -37,7 +37,6 @@
//////////////////////////////////////////////////////////////////////////////
extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init);
extern size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff);
extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);

View File

@@ -30,7 +30,8 @@
//////////////////////////////////////////////////////////////////////////////
extern size_t add_zeros(std::vector<llvm::Type*>& defaultTypes, size_t diff);
extern size_t add_zeros(std::vector<llvm::Type*>& defaultTypes,
size_t startOffset, size_t endOffset);
extern bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2);
//////////////////////////////////////////////////////////////////////////////
@@ -167,7 +168,7 @@ void IrTypeClass::addBaseClassData(
// insert explicit padding?
if (alignedoffset < vd->offset)
{
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
field_index += add_zeros(defaultTypes, alignedoffset, vd->offset);
}
// add default type
@@ -220,7 +221,7 @@ void IrTypeClass::addBaseClassData(
// tail padding?
if (offset < base->structsize)
{
field_index += add_zeros(defaultTypes, base->structsize - offset);
field_index += add_zeros(defaultTypes, offset, base->structsize);
offset = base->structsize;
}
#endif
@@ -268,7 +269,7 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd)
// tail padding?
if (offset < cd->structsize)
{
field_index += add_zeros(defaultTypes, cd->structsize - offset);
field_index += add_zeros(defaultTypes, offset, cd->structsize);
offset = cd->structsize;
}
#endif

View File

@@ -38,35 +38,51 @@ IrTypeStruct::IrTypeStruct(StructDeclaration * sd)
//////////////////////////////////////////////////////////////////////////////
size_t add_zeros(std::vector<llvm::Type*>& defaultTypes, size_t diff)
static bool isAligned(llvm::Type* type, size_t offset) {
return gDataLayout->getABITypeAlignment(type) % offset == 0;
}
size_t add_zeros(std::vector<llvm::Type*>& defaultTypes,
size_t startOffset, size_t endOffset)
{
size_t n = defaultTypes.size();
while (diff)
size_t const oldLength = defaultTypes.size();
llvm::Type* const eightByte = llvm::Type::getInt64Ty(gIR->context());
llvm::Type* const fourByte = llvm::Type::getInt32Ty(gIR->context());
llvm::Type* const twoByte = llvm::Type::getInt16Ty(gIR->context());
assert(startOffset <= endOffset);
size_t paddingLeft = endOffset - startOffset;
while (paddingLeft)
{
if (global.params.is64bit && diff % 8 == 0)
if (global.params.is64bit && paddingLeft >= 8 && isAligned(eightByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt64Ty(gIR->context()));
diff -= 8;
defaultTypes.push_back(eightByte);
startOffset += 8;
}
else if (diff % 4 == 0)
else if (paddingLeft >= 4 && isAligned(fourByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt32Ty(gIR->context()));
diff -= 4;
defaultTypes.push_back(fourByte);
startOffset += 4;
}
else if (diff % 2 == 0)
else if (paddingLeft >= 2 && isAligned(twoByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt16Ty(gIR->context()));
diff -= 2;
defaultTypes.push_back(twoByte);
startOffset += 2;
}
else
{
defaultTypes.push_back(llvm::Type::getInt8Ty(gIR->context()));
diff -= 1;
startOffset += 1;
}
paddingLeft = endOffset - startOffset;
}
return defaultTypes.size() - n;
return defaultTypes.size() - oldLength;
}
bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
{
if (v1 && v2)
@@ -209,7 +225,7 @@ IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
// insert explicit padding?
if (alignedoffset < vd->offset)
{
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
field_index += add_zeros(defaultTypes, alignedoffset, vd->offset);
}
// add default type
@@ -225,7 +241,7 @@ IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
// tail padding?
if (offset < sd->structsize)
{
add_zeros(defaultTypes, sd->structsize - offset);
add_zeros(defaultTypes, offset, sd->structsize);
}
// set struct body