Respect alignments of captured variables when building nested context LL struct

This commit is contained in:
Martin 2015-10-18 23:25:37 +02:00
parent 05c10d9107
commit 93158caca8
7 changed files with 40 additions and 25 deletions

View file

@ -16,6 +16,7 @@
#include "gen/logger.h" #include "gen/logger.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "ir/irfunction.h" #include "ir/irfunction.h"
#include "ir/irtypeaggr.h"
#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/ValueTracking.h"
/****************************************************************************************/ /****************************************************************************************/
@ -334,24 +335,17 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd)
IF_LOG Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; IF_LOG Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
typedef std::vector<LLType*> TypeVec; AggrTypeBuilder builder(false);
TypeVec types;
if (depth != 0) if (depth != 0)
{ {
assert(innerFrameType); assert(innerFrameType);
unsigned ptrSize = gDataLayout->getPointerSize();
// Add frame pointer types for all but last frame // Add frame pointer types for all but last frame
for (unsigned i = 0; i < (depth - 1); ++i) for (unsigned i = 0; i < (depth - 1); ++i)
types.push_back(innerFrameType->getElementType(i)); builder.addType(innerFrameType->getElementType(i), ptrSize);
// Add frame pointer type for last frame // Add frame pointer type for last frame
types.push_back(LLPointerType::getUnqual(innerFrameType)); builder.addType(LLPointerType::getUnqual(innerFrameType), ptrSize);
}
if (Logger::enabled() && depth != 0)
{
Logger::println("Frame types: ");
LOG_SCOPE;
for (TypeVec::iterator i = types.begin(); i != types.end(); ++i)
Logger::cout() << **i << '\n';
} }
// Add the direct nested variables of this function, and update their indices to match. // Add the direct nested variables of this function, and update their indices to match.
@ -361,10 +355,16 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd)
I != E; ++I) I != E; ++I)
{ {
VarDeclaration* vd = *I; VarDeclaration* vd = *I;
unsigned alignment = DtoAlignment(vd);
if (alignment > 1)
builder.alignCurrentOffset(alignment);
IrLocal& irLocal = *getIrLocal(vd, true); IrLocal& irLocal = *getIrLocal(vd, true);
irLocal.nestedIndex = types.size(); irLocal.nestedIndex = builder.currentFieldIndex();
irLocal.nestedDepth = depth; irLocal.nestedDepth = depth;
LLType* t = NULL;
if (vd->isParameter() && getIrParameter(vd)->arg) if (vd->isParameter() && getIrParameter(vd)->arg)
{ {
// Parameters that are part of the LLVM signature will have // Parameters that are part of the LLVM signature will have
@ -380,29 +380,32 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd)
{ {
// This will be copied to the nesting frame. // This will be copied to the nesting frame.
if (lazy) if (lazy)
types.push_back(irparam->value->getType()->getContainedType(0)); t = irparam->value->getType()->getContainedType(0);
else else
types.push_back(DtoMemType(vd->type)); t = DtoMemType(vd->type);
} }
else else
types.push_back(irparam->value->getType()); t = irparam->value->getType();
} }
else if (isSpecialRefVar(vd)) else if (isSpecialRefVar(vd))
types.push_back(DtoType(vd->type->pointerTo())); t = DtoType(vd->type->pointerTo());
else else
types.push_back(DtoMemType(vd->type)); t = DtoMemType(vd->type);
builder.addType(t, getTypeAllocSize(t));
IF_LOG Logger::cout() << "Nested var '" << vd->toChars() IF_LOG Logger::cout() << "Nested var '" << vd->toChars()
<< "' of type " << *types.back() << "\n"; << "' of type " << *t << "\n";
} }
LLStructType* frameType = LLStructType::create(gIR->context(), types, LLStructType* frameType = LLStructType::create(gIR->context(), builder.defaultTypes(),
std::string("nest.") + fd->toChars()); std::string("nest.") + fd->toChars());
IF_LOG Logger::cout() << "frameType = " << *frameType << '\n'; IF_LOG Logger::cout() << "frameType = " << *frameType << '\n';
// Store type in IrFunction // Store type in IrFunction
irFunc.frameType = frameType; irFunc.frameType = frameType;
irFunc.frameTypeAlignment = builder.overallAlignment();
} }
else // no captured variables else // no captured variables
{ {
@ -411,6 +414,7 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd)
// Propagate context arg properties if the context arg is passed on unmodified. // Propagate context arg properties if the context arg is passed on unmodified.
IrFunction& parentIrFunc = *getIrFunc(parentFunc); IrFunction& parentIrFunc = *getIrFunc(parentFunc);
irFunc.frameType = parentIrFunc.frameType; irFunc.frameType = parentIrFunc.frameType;
irFunc.frameTypeAlignment = parentIrFunc.frameTypeAlignment;
irFunc.depth = parentIrFunc.depth; irFunc.depth = parentIrFunc.depth;
} }
} }
@ -430,13 +434,18 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
unsigned depth = irfunction->depth; unsigned depth = irfunction->depth;
LLStructType *frameType = irfunction->frameType; LLStructType *frameType = irfunction->frameType;
// Create frame for current function and append to frames list // Create frame for current function and append to frames list
// FIXME: alignment ?
LLValue* frame = 0; LLValue* frame = 0;
bool needsClosure = fd->needsClosure(); bool needsClosure = fd->needsClosure();
if (needsClosure) if (needsClosure)
{
// FIXME: alignment ?
frame = DtoGcMalloc(fd->loc, frameType, ".frame"); frame = DtoGcMalloc(fd->loc, frameType, ".frame");
}
else else
frame = DtoRawAlloca(frameType, 0, ".frame"); {
unsigned alignment = std::max(getABITypeAlign(frameType), irfunction->frameTypeAlignment);
frame = DtoRawAlloca(frameType, alignment, ".frame");
}
// copy parent frames into beginning // copy parent frames into beginning
if (depth != 0) { if (depth != 0) {

View file

@ -723,7 +723,7 @@ size_t getTypeAllocSize(LLType* t)
return gDataLayout->getTypeAllocSize(t); return gDataLayout->getTypeAllocSize(t);
} }
unsigned char getABITypeAlign(LLType* t) unsigned int getABITypeAlign(LLType* t)
{ {
return gDataLayout->getABITypeAlignment(t); return gDataLayout->getABITypeAlignment(t);
} }

