From 9cd32549c448a6dca4b1f67c68027a8812a7fd8d Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Sun, 14 Feb 2010 10:11:05 +0100 Subject: [PATCH] Improve array append performance. Actually use the appropriate runtime function, instead of just growing the array by one! --- gen/arrays.cpp | 39 ++++++++++++++++---------------- gen/arrays.h | 2 +- gen/runtime.cpp | 11 ++++++++++ gen/toir.cpp | 19 ++++++++-------- tango-0.99.9.patch | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 tango-0.99.9.patch diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 8d259dd0..d8d0c07c 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -474,7 +474,7 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size // build dims LLValue* dimsArg = DtoArrayAlloca(Type::tsize_t, ndims, ".newdims"); - LLValue* firstDim = NULL; + LLValue* firstDim = NULL; for (size_t i=0; igetRVal(); @@ -532,30 +532,29 @@ DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, DValue* newdim) } ////////////////////////////////////////////////////////////////////////////////////////// -DSliceValue* DtoCatAssignElement(DValue* array, Expression* exp) +void DtoCatAssignElement(Type* arrayType, DValue* array, Expression* exp) { Logger::println("DtoCatAssignElement"); LOG_SCOPE; assert(array); - LLValue* idx = DtoArrayLen(array); - LLValue* one = DtoConstSize_t(1); - LLValue* len = gIR->ir->CreateAdd(idx,one,"tmp"); + DValue *expVal = exp->toElem(gIR); + LLValue *valueToAppend; + if (expVal->isLVal()) + valueToAppend = expVal->getLVal(); + else { + valueToAppend = DtoAlloca(expVal->getType(), ".appendingElementOnStack"); + DtoStore(expVal->getRVal(), valueToAppend); + } - DValue* newdim = new DImValue(Type::tsize_t, len); - DSliceValue* slice = DtoResizeDynArray(array->getType(), array, newdim); + LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_arrayappendcT"); + LLSmallVector args; + args.push_back(DtoTypeInfoOf(arrayType)); + args.push_back(DtoBitCast(array->getLVal(), getVoidPtrType())); + args.push_back(DtoBitCast(valueToAppend, getVoidPtrType())); - LLValue* ptr = slice->ptr; - ptr = llvm::GetElementPtrInst::Create(ptr, idx, "tmp", gIR->scopebb()); - - DValue* dptr = new DVarValue(exp->type, ptr); - - DValue* e = exp->toElem(gIR); - - DtoAssign(exp->loc, dptr, e); - - return slice; + gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), ".appendedArray"); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -980,7 +979,7 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to) else if (totype->ty == Tsarray) { if (Logger::enabled()) Logger::cout() << "to sarray" << '\n'; - + size_t tosize = ((TypeSArray*)totype)->dim->toInteger(); if (fromtype->ty == Tsarray) { @@ -1004,9 +1003,9 @@ DValue* DtoCastArray(Loc& loc, DValue* u, Type* to) size_t i = (tosize * totype->nextOf()->size() - 1) / fromtype->nextOf()->size(); DConstValue index(Type::tsize_t, DtoConstSize_t(i)); DtoArrayBoundsCheck(loc, u, &index, false); - + rval = DtoArrayPtr(u); - rval = DtoBitCast(rval, getPtrToType(tolltype)); + rval = DtoBitCast(rval, getPtrToType(tolltype)); } } else if (totype->ty == Tbool) { diff --git a/gen/arrays.h b/gen/arrays.h index 7e0cf242..c7ec1dfb 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -24,7 +24,7 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size_t ndims, bool defaultInit=true); DSliceValue* DtoResizeDynArray(Type* arrayType, DValue* array, DValue* newdim); -DSliceValue* DtoCatAssignElement(DValue* arr, Expression* exp); +void DtoCatAssignElement(Type* type, DValue* arr, Expression* exp); DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp); DSliceValue* DtoCatArrays(Type* type, Expression* e1, Expression* e2); DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 5517736d..e83fb085 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -326,6 +326,17 @@ static void LLVM_D_BuildRuntimeModule() llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); } + // void* _d_arrayappendcT(TypeInfo ti, void* array, void* element) + { + llvm::StringRef fname("_d_arrayappendcT"); + std::vector types; + types.push_back(typeInfoTy); + types.push_back(voidPtrTy); + types.push_back(voidPtrTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(rt_array(byteTy), types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); + } + // Object _d_allocclass(ClassInfo ci) { llvm::StringRef fname("_d_allocclass"); diff --git a/gen/toir.cpp b/gen/toir.cpp index b131c7f0..694a874b 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -624,7 +624,7 @@ static void errorOnIllegalArrayOp(Expression* base, Expression* e1, Expression* // valid array ops would have been transformed by optimize if ((t1->ty == Tarray || t1->ty == Tsarray) && (t2->ty == Tarray || t2->ty == Tsarray) - ) + ) { base->error("Array operation %s not recognized", base->toChars()); fatal(); @@ -1013,7 +1013,7 @@ LLConstant* AddrExp::toConstElem(IRState* p) return DtoBitCast(gep, DtoType(type)); } else if ( - e1->op == TOKstructliteral || + e1->op == TOKstructliteral || e1->op == TOKslice) { error("non-constant expression '%s'", toChars()); @@ -1138,7 +1138,7 @@ DValue* DotVarExp::toElem(IRState* p) // decide whether this function needs to be looked up in the vtable // bool vtbllookup = fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual()); - + // even virtual functions are looked up directly if super or DotTypeExp // are used, thus we need to walk through the this expression and check Expression* e = e1; @@ -1150,7 +1150,7 @@ DValue* DotVarExp::toElem(IRState* p) else break; } - + // // look up function // @@ -1237,12 +1237,12 @@ DValue* IndexExp::toElem(IRState* p) arrptr = DtoGEP1(l->getRVal(),r->getRVal()); } else if (e1type->ty == Tsarray) { - if(global.params.useArrayBounds) + if(global.params.useArrayBounds) DtoArrayBoundsCheck(loc, l, r, false); arrptr = DtoGEP(l->getRVal(), zero, r->getRVal()); } else if (e1type->ty == Tarray) { - if(global.params.useArrayBounds) + if(global.params.useArrayBounds) DtoArrayBoundsCheck(loc, l, r, false); arrptr = DtoArrayPtr(l); arrptr = DtoGEP1(arrptr,r->getRVal()); @@ -1769,7 +1769,7 @@ DValue* AssertExp::toElem(IRState* p) // class invariants if( - global.params.useInvariants && + global.params.useInvariants && condty->ty == Tclass && !((TypeClass*)condty)->sym->isInterfaceDeclaration()) { @@ -1780,7 +1780,7 @@ DValue* AssertExp::toElem(IRState* p) } // struct invariants else if( - global.params.useInvariants && + global.params.useInvariants && condty->ty == Tpointer && condty->nextOf()->ty == Tstruct && (invdecl = ((TypeStruct*)condty->nextOf())->sym->inv) != NULL) { @@ -2234,8 +2234,7 @@ DValue* CatAssignExp::toElem(IRState* p) Type* e2type = e2->type->toBasetype(); if (e2type == elemtype) { - DSliceValue* slice = DtoCatAssignElement(l,e2); - DtoAssign(loc, l, slice); + DtoCatAssignElement(e1type, l, e2); } else if (e1type == e2type) { DSliceValue* slice = DtoCatAssignArray(l,e2); diff --git a/tango-0.99.9.patch b/tango-0.99.9.patch new file mode 100644 index 00000000..cf16ad93 --- /dev/null +++ b/tango-0.99.9.patch @@ -0,0 +1,55 @@ +Index: tango/core/rt/compiler/ldc/rt/lifetime.d +=================================================================== +--- tango/core/rt/compiler/ldc/rt/lifetime.d (revision 5368) ++++ tango/core/rt/compiler/ldc/rt/lifetime.d (working copy) +@@ -786,6 +786,7 @@ + return *cast(long*)px; + } + +++/ + + /** + * +@@ -849,10 +850,11 @@ + + + /** +- * ++ * Appends a single element to an array. + */ +-extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...) ++extern (C) byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element) + { ++ auto x = cast(byte[]*)array; + auto sizeelem = ti.next.tsize(); // array element size + auto info = gc_query(x.ptr); + auto length = x.length; +@@ -879,16 +881,16 @@ + assert(newcap >= newlength * sizeelem); + newdata = cast(byte *)gc_malloc(newcap + 1, info.attr); + memcpy(newdata, x.ptr, length * sizeelem); +- (cast(void**)(&x))[1] = newdata; ++ (cast(void**)x)[1] = newdata; + } + L1: +- byte *argp = cast(byte *)(&ti + 2); ++ byte *argp = cast(byte *)element; + +- *cast(size_t *)&x = newlength; ++ *cast(size_t *)x = newlength; + x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem]; + assert((cast(size_t)x.ptr & 15) == 0); + assert(gc_sizeOf(x.ptr) > x.length * sizeelem); +- return x; ++ return *x; + } + + +@@ -1128,6 +1130,7 @@ + return result; + } + ++/+ + + /** + *