From 85c1b42b1b4b8275dfdb44b980869c3980f1d047 Mon Sep 17 00:00:00 2001 From: Tomas Lindquist Olsen Date: Sun, 13 Jul 2008 01:29:49 +0200 Subject: [PATCH] [svn r360] Another mostly rewrite of DtoArrayInit. Should be much more robust now, and probably faster code generated for the most common cases too! Fixed issues with slice initialization (!!!) of multidimensional static arrays. Attempt to fix issue with referencing nested 'this' pointers introduced in DMD 1.033 merge. --- gen/arrays.cpp | 160 ++++++++++++++--------------- gen/llvmhelpers.cpp | 11 ++ gen/runtime.cpp | 2 + gen/toir.cpp | 21 +++- tango/lib/compiler/llvmdc/arrays.d | 8 ++ test/multiarr1.d | 11 +- test/staticarrays.d | 6 ++ 7 files changed, 134 insertions(+), 85 deletions(-) diff --git a/gen/arrays.cpp b/gen/arrays.cpp index e022aad3..b8caa367 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -130,99 +130,97 @@ void DtoArrayInit(DValue* array, DValue* value) LLValue* ptr = DtoArrayPtr(array); LLValue* val = value->getRVal(); - Logger::cout() << "llvm values:\n" << " ptr: " << *ptr << " dim: " << *dim << " val: " << *val << '\n'; - - const LLType* pt = ptr->getType()->getContainedType(0); - const LLType* t = val->getType(); - - size_t aggrsz = 0; - Type* valtype = value->getType()->toBasetype(); - - const char* funcname = NULL; - + // prepare runtime call LLSmallVector args; args.push_back(ptr); args.push_back(dim); args.push_back(val); - // if t is a primitive type, use the corresponding runtime function - if (t == LLType::Int1Ty) { - funcname = "_d_array_init_i1"; - } - else if (t == LLType::Int8Ty) { - funcname = "_d_array_init_i8"; - } - else if (t == LLType::Int16Ty) { - funcname = "_d_array_init_i16"; - } - else if (t == LLType::Int32Ty) { - funcname = "_d_array_init_i32"; - } - else if (t == LLType::Int64Ty) { - funcname = "_d_array_init_i64"; - } - else if (t == LLType::FloatTy) { - funcname = "_d_array_init_float"; - } - else if (t == LLType::DoubleTy) { - funcname = "_d_array_init_double"; - } - else if (t == getPtrToType(LLType::Int8Ty)) { - funcname = "_d_array_init_pointer"; + // determine the right runtime function to call + const char* funcname = NULL; + Type* t = value->getType()->toBasetype(); - const LLType* dstty = getPtrToType(getVoidPtrType()); - if (args[0]->getType() != dstty) - args[0] = DtoBitCast(args[0],dstty); - - const LLType* valty = getVoidPtrType(); - if (args[2]->getType() != valty) - args[2] = DtoBitCast(args[2],valty); - } - // handle array rhs - else if (value->getType()->ty == Tarray || value->getType()->ty == Tsarray) + // lets first optimize all zero initializations down to a memset. + // this simplifies codegen later on as llvm null's have no address! + if (isaConstant(val) && isaConstant(val)->isNullValue()) { - const LLArrayType* dstarrty = isaArray(pt); - assert(dstarrty); - const LLPointerType* srcty = isaPointer(t); - assert(dstarrty == srcty->getElementType()); - - funcname = "_d_array_init_mem"; - - args[0] = gIR->ir->CreateBitCast(ptr, getVoidPtrType(), "tmp"); - args[2] = gIR->ir->CreateBitCast(val, getVoidPtrType(), "tmp"); - - size_t n_inner = getABITypeSize(srcty->getElementType()); - args.push_back(DtoConstSize_t(n_inner)); - } - // handle null aggregate - else if (isaStruct(t)) - { - aggrsz = getABITypeSize(t); - LLConstant* c = isaConstant(val); - assert(c && c->isNullValue()); - LLValue* nbytes; - if (aggrsz == 1) - nbytes = dim; - else - nbytes = gIR->ir->CreateMul(dim, DtoConstSize_t(aggrsz), "tmp"); - DtoMemSetZero(ptr,nbytes); + size_t X = getABITypeSize(val->getType()); + LLValue* nbytes = gIR->ir->CreateMul(dim, DtoConstSize_t(X), ".nbytes"); + DtoMemSetZero(ptr, nbytes); return; } - // handle general aggregate case - else if (DtoIsPassedByRef(valtype)) + + // if not a zero initializer, call the appropriate runtime function! + switch (t->ty) { + case Tbool: + funcname = "_d_array_init_i1"; + break; + + case Tvoid: + case Tchar: + case Tint8: + case Tuns8: + funcname = "_d_array_init_i8"; + break; + + case Twchar: + case Tint16: + case Tuns16: + funcname = "_d_array_init_i16"; + break; + + case Tdchar: + case Tint32: + case Tuns32: + funcname = "_d_array_init_i32"; + break; + + case Tint64: + case Tuns64: + funcname = "_d_array_init_i64"; + break; + + case Tfloat32: + case Timaginary32: + funcname = "_d_array_init_float"; + break; + + case Tfloat64: + case Timaginary64: + funcname = "_d_array_init_double"; + break; + + case Tfloat80: + case Timaginary80: + funcname = "_d_array_init_real"; + break; + + case Tpointer: + case Tclass: + funcname = "_d_array_init_pointer"; + args[0] = DtoBitCast(args[0], getPtrToType(getVoidPtrType())); + args[2] = DtoBitCast(args[2], getVoidPtrType()); + break; + + // this currently acts as a kind of fallback for all the bastards... + // FIXME: this is probably too slow. + case Tstruct: + case Tdelegate: + case Tarray: + case Tsarray: + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: funcname = "_d_array_init_mem"; + args[0] = DtoBitCast(args[0], getVoidPtrType()); + args[2] = DtoBitCast(args[2], getVoidPtrType()); + args.push_back(DtoConstSize_t(getABITypeSize(DtoType(t)))); + break; - args[0] = gIR->ir->CreateBitCast(ptr, getVoidPtrType(), "tmp"); - args[2] = gIR->ir->CreateBitCast(val, getVoidPtrType(), "tmp"); - - aggrsz = getABITypeSize(pt); - args.push_back(DtoConstSize_t(aggrsz)); - } - else - { - Logger::cout() << *ptr->getType() << " = " << *val->getType() << '\n'; - assert(0); + default: + error("unhandled array init: %s = %s", array->getType()->toChars(), value->getType()->toChars()); + assert(0 && "unhandled array init"); } LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, funcname); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index ff460fd9..f47e0232 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -3,6 +3,7 @@ #include "mars.h" #include "init.h" +#include "id.h" #include "gen/tollvm.h" #include "gen/llvmhelpers.h" @@ -465,6 +466,16 @@ LLValue* DtoNestedVariable(VarDeclaration* vd) LLValue* ptr = DtoNestedContext(func); assert(ptr && "nested var, but no context"); + // if the nested var is a this pointer it's a class member and not a magic struct + // so we're done here! + // this happens since 1.033 for some reason... always correct ? + if (vd->ident == Id::This) + { + return ptr; + } + + // handle a "normal" nested variable + // we must cast here to be sure. nested classes just have a void* ptr = DtoBitCast(ptr, func->ir.irFunc->nestedVar->getType()); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 29113154..3195ba0e 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -194,6 +194,7 @@ static void LLVM_D_BuildRuntimeModule() const LLType* longTy = LLType::Int64Ty; const LLType* floatTy = LLType::FloatTy; const LLType* doubleTy = LLType::DoubleTy; + const LLType* realTy = (global.params.useFP80) ? LLType::X86_FP80Ty : LLType::DoubleTy; const LLType* sizeTy = DtoSize_t(); const LLType* voidPtrTy = rt_ptr(byteTy); const LLType* stringTy = rt_array(byteTy); @@ -361,6 +362,7 @@ static void LLVM_D_BuildRuntimeModule() ARRAY_INIT(longTy,"i64") ARRAY_INIT(floatTy,"float") ARRAY_INIT(doubleTy,"double") + ARRAY_INIT(realTy,"real") ARRAY_INIT(voidPtrTy,"pointer") #undef ARRAY_INIT diff --git a/gen/toir.cpp b/gen/toir.cpp index e18d3f06..5bb1a85d 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -234,7 +234,12 @@ DValue* VarExp::toElem(IRState* p) // function parameter else if (vd->isParameter()) { Logger::println("function param"); - if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa(vd->ir.getIrValue())) { + FuncDeclaration* fd = vd->toParent2()->isFuncDeclaration(); + if (fd && fd != p->func()->decl) { + Logger::println("nested parameter"); + return new DVarValue(vd, DtoNestedVariable(vd), true); + } + else if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa(vd->ir.getIrValue())) { return new DVarValue(vd, vd->ir.getIrValue(), true); } else if (llvm::isa(vd->ir.getIrValue())) { @@ -1543,7 +1548,19 @@ DValue* SliceExp::toElem(IRState* p) else { assert(e1->type->toBasetype()->ty != Tpointer); - elen = DtoArrayLen(e); + // if the sliceee is a static array, we use the length of that as DMD seems + // to give contrary inconsistent sizesin some multidimensional static array cases. + // (namely default initialization, int[16][16] arr; -> int[256] arr = 0;) + if (etype->ty == Tsarray) + { + TypeSArray* tsa = (TypeSArray*)etype; + elen = DtoConstSize_t(tsa->dim->toUInteger()); + } + // for normal code the actual array length is what we want! + else + { + elen = DtoArrayLen(e); + } } return new DSliceValue(type, elen, eptr); diff --git a/tango/lib/compiler/llvmdc/arrays.d b/tango/lib/compiler/llvmdc/arrays.d index 198b60bd..b9b2b65a 100644 --- a/tango/lib/compiler/llvmdc/arrays.d +++ b/tango/lib/compiler/llvmdc/arrays.d @@ -68,6 +68,14 @@ void _d_array_init_double(double* a, size_t n, double v) *p++ = v; } +void _d_array_init_real(real* a, size_t n, real v) +{ + auto p = a; + auto end = a+n; + while (p !is end) + *p++ = v; +} + void _d_array_init_pointer(void** a, size_t n, void* v) { auto p = a; diff --git a/test/multiarr1.d b/test/multiarr1.d index 90fabffe..9258ef19 100644 --- a/test/multiarr1.d +++ b/test/multiarr1.d @@ -3,9 +3,16 @@ module multiarr1; void main() { int[16][16] a; + assert(a[0][0] == 0); + assert(a[0][1] == 0); + assert(a[0][2] == 0); + assert(a[0][3] == 0); + assert(a[10][13] == 0); + assert(a[15][15] == 0); a[10][13] = 42; - //assert(a[0][0] == 0); - //assert(a[10][13] == 42); + assert(a[0][0] == 0); + assert(a[10][13] == 42); + assert(a[15][15] == 0); { int* l = cast(int*)a; l += 10*16+13; diff --git a/test/staticarrays.d b/test/staticarrays.d index 5de4decd..1d76c99d 100644 --- a/test/staticarrays.d +++ b/test/staticarrays.d @@ -65,8 +65,14 @@ void refs() } } +void vals() +{ + S[5] structs; +} + void main() { numbers(); refs(); + vals(); }