diff --git a/gen/arrays.cpp b/gen/arrays.cpp index a671fe22..0b07b2ea 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -20,6 +20,22 @@ ////////////////////////////////////////////////////////////////////////////////////////// +static LLValue *DtoSlice(DValue *dval) +{ + LLValue *val = dval->getRVal(); + if (dval->isVar() && dval->isVar()->type->ty == Tsarray) { + // Convert static array to slice + const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context())); + LLValue *array = DtoRawAlloca(type, 0, ".array"); + DtoStore(DtoArrayLen(dval), DtoGEPi(array, 0, 0, ".len")); + DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEPi(array, 0, 1, ".ptr")); + val = DtoLoad(array); + } + return val; +} + +////////////////////////////////////////////////////////////////////////////////////////// + const LLStructType* DtoArrayType(Type* arrayTy) { assert(arrayTy->nextOf()); @@ -65,11 +81,20 @@ void DtoSetArrayToNull(LLValue* v) ////////////////////////////////////////////////////////////////////////////////////////// -void DtoArrayInit(Loc& loc, DValue* array, DValue* value) +void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op) { Logger::println("DtoArrayInit"); LOG_SCOPE; +#if DMDV2 + Type *elemType = array->type->toBasetype()->nextOf()->toBasetype(); + if (op != -1 && op != TOKblit && arrayNeedsPostblit(elemType)) + { + DtoArraySetAssign(loc, array, value, op); + return; + } +#endif + LLValue* dim = DtoArrayLen(array); LLValue* ptr = DtoArrayPtr(array); LLValue* val; @@ -209,6 +234,69 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value) ////////////////////////////////////////////////////////////////////////////////////////// +#if DMDV2 + +// Determine whether t is an array of structs that need a postblit. +bool arrayNeedsPostblit(Type *t) +{ + t = t->toBasetype(); + while (t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + if (t->ty == Tstruct) + return ((TypeStruct *)t)->sym->postblit != 0; + return false; +} + +// Does array assignment (or initialization) from another array of the same element type. +void DtoArrayAssign(DValue *array, DValue *value, int op) +{ + Logger::println("DtoArrayAssign"); + LOG_SCOPE; + + assert(value && array); + assert(op != TOKblit); + Type *t = value->type->toBasetype(); + assert(t->nextOf()); + Type *elemType = t->nextOf()->toBasetype(); + + LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, op == TOKconstruct ? "_d_arrayctor" : "_d_arrayassign"); + LLSmallVector args; + args.push_back(DtoTypeInfoOf(elemType)); + args.push_back(DtoAggrPaint(DtoSlice(value), fn->getFunctionType()->getParamType(1))); + args.push_back(DtoAggrPaint(DtoSlice(array), fn->getFunctionType()->getParamType(2))); + + LLCallSite call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".array"); + call.setCallingConv(llvm::CallingConv::C); +} + +// If op is TOKconstruct, does construction of an array; +// otherwise, does assignment to an array. +void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op) +{ + Logger::println("DtoArraySetAssign"); + LOG_SCOPE; + + assert(array && value); + assert(op != TOKblit); + + LLValue *ptr = DtoArrayPtr(array); + LLValue *len = DtoArrayLen(array); + + LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, op == TOKconstruct ? "_d_arraysetctor" : "_d_arraysetassign"); + LLSmallVector args; + args.push_back(DtoBitCast(ptr, getVoidPtrType())); + args.push_back(DtoBitCast(makeLValue(loc, value), getVoidPtrType())); + args.push_back(len); + args.push_back(DtoTypeInfoOf(array->type->toBasetype()->nextOf()->toBasetype())); + + LLCallSite call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".newptr"); + call.setCallingConv(llvm::CallingConv::C); +} + +#endif + +////////////////////////////////////////////////////////////////////////////////////////// + void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr) { Logger::println("SetArray"); @@ -671,21 +759,6 @@ DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) #if DMDV2 -static LLValue *getParamForArrayCat(Expression* exp) -{ - DValue *dval = exp->toElem(gIR); - LLValue *val = dval->getRVal(); - if (dval->isVar() && dval->isVar()->type->ty == Tsarray) { - // Convert static array to slice - const LLStructType *type = DtoArrayType(LLType::getInt8Ty(gIR->context())); - LLValue *array = DtoRawAlloca(type, 0, ".array"); - DtoStore(DtoArrayLen(dval), DtoGEPi(array, 0, 0, ".len")); - DtoStore(DtoBitCast(val, getVoidPtrType()), DtoGEPi(array, 0, 1, ".ptr")); - val = DtoLoad(array); - } - return val; -} - DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) { Logger::println("DtoCatAssignArray"); @@ -697,11 +770,11 @@ DSliceValue* DtoCatArrays(Type* arrayType, Expression* exp1, Expression* exp2) // TypeInfo ti args.push_back(DtoTypeInfoOf(arrayType)); // byte[] x - LLValue *val = getParamForArrayCat(exp1); + LLValue *val = DtoSlice(exp1->toElem(gIR)); val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(1)); args.push_back(val); // byte[] y - val = getParamForArrayCat(exp2); + val = DtoSlice(exp2->toElem(gIR)); val = DtoAggrPaint(val, fn->getFunctionType()->getParamType(2)); args.push_back(val); diff --git a/gen/arrays.h b/gen/arrays.h index 8ea34eab..66694ca6 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -15,8 +15,12 @@ LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr); void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src); void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src); -void DtoArrayInit(Loc& loc, DValue* array, DValue* value); -void DtoArrayAssign(LLValue* l, LLValue* r); +void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op); +#if DMDV2 +bool arrayNeedsPostblit(Type *t); +void DtoArrayAssign(DValue *from, DValue *to, int op); +void DtoArraySetAssign(Loc &loc, DValue *array, DValue *value, int op); +#endif void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr); void DtoSetArrayToNull(LLValue* v); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index faa4d9e1..d1c187f8 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -385,7 +385,7 @@ void DtoLeaveMonitor(LLValue* v) // is this a good approach at all ? -void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs) +void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op) { Logger::println("DtoAssign(...);\n"); LOG_SCOPE; @@ -411,11 +411,17 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs) else if (t->ty == Tarray) { // lhs is slice if (DSliceValue* s = lhs->isSlice()) { - if (DSliceValue* s2 = rhs->isSlice()) { - DtoArrayCopySlices(s, s2); + Type *elemType = t->nextOf()->toBasetype(); + if (elemType->equals(t2)) { + DtoArrayInit(loc, s, rhs, op); } - else if (t->nextOf()->toBasetype()->equals(t2)) { - DtoArrayInit(loc, s, rhs); +#if DMDV2 + else if (op != -1 && op != TOKblit && arrayNeedsPostblit(elemType)) { + DtoArrayAssign(s, rhs, op); + } +#endif + else if (DSliceValue *s2 = rhs->isSlice()) { + DtoArrayCopySlices(s, s2); } else { DtoArrayCopyToSlice(s, rhs); @@ -440,13 +446,19 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs) } } else if (t->ty == Tsarray) { - // T[n] = T[n] - if (DtoType(lhs->getType()) == DtoType(rhs->getType())) { - DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal()); - } + Type *elemType = t->nextOf()->toBasetype(); // T[n] = T - else if (t->nextOf()->toBasetype()->equals(t2)) { - DtoArrayInit(loc, lhs, rhs); + if (elemType->equals(t2)) { + DtoArrayInit(loc, lhs, rhs, op); + } +#if DMDV2 + else if (op != -1 && op != TOKblit && arrayNeedsPostblit(elemType)) { + DtoArrayAssign(lhs, rhs, op); + } +#endif + // T[n] = T[n] + else if (DtoType(lhs->getType()) == DtoType(rhs->getType())) { + DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal()); } // T[n] = T[] - generally only generated by frontend in rare cases else if (t2->ty == Tarray && t->nextOf()->toBasetype()->equals(t2->nextOf()->toBasetype())) { diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 6d949aa9..ca934e54 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -72,7 +72,7 @@ void DtoEnterMonitor(LLValue* v); void DtoLeaveMonitor(LLValue* v); // basic operations -void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs); +void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op = -1); /// Create a null DValue. DValue* DtoNullValue(Type* t); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 93a46a63..b78318e8 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -642,6 +642,45 @@ static void LLVM_D_BuildRuntimeModule() ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// +#if DMDV2 + + // void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) + // void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) + { + llvm::StringRef fname("_d_arrayassign"); + llvm::StringRef fname2("_d_arrayctor"); + std::vector types; + types.push_back(typeInfoTy); + types.push_back(voidArrayTy); + types.push_back(voidArrayTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidArrayTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); + } + + // void* _d_arraysetassign(void* p, void* value, size_t count, TypeInfo ti) + // void* _d_arraysetctor(void* p, void* value, size_t count, TypeInfo ti) + { + llvm::StringRef fname("_d_arraysetassign"); + llvm::StringRef fname2("_d_arraysetctor"); + std::vector types; + types.push_back(voidPtrTy); + types.push_back(voidPtrTy); + types.push_back(sizeTy); + types.push_back(typeInfoTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) + ->setAttributes(Attr_NoAlias); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M) + ->setAttributes(Attr_NoAlias); + } + +#endif + + ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + // cast to object // Object _d_toObject(void* p) { diff --git a/gen/toir.cpp b/gen/toir.cpp index 8938fb0f..8ae43465 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -570,7 +570,7 @@ DValue* AssignExp::toElem(IRState* p) DValue* l = e1->toElem(p); DValue* r = e2->toElem(p); - DtoAssign(loc, l, r); + DtoAssign(loc, l, r, op); if (l->isSlice()) return l; @@ -2628,7 +2628,7 @@ DValue* StructLiteralExp::toElem(IRState* p) DVarValue field(vd->type, vd, DtoIndexStruct(mem, sd, vd)); // store the initializer there - DtoAssign(loc, &field, val); + DtoAssign(loc, &field, val, TOKconstruct); #if DMDV2 Type *tb = vd->type->toBasetype(); diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index a43729a5..6c5e8b59 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -69,7 +69,6 @@ elseif(D_VERSION EQUAL 2) file(GLOB_RECURSE GC_D ${RUNTIME_GC_DIR}/*.d) file(GLOB_RECURSE DCRT_D ${RUNTIME_DC_DIR}/*.d) list(REMOVE_ITEM DCRT_D - ${RUNTIME_DC_DIR}/arrayassign.d ${RUNTIME_DC_DIR}/arraybyte.d ${RUNTIME_DC_DIR}/arraycast.d ${RUNTIME_DC_DIR}/arraycat.d