diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 74ac87e1..6f199479 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -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(ale->elements->data[i]); + isAllConst = expr->isConst() == 1; + } + + if (isAllConst) + { + // 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); + +#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) { diff --git a/gen/arrays.h b/gen/arrays.h index a78d146d..957a03e0 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -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); diff --git a/gen/toir.cpp b/gen/toir.cpp index 8c6c6362..cead06b4 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -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(elements->data[i]); - isAllConst = expr->isConst() == 1; - } - - if (isAllConst) - { - // allocate room for initializers - std::vector 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(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(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; } //////////////////////////////////////////////////////////////////////////////////////////