From 60cdf581680554d28fdfe3cef90af3489d7e12ad Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 9 Oct 2013 02:32:15 +0200 Subject: [PATCH] Combine ArrayLiteralExp::toConstElem and initializeArrayLiteral implementations. --- gen/arrays.cpp | 91 ++++++++++++++++++++++++++++++++------------------ gen/arrays.h | 6 ++++ gen/toir.cpp | 40 +--------------------- 3 files changed, 65 insertions(+), 72 deletions(-) diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 6f199479..fdc8eebb 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -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(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 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 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(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()); diff --git a/gen/arrays.h b/gen/arrays.h index 957a03e0..f72a912a 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -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. diff --git a/gen/toir.cpp b/gen/toir.cpp index 58b3c792..0d2a9901 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -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 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 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)