Factored actual literal building code out of ArrayLiteralExp::toElem.

This commit is contained in:
David Nadlinger
2013-10-09 01:04:23 +02:00
parent d51d05c52e
commit 44f60199ad
3 changed files with 108 additions and 83 deletions

View File

@@ -11,6 +11,7 @@
#include "aggregate.h"
#include "declaration.h"
#include "dsymbol.h"
#include "expression.h"
#include "init.h"
#include "module.h"
#include "mtype.h"
@@ -387,6 +388,98 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
return DtoConstSlice(DtoConstSize_t(arrlen), gep, arrty);
}
//////////////////////////////////////////////////////////////////////////////////////////
void initializeArrayLiteral(IRState* p, ArrayLiteralExp* ale, LLValue* dstMem)
{
Type* const arrayType = ale->type->toBasetype();
Type* const elemType = arrayType->nextOf()->toBasetype();
size_t const len = ale->elements->dim;
// Check for const'ness
bool isAllConst = true;
for (size_t i = 0; i < len && isAllConst; ++i)
{
Expression *expr = static_cast<Expression *>(ale->elements->data[i]);
isAllConst = expr->isConst() == 1;
}
if (isAllConst)
{
// allocate room for initializers
std::vector<LLConstant *> initvals(len, NULL);
LLType* llElemType = voidToI8(DtoType(elemType));
// true if array elements differ in type
bool mismatch = false;
// store elements
for (size_t i = 0; i < len; ++i)
{
Expression *expr = static_cast<Expression *>(ale->elements->data[i]);
llvm::Constant *c = expr->toConstElem(gIR);
if (llElemType != c->getType())
mismatch = true;
initvals[i] = c;
}
LLConstant *constarr;
if (mismatch)
constarr = LLConstantStruct::getAnon(gIR->context(), initvals); // FIXME should this pack?;
else
constarr = LLConstantArray::get(LLArrayType::get(llElemType, len), initvals);
#if LDC_LLVM_VER == 301
// Simply storing the constant array triggers a problem in LLVM 3.1.
// With -O3 the statement
// void[0] sa0 = (void[0]).init;
// is compiled to
// tail call void @llvm.trap()
// which is not what we want!
// Therefore a global variable is always used.
LLGlobalVariable *gvar = new LLGlobalVariable(
*gIR->module,
constarr->getType(),
true,
LLGlobalValue::InternalLinkage,
constarr,
".constarrayliteral_init"
);
DtoMemCpy(dstMem, gvar, DtoConstSize_t(getTypePaddedSize(constarr->getType())));
#else
// If the type pointed to by dstMem is different from the array type
// then we must assign the value to a global variable.
if (constarr->getType() != dstMem->getType()->getPointerElementType())
{
LLGlobalVariable *gvar = new LLGlobalVariable(
*gIR->module,
constarr->getType(),
true,
LLGlobalValue::InternalLinkage,
constarr,
".constarrayliteral_init"
);
DtoMemCpy(dstMem, gvar, DtoConstSize_t(getTypePaddedSize(constarr->getType())));
}
else
DtoStore(constarr, dstMem);
#endif
}
else
{
// store elements
for (size_t i = 0; i < len; ++i)
{
LLValue *elemAddr = DtoGEPi(dstMem, 0, i, "tmp", p->scopebb());
// emulate assignment
DVarValue *vv = new DVarValue((*ale->elements)[i]->type, elemAddr);
DValue *e = (*ale->elements)[i]->toElem(p);
DtoAssign(ale->loc, vv, e);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz)
{

View File

@@ -18,9 +18,11 @@
#include "gen/llvm.h"
struct ArrayInitializer;
struct ArrayLiteralExp;
class DSliceValue;
class DValue;
struct Expression;
struct IRState;
struct Loc;
struct Type;
@@ -32,6 +34,11 @@ LLType* DtoConstArrayInitializerType(ArrayInitializer* arrinit);
LLConstant* DtoConstArrayInitializer(ArrayInitializer* si);
LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr, Type *type = 0);
/// Initializes a chunk of memory with the contents of an array literal.
///
/// dstMem is expected to be a pointer to the array allocation.
void initializeArrayLiteral(IRState* p, ArrayLiteralExp* ale, LLValue* dstMem);
void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src);
void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src);

