mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-26 00:23:14 +01:00
Fix #153. Factor out common code in StructLiteralExp::to(Const)Elem.
This commit is contained in:
158
gen/structs.cpp
158
gen/structs.cpp
@@ -298,6 +298,164 @@ Lpadding2:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits)
|
||||
{
|
||||
// get arrays
|
||||
size_t nvars = sd->fields.dim;
|
||||
VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
|
||||
|
||||
assert(inits.size() == nvars);
|
||||
|
||||
// first locate all explicit initializers
|
||||
std::vector<VarDeclaration*> explicitInits;
|
||||
for (size_t i=0; i < nvars; i++)
|
||||
{
|
||||
if (inits[i])
|
||||
{
|
||||
explicitInits.push_back(vars[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// vector of values to build aggregate from
|
||||
std::vector<llvm::Value*> values;
|
||||
|
||||
// offset trackers
|
||||
size_t lastoffset = 0;
|
||||
size_t lastsize = 0;
|
||||
|
||||
// index of next explicit init
|
||||
size_t exidx = 0;
|
||||
// number of explicit inits
|
||||
size_t nex = explicitInits.size();
|
||||
|
||||
// for through each field and build up the struct, padding with zeros
|
||||
size_t i;
|
||||
for (i=0; i<nvars; i++)
|
||||
{
|
||||
VarDeclaration* var = vars[i];
|
||||
|
||||
// get var info
|
||||
size_t os = var->offset;
|
||||
size_t sz = var->type->size();
|
||||
|
||||
// get next explicit
|
||||
VarDeclaration* nextVar = NULL;
|
||||
size_t nextOs = 0;
|
||||
if (exidx < nex)
|
||||
{
|
||||
nextVar = explicitInits[exidx];
|
||||
nextOs = nextVar->offset;
|
||||
}
|
||||
// none, rest is defaults
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// not explicit initializer, default initialize if there is room, otherwise skip
|
||||
if (!inits[i])
|
||||
{
|
||||
// default init if there is room
|
||||
// (past current offset) and (small enough to fit before next explicit)
|
||||
if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
|
||||
{
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("1added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// get field default init
|
||||
IrField* f = var->ir.irField;
|
||||
assert(f);
|
||||
if (!f->constInit)
|
||||
f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
|
||||
|
||||
values.push_back(f->constInit);
|
||||
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
//printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nextVar == var);
|
||||
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// add the expression value
|
||||
values.push_back(inits[i]);
|
||||
|
||||
// update offsets
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
|
||||
// go to next explicit init
|
||||
exidx++;
|
||||
|
||||
//printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
|
||||
// fill out rest with default initializers
|
||||
const LLType* structtype = DtoType(sd->type);
|
||||
size_t structsize = getABITypeSize(structtype);
|
||||
|
||||
// FIXME: this could probably share some code with the above
|
||||
if (structsize > lastoffset+lastsize)
|
||||
{
|
||||
for (/*continue from first loop*/; i < nvars; i++)
|
||||
{
|
||||
VarDeclaration* var = vars[i];
|
||||
|
||||
// get var info
|
||||
size_t os = var->offset;
|
||||
size_t sz = var->type->size();
|
||||
|
||||
// skip?
|
||||
if (os < lastoffset + lastsize)
|
||||
continue;
|
||||
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("2added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// get field default init
|
||||
IrField* f = var->ir.irField;
|
||||
assert(f);
|
||||
if (!f->constInit)
|
||||
f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
|
||||
|
||||
values.push_back(f->constInit);
|
||||
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
//printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
}
|
||||
|
||||
// add any 0 padding needed at the end of the literal
|
||||
if (structsize > lastoffset+lastsize)
|
||||
{
|
||||
//printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, structsize);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
|
||||
{
|
||||
Logger::println("indexing struct field %s:", vd->toPrettyChars());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
struct StructInitializer;
|
||||
|
||||
LLConstant* DtoConstStructInitializer(StructInitializer* si);
|
||||
std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits);
|
||||
|
||||
/**
|
||||
* Resolves the llvm type for a struct
|
||||
|
||||
237
gen/toir.cpp
237
gen/toir.cpp
@@ -860,15 +860,34 @@ LLConstant* CastExp::toConstElem(IRState* p)
|
||||
Logger::print("CastExp::toConstElem: %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
LLConstant* c = e1->toConstElem(p);
|
||||
LLConstant* res;
|
||||
const LLType* lltype = DtoType(type);
|
||||
Type* tb = to->toBasetype();
|
||||
|
||||
if(!isaPointer(c->getType()) || !isaPointer(lltype)) {
|
||||
error("can only cast pointers to pointers at code generation time, not %s to %s", type->toChars(), e1->type->toChars());
|
||||
fatal();
|
||||
// string literal to dyn array:
|
||||
// reinterpret the string data as an array, calculate the length
|
||||
if (e1->op == TOKstring && tb->ty == Tarray) {
|
||||
/* StringExp *strexp = (StringExp*)e1;
|
||||
size_t datalen = strexp->sz * strexp->len;
|
||||
Type* eltype = tb->nextOf()->toBasetype();
|
||||
if (datalen % eltype->size() != 0) {
|
||||
error("the sizes don't line up");
|
||||
return e1->toConstElem(p);
|
||||
}
|
||||
size_t arrlen = datalen / eltype->size();*/
|
||||
error("ct cast of string to dynamic array not fully implemented");
|
||||
return e1->toConstElem(p);
|
||||
}
|
||||
// pointer to pointer
|
||||
else if (tb->ty == Tpointer && e1->type->toBasetype()->ty == Tpointer) {
|
||||
res = llvm::ConstantExpr::getBitCast(e1->toConstElem(p), lltype);
|
||||
}
|
||||
else {
|
||||
error("can not cast %s to %s at compile time", e1->type->toChars(), type->toChars());
|
||||
return e1->toConstElem(p);
|
||||
}
|
||||
|
||||
return llvm::ConstantExpr::getBitCast(c, lltype);
|
||||
return res;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2364,161 +2383,23 @@ DValue* StructLiteralExp::toElem(IRState* p)
|
||||
Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// get arrays
|
||||
// get inits
|
||||
std::vector<LLValue*> inits(sd->fields.dim, NULL);
|
||||
|
||||
size_t nexprs = elements->dim;;
|
||||
Expression** exprs = (Expression**)elements->data;
|
||||
|
||||
size_t nvars = sd->fields.dim;
|
||||
VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
|
||||
|
||||
assert(nexprs <= nvars);
|
||||
|
||||
// first locate all explicit initializers
|
||||
std::vector<VarDeclaration*> explicitInits;
|
||||
for (size_t i=0; i < nexprs; i++)
|
||||
for (size_t i = 0; i < nexprs; i++)
|
||||
{
|
||||
if (exprs[i])
|
||||
{
|
||||
explicitInits.push_back(vars[i]);
|
||||
DValue* v = exprs[i]->toElem(p);
|
||||
inits[i] = v->getRVal();
|
||||
}
|
||||
}
|
||||
|
||||
// vector of values to build aggregate from
|
||||
std::vector<llvm::Value*> values;
|
||||
|
||||
// offset trackers
|
||||
size_t lastoffset = 0;
|
||||
size_t lastsize = 0;
|
||||
|
||||
// index of next explicit init
|
||||
size_t exidx = 0;
|
||||
// number of explicit inits
|
||||
size_t nex = explicitInits.size();
|
||||
|
||||
// for through each field and build up the struct, padding with zeros
|
||||
size_t i;
|
||||
for (i=0; i<nvars; i++)
|
||||
{
|
||||
Expression* e = (nexprs > i) ? exprs[i] : NULL;
|
||||
VarDeclaration* var = vars[i];
|
||||
|
||||
// get var info
|
||||
size_t os = var->offset;
|
||||
size_t sz = var->type->size();
|
||||
|
||||
// get next explicit
|
||||
VarDeclaration* nextVar = NULL;
|
||||
size_t nextOs = 0;
|
||||
if (exidx < nex)
|
||||
{
|
||||
nextVar = explicitInits[exidx];
|
||||
nextOs = nextVar->offset;
|
||||
}
|
||||
// none, rest is defaults
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// not explicit initializer, default initialize if there is room, otherwise skip
|
||||
if (!e)
|
||||
{
|
||||
// default init if there is room
|
||||
// (past current offset) and (small enough to fit before next explicit)
|
||||
if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
|
||||
{
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("1added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// get field default init
|
||||
IrField* f = var->ir.irField;
|
||||
assert(f);
|
||||
if (!f->constInit)
|
||||
f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
|
||||
|
||||
values.push_back(f->constInit);
|
||||
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
//printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nextVar == var);
|
||||
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// add the expression value
|
||||
DValue* v = e->toElem(p);
|
||||
values.push_back(v->getRVal());
|
||||
|
||||
// update offsets
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
|
||||
// go to next explicit init
|
||||
exidx++;
|
||||
|
||||
//printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
|
||||
// fill out rest with default initializers
|
||||
const LLType* structtype = DtoType(sd->type);
|
||||
size_t structsize = getABITypeSize(structtype);
|
||||
|
||||
// FIXME: this could probably share some code with the above
|
||||
if (structsize > lastoffset+lastsize)
|
||||
{
|
||||
for (/*continue from first loop*/; i < nvars; i++)
|
||||
{
|
||||
VarDeclaration* var = vars[i];
|
||||
|
||||
// get var info
|
||||
size_t os = var->offset;
|
||||
size_t sz = var->type->size();
|
||||
|
||||
// skip?
|
||||
if (os < lastoffset + lastsize)
|
||||
continue;
|
||||
|
||||
// add any 0 padding needed before this field
|
||||
if (os > lastoffset + lastsize)
|
||||
{
|
||||
//printf("2added %lu zeros\n", os - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, os);
|
||||
}
|
||||
|
||||
// get field default init
|
||||
IrField* f = var->ir.irField;
|
||||
assert(f);
|
||||
if (!f->constInit)
|
||||
f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
|
||||
|
||||
values.push_back(f->constInit);
|
||||
|
||||
lastoffset = os;
|
||||
lastsize = sz;
|
||||
//printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
|
||||
}
|
||||
}
|
||||
|
||||
// add any 0 padding needed at the end of the literal
|
||||
if (structsize > lastoffset+lastsize)
|
||||
{
|
||||
//printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
|
||||
addZeros(values, lastoffset + lastsize, structsize);
|
||||
}
|
||||
std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
|
||||
|
||||
// get the struct type from the values
|
||||
size_t n = values.size();
|
||||
@@ -2542,6 +2423,7 @@ DValue* StructLiteralExp::toElem(IRState* p)
|
||||
}
|
||||
|
||||
// cast the alloca pointer to the "formal" struct type
|
||||
const LLType* structtype = DtoType(sd->type);
|
||||
mem = DtoBitCast(mem, getPtrToType(structtype));
|
||||
|
||||
// return as a var
|
||||
@@ -2555,55 +2437,26 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p)
|
||||
Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// get arrays
|
||||
size_t n = elements->dim;
|
||||
// get inits
|
||||
std::vector<LLValue*> inits(sd->fields.dim, NULL);
|
||||
|
||||
size_t nexprs = elements->dim;;
|
||||
Expression** exprs = (Expression**)elements->data;
|
||||
|
||||
assert(sd->fields.dim == n);
|
||||
VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
|
||||
for (size_t i = 0; i < nexprs; i++)
|
||||
if (exprs[i])
|
||||
inits[i] = exprs[i]->toConstElem(p);
|
||||
|
||||
// vector of values to build aggregate from
|
||||
std::vector<llvm::Constant*> values;
|
||||
std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
|
||||
|
||||
// trackers
|
||||
size_t lastoffset = 0;
|
||||
size_t lastsize = 0;
|
||||
|
||||
// for through each field and build up the struct, padding with zeros
|
||||
for (size_t i=0; i<n; i++)
|
||||
{
|
||||
Expression* e = exprs[i];
|
||||
VarDeclaration* var = vars[i];
|
||||
|
||||
// field is skipped
|
||||
if (!e)
|
||||
continue;
|
||||
|
||||
// add any 0 padding needed before this field
|
||||
if (var->offset > lastoffset + lastsize)
|
||||
{
|
||||
addZeros(values, lastoffset + lastsize, var->offset);
|
||||
}
|
||||
|
||||
// add the expression value
|
||||
values.push_back(e->toConstElem(p));
|
||||
|
||||
// update offsets
|
||||
lastoffset = var->offset;
|
||||
lastsize = var->type->size();
|
||||
}
|
||||
|
||||
// add any 0 padding needed at the end of the literal
|
||||
const LLType* structtype = DtoType(sd->type);
|
||||
size_t structsize = getABITypeSize(structtype);
|
||||
|
||||
if (structsize > lastoffset+lastsize)
|
||||
{
|
||||
addZeros(values, lastoffset + lastsize, structsize);
|
||||
}
|
||||
// we know those values are constants.. cast them
|
||||
std::vector<LLConstant*> constvals(values.size(), NULL);
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
constvals[i] = llvm::cast<LLConstant>(values[i]);
|
||||
|
||||
// return constant struct
|
||||
return LLConstantStruct::get(values, sd->ir.irStruct->packed);
|
||||
return LLConstantStruct::get(constvals, sd->ir.irStruct->packed);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user