View file

@ -131,7 +131,7 @@ size_t getTypePaddedSize(LLType* t);
size_t getTypeAllocSize(LLType* t); size_t getTypeAllocSize(LLType* t);
// type alignments // type alignments
unsigned char getABITypeAlign(LLType* t); unsigned int getABITypeAlign(LLType* t);
// pair type helpers // pair type helpers
LLValue* DtoAggrPair(LLType* type, LLValue* V1, LLValue* V2, const char* name = ""); LLValue* DtoAggrPair(LLType* type, LLValue* V1, LLValue* V2, const char* name = "");

View file

@ -423,6 +423,7 @@ IrFunction::IrFunction(FuncDeclaration* fd) {
nestedVar = NULL; nestedVar = NULL;
frameType = NULL; frameType = NULL;
frameTypeAlignment = 0;
depth = -1; depth = -1;
nestedContextCreated = false; nestedContextCreated = false;

View file

@ -411,6 +411,7 @@ struct IrFunction {
llvm::Value* nestedVar; // alloca for the nested context of this function llvm::Value* nestedVar; // alloca for the nested context of this function
llvm::StructType* frameType; // type of nested context llvm::StructType* frameType; // type of nested context
unsigned frameTypeAlignment; // its alignment
// number of enclosing functions with variables accessed by nested functions // number of enclosing functions with variables accessed by nested functions
// (-1 if neither this function nor any enclosing ones access variables from enclosing functions) // (-1 if neither this function nor any enclosing ones access variables from enclosing functions)
int depth; int depth;

View file

@ -50,7 +50,7 @@ bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
} }
AggrTypeBuilder::AggrTypeBuilder(bool packed) : AggrTypeBuilder::AggrTypeBuilder(bool packed) :
m_offset(0), m_fieldIndex(0), m_packed(packed) m_offset(0), m_fieldIndex(0), m_overallAlignment(0), m_packed(packed)
{ {
m_defaultTypes.reserve(32); m_defaultTypes.reserve(32);
} }
@ -192,6 +192,8 @@ void AggrTypeBuilder::addAggregate(AggregateDeclaration *ad)
void AggrTypeBuilder::alignCurrentOffset(unsigned alignment) void AggrTypeBuilder::alignCurrentOffset(unsigned alignment)
{ {
m_overallAlignment = std::max(alignment, m_overallAlignment);
unsigned aligned = (m_offset + alignment - 1) & ~(alignment - 1); unsigned aligned = (m_offset + alignment - 1) & ~(alignment - 1);
if (m_offset < aligned) { if (m_offset < aligned) {
m_fieldIndex += add_zeros(m_defaultTypes, m_offset, aligned); m_fieldIndex += add_zeros(m_defaultTypes, m_offset, aligned);

View file

@ -43,11 +43,13 @@ public:
unsigned currentFieldIndex() const { return m_fieldIndex; } unsigned currentFieldIndex() const { return m_fieldIndex; }
std::vector<llvm::Type*> defaultTypes() const { return m_defaultTypes; } std::vector<llvm::Type*> defaultTypes() const { return m_defaultTypes; }
VarGEPIndices varGEPIndices() const { return m_varGEPIndices; } VarGEPIndices varGEPIndices() const { return m_varGEPIndices; }
unsigned overallAlignment() const { return m_overallAlignment; }
protected: protected:
std::vector<llvm::Type*> m_defaultTypes; std::vector<llvm::Type*> m_defaultTypes;
VarGEPIndices m_varGEPIndices; VarGEPIndices m_varGEPIndices;
unsigned m_offset; unsigned m_offset;
unsigned m_fieldIndex; unsigned m_fieldIndex;
unsigned m_overallAlignment;
bool m_packed; bool m_packed;
}; };