View File

@@ -2873,94 +2873,19 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
}
// dst pointer
LLValue* dstMem;
DSliceValue* dynSlice = NULL;
if(dyn)
if (dyn)
{
dynSlice = DtoNewDynArray(loc, arrayType, new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false);
dstMem = dynSlice->ptr;
}
else
dstMem = DtoRawAlloca(llStoType, 0, "arrayliteral");
// Check for const'ness
bool isAllConst = true;
for (size_t i = 0; i < len && isAllConst; ++i)
{
Expression *expr = static_cast<Expression *>(elements->data[i]);
isAllConst = expr->isConst() == 1;
}
if (isAllConst)
{
// allocate room for initializers
std::vector<LLConstant *> initvals(len, NULL);
// true if array elements differ in type
bool mismatch = false;
// store elements
for (size_t i = 0; i < len; ++i)
{
Expression *expr = static_cast<Expression *>(elements->data[i]);
llvm::Constant *c = expr->toConstElem(gIR);
if (llElemType != c->getType())
mismatch = true;
initvals[i] = c;
}
LLConstant *constarr;
if (mismatch)
constarr = LLConstantStruct::getAnon(gIR->context(), initvals); // FIXME should this pack?;
else
constarr = LLConstantArray::get(LLArrayType::get(llElemType, len), initvals);
#if LDC_LLVM_VER == 301
// Simply storing the constant array triggers a problem in LLVM 3.1.
// With -O3 the statement
// void[0] sa0 = (void[0]).init;
// is compiled to
// tail call void @llvm.trap()
// which is not what we want!
// Therefore a global variable is always used.
LLGlobalVariable *gvar = new LLGlobalVariable(*gIR->module, constarr->getType(), true, LLGlobalValue::InternalLinkage, constarr, ".constarrayliteral_init");
DtoMemCpy(dstMem, gvar, DtoConstSize_t(getTypePaddedSize(constarr->getType())));
#else
// If the type pointed to by dstMem is different from the array type
// then we must assign the value to a global variable.
if (constarr->getType() != dstMem->getType()->getPointerElementType())
{
LLGlobalVariable *gvar = new LLGlobalVariable(*gIR->module, constarr->getType(), true, LLGlobalValue::InternalLinkage, constarr, ".constarrayliteral_init");
DtoMemCpy(dstMem, gvar, DtoConstSize_t(getTypePaddedSize(constarr->getType())));
}
else
DtoStore(constarr, dstMem);
#endif
DSliceValue* dynSlice = DtoNewDynArray(loc, arrayType,
new DConstValue(Type::tsize_t, DtoConstSize_t(len)), false);
initializeArrayLiteral(p, this, DtoBitCast(dynSlice->ptr, getPtrToType(llStoType)));
return dynSlice;
}
else
{
// store elements
for (size_t i = 0; i < len; ++i)
{
Expression *expr = static_cast<Expression *>(elements->data[i]);
LLValue *elemAddr;
if(dyn)
elemAddr = DtoGEPi1(dstMem, i, "tmp", p->scopebb());
else
elemAddr = DtoGEPi(dstMem, 0, i, "tmp", p->scopebb());
// emulate assignment
DVarValue *vv = new DVarValue(expr->type, elemAddr);
DValue *e = expr->toElem(p);
DtoAssign(loc, vv, e);
}
llvm::Value* storage = DtoRawAlloca(llStoType, 0, "arrayliteral");
initializeArrayLiteral(p, this, storage);
return new DImValue(type, storage);
}
// return storage directly ?
if (!dyn)
return new DImValue(type, dstMem);
// return slice
return dynSlice;
}
//////////////////////////////////////////////////////////////////////////////////////////