Combine ArrayLiteralExp::toConstElem and initializeArrayLiteral implementations.

This commit is contained in:
David Nadlinger
2013-10-09 02:32:15 +02:00
parent eb3261f93c
commit 60cdf58168
3 changed files with 65 additions and 72 deletions

View File

@@ -390,44 +390,69 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
//////////////////////////////////////////////////////////////////////////////////////////
void initializeArrayLiteral(IRState* p, ArrayLiteralExp* ale, LLValue* dstMem)
bool isConstLiteral(ArrayLiteralExp* ale)
{
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)
for (size_t i = 0; i < ale->elements->dim; ++i)
{
Expression *expr = static_cast<Expression *>(ale->elements->data[i]);
isAllConst = expr->isConst() == 1;
// We have to check specifically for '1', as SymOffExp is classified as
// '2' and the address of a local variable is not an LLVM constant.
if ((*ale->elements)[i]->isConst() != 1)
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
llvm::Constant* arrayLiteralToConst(IRState* p, ArrayLiteralExp* ale)
{
assert(isConstLiteral(ale) && "Array literal cannot be represented as a constant.");
// Build the initializer. We have to take care as due to unions in the
// element types (with different fields being initialized), we can end up
// with different types for the initializer values. In this case, we
// generate a packed struct constant instead of an array constant.
LLType *elementType = NULL;
bool differentTypes = false;
std::vector<LLConstant*> vals;
vals.reserve(ale->elements->dim);
for (unsigned i = 0; i < ale->elements->dim; ++i)
{
llvm::Constant *val = (*ale->elements)[i]->toConstElem(p);
if (!elementType)
elementType = val->getType();
else
differentTypes |= (elementType != val->getType());
vals.push_back(val);
}
if (isAllConst)
if (differentTypes)
return llvm::ConstantStruct::getAnon(vals, true);
if (!elementType)
{
assert(ale->elements->dim == 0);
elementType = i1ToI8(voidToI8(DtoType(ale->type->toBasetype()->nextOf())));
return llvm::ConstantArray::get(LLArrayType::get(elementType, 0), vals);
}
llvm::ArrayType *t = llvm::ArrayType::get(elementType, ale->elements->dim);
return llvm::ConstantArray::get(t, vals);
}
//////////////////////////////////////////////////////////////////////////////////////////
void initializeArrayLiteral(IRState* p, ArrayLiteralExp* ale, LLValue* dstMem)
{
// Don't try to write nothing to a zero-element array, we might represent it
// as a null pointer.
if (ale->elements->dim == 0) return;
if (isConstLiteral(ale))
{
// 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);
llvm::Constant* constarr = arrayLiteralToConst(p, ale);
#if LDC_LLVM_VER == 301
// Simply storing the constant array triggers a problem in LLVM 3.1.
@@ -468,7 +493,7 @@ void initializeArrayLiteral(IRState* p, ArrayLiteralExp* ale, LLValue* dstMem)
else
{
// store elements
for (size_t i = 0; i < len; ++i)
for (size_t i = 0; i < ale->elements->dim; ++i)
{
LLValue *elemAddr = DtoGEPi(dstMem, 0, i, "tmp", p->scopebb());

View File

@@ -34,6 +34,12 @@ LLType* DtoConstArrayInitializerType(ArrayInitializer* arrinit);
LLConstant* DtoConstArrayInitializer(ArrayInitializer* si);
LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr, Type *type = 0);
/// Returns whether the array literal can be evaluated to a (LLVM) constant.
bool isConstLiteral(ArrayLiteralExp* ale);
/// Returns the constant for the given array literal expression.
llvm::Constant* arrayLiteralToConst(IRState* p, ArrayLiteralExp* ale);
/// Initializes a chunk of memory with the contents of an array literal.
///
/// dstMem is expected to be a pointer to the array allocation.

View File

@@ -2925,45 +2925,7 @@ LLConstant* ArrayLiteralExp::toConstElem(IRState* p)
// dynamic arrays can occur here as well ...
bool dyn = (bt->ty != Tsarray);
// Build the initializer. We have to take care as due to unions in the
// element types (with different fields being initialized), we can end up
// with different types for the initializer values. In this case, we
// generate a packed struct constant instead of an array constant.
LLType *elementType = NULL;
bool differentTypes = false;
std::vector<LLConstant*> vals;
vals.reserve(elements->dim);
for (unsigned i = 0; i < elements->dim; ++i)
{
LLConstant *val = (*elements)[i]->toConstElem(p);
if (!elementType)
elementType = val->getType();
else
differentTypes |= (elementType != val->getType());
vals.push_back(val);
}
LLConstant *initval;
if (differentTypes)
{
std::vector<llvm::Type*> types;
types.reserve(elements->dim);
for (unsigned i = 0; i < elements->dim; ++i)
types.push_back(vals[i]->getType());
LLStructType *t = llvm::StructType::get(gIR->context(), types, true);
initval = LLConstantStruct::get(t, vals);
}
else if (!elementType)
{
assert(elements->dim == 0);
initval = LLConstantArray::get(arrtype, vals);
}
else
{
LLArrayType *t = LLArrayType::get(elementType, elements->dim);
initval = LLConstantArray::get(t, vals);
}
llvm::Constant* initval = arrayLiteralToConst(p, this);
// if static array, we're done
if (!dyn)