Rewrote runtime struct literal codegen.

This commit is contained in:
Tomas Lindquist Olsen
2009-04-22 03:08:28 +02:00
parent f6f12e4241
commit 687395cda6
3 changed files with 156 additions and 30 deletions

View File

@@ -1186,6 +1186,78 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp)
//////////////////////////////////////////////////////////////////////////////////////////
static LLValue* expand_value_to_sarray(Type *base, Expression* exp)
{
Logger::println("building type %s from expression (%s) of type %s", base->toChars(), exp->toChars(), exp->type->toChars());
const LLType* dstTy = DtoType(base);
if (Logger::enabled())
Logger::cout() << "final llvm type requested: " << *dstTy << '\n';
// get initial value
LLValue* val = exp->toElem(gIR)->getRVal();
if (DtoIsPassedByRef(exp->type))
val = DtoLoad(val);
Type* expbase = exp->type->toBasetype();
Logger::println("expbase: %s", expbase->toChars());
Type* t = base->toBasetype();
LLSmallVector<size_t, 4> dims;
while(1)
{
Logger::println("t: %s", t->toChars());
if (t->equals(expbase))
break;
assert(t->ty == Tsarray);
TypeSArray* tsa = (TypeSArray*)t;
dims.push_back(tsa->dim->toInteger());
assert(t->nextOf());
t = t->nextOf()->toBasetype();
}
size_t i = dims.size();
assert(i);
std::vector<LLValue*> inits;
while (i--)
{
// start with undefined array
const LLArrayType* arrty = LLArrayType::get(val->getType(), dims[i]);
LLValue* tmp = llvm::UndefValue::get(arrty);
for (size_t j = 0; j < dims[i]; j++)
{
tmp = gIR->ir->CreateInsertValue(tmp, val, j);
}
val = tmp;
}
return val;
}
LLValue* DtoExprValue(Type* type, Expression* e)
{
Type* t1 = e->type->toBasetype();
Type* t2 = type->toBasetype();
// expand static arrays
if (t2->ty == Tsarray && !t1->equals(t2))
{
return expand_value_to_sarray(t2, e);
}
// or not
else
{
DValue* dv = e->toElem(gIR);
LLValue* v = dv->getRVal();
if (DtoIsPassedByRef(e->type))
v = DtoLoad(v);
return v;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoAnnotation(const char* str)
{
std::string s("CODE: ");

View File

@@ -102,6 +102,8 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init);
LLConstant* DtoConstExpInit(Loc loc, Type* t, Expression* exp);
DValue* DtoInitializer(LLValue* target, Initializer* init);
LLValue* DtoExprValue(Type* type, Expression* e);
// annotation generator
void DtoAnnotation(const char* str);

View File

@@ -37,6 +37,7 @@
#include "gen/functions.h"
#include "gen/todebug.h"
#include "gen/nested.h"
#include "gen/utils.h"
#include "llvm/Support/ManagedStatic.h"
@@ -2404,60 +2405,111 @@ LLConstant* ArrayLiteralExp::toConstElem(IRState* p)
//////////////////////////////////////////////////////////////////////////////////////////
// building a struct literal is pretty much the same as building a default initializer.
extern size_t add_zeros(std::vector<llvm::Value*>& values, size_t diff);
extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init);
DValue* StructLiteralExp::toElem(IRState* p)
{
Logger::print("StructLiteralExp::toElem: %s @ %s\n", toChars(), type->toChars());
LOG_SCOPE;
// make sure the struct is resolved
// make sure the struct is fully resolved
sd->codegen(Type::sir);
// get inits
std::vector<LLValue*> inits(sd->fields.dim, NULL);
// final list of values to put in the struct
std::vector<LLValue*> initvalues;
// offset tracker
size_t offset = 0;
// align(1) struct S { ... }
bool packed = sd->type->alignsize() == 1;
// ready elements data
assert(elements && "struct literal has null elements");
size_t nexprs = elements->dim;;
Expression** exprs = (Expression**)elements->data;
for (size_t i = 0; i < nexprs; i++)
// go through fields
ArrayIter<VarDeclaration> it(sd->fields);
for (; !it.done(); it.next())
{
if (exprs[i])
VarDeclaration* vd = it.get();
if (vd->offset < offset)
{
DValue* v = exprs[i]->toElem(p);
inits[i] = v->getRVal();
// make sure we get inner structs/staticarrays right
if (DtoIsPassedByRef(v->getType()))
inits[i] = DtoLoad(inits[i]);
IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
continue;
}
IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
// get next aligned offset for this field
size_t alignedoffset = offset;
if (!packed)
{
size_t alignsize = vd->type->alignsize();
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
}
// insert explicit padding?
if (alignedoffset < vd->offset)
{
add_zeros(initvalues, vd->offset - alignedoffset);
}
// add initializer
Expression* expr = (it.index < nexprs) ? exprs[it.index] : NULL;
IF_LOG Logger::println("expr: %p", expr);
if (expr)
{
IF_LOG Logger::println("expr = %s", it.index, expr->toChars());
LLValue* v = DtoExprValue(vd->type, expr);
initvalues.push_back(v);
}
else
{
IF_LOG Logger::println("using default initializer");
initvalues.push_back(get_default_initializer(vd, NULL));
}
// advance offset to right past this field
offset = vd->offset + vd->type->size();
}
// vector of values to build aggregate from
std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
// get the struct type from the values
size_t n = values.size();
std::vector<const LLType*> types(n, NULL);
for (size_t i=0; i<n; i++)
// tail padding?
if (offset < sd->structsize)
{
types[i] = values[i]->getType();
add_zeros(initvalues, sd->structsize - offset);
}
const LLStructType* sty = LLStructType::get(types, sd->ir.irStruct->packed);
// build type
std::vector<const LLType*> valuetypes;
// allocate storage for the struct literal on the stack
LLValue* mem = DtoAlloca(sty, "tmpstructliteral");
size_t n = initvalues.size();
valuetypes.reserve(n);
// put all the values into the storage
for (size_t i=0; i<n; i++)
for (size_t i = 0; i < n; i++)
{
LLValue* ptr = DtoGEPi(mem, 0, i);
DtoStore(values[i], ptr);
valuetypes.push_back(initvalues[i]->getType());
}
// cast the alloca pointer to the "formal" struct type
const LLType* structtype = DtoType(sd->type);
mem = DtoBitCast(mem, getPtrToType(structtype));
const LLType* st = llvm::StructType::get(valuetypes, packed);
// alloca a stack slot
LLValue* mem = DtoAlloca(st, ".structliteral");
// fill in values
for (size_t i = 0; i < n; i++)
{
LLValue* addr = DtoGEPi(mem, 0, i);
p->ir->CreateStore(initvalues[i], addr);
}
// cast to default struct type
mem = DtoBitCast(mem, DtoType(sd->type->pointerTo()));
// return as a var
return new DVarValue(type, mem);