changeset 109:5ab8e92611f9 trunk

[svn r113] Added initial support for associative arrays (AAs). Fixed some problems with the string runtime support functions. Fixed initialization of array of structs. Fixed slice assignment where LHS is slice but RHS is dynamic array. Fixed problems with result of assignment expressions. Fixed foreach problems with key type mismatches.
author lindquist
date Wed, 21 Nov 2007 04:13:15 +0100
parents 288fe1029e1f
children e8da7856a260
files dmd/mtype.c gen/aa.cpp gen/aa.h gen/arrays.cpp gen/functions.cpp gen/statements.cpp gen/toir.cpp gen/tollvm.cpp gen/tollvm.h gen/typinf.cpp llvmdc.kdevelop llvmdc.kdevelop.filelist lphobos/build.sh lphobos/gc/gcbits.d lphobos/internal/aaA.d lphobos/internal/adi.d lphobos/internal/arrays.d lphobos/internal/qsort2.d test/aa1.d test/aa2.d test/aa3.d test/aa4.d test/aa5.d test/arrays14.d test/typeinfo13.d
diffstat 25 files changed, 756 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mtype.c	Tue Nov 20 05:29:20 2007 +0100
+++ b/dmd/mtype.c	Wed Nov 21 04:13:15 2007 +0100
@@ -1515,6 +1515,7 @@
 	nm = name[n->ty == Twchar];
 	fd = FuncDeclaration::genCfunc(Type::tindex, nm);
     fd->llvmRunTimeHack = true;
+    ((TypeFunction*)fd->type)->llvmRetInPtr = true;
 	ec = new VarExp(0, fd);
 	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
 	arguments = new Expressions();
@@ -1533,6 +1534,7 @@
 	nm = name[n->ty == Twchar];
 	fd = FuncDeclaration::genCfunc(Type::tindex, nm);
     fd->llvmRunTimeHack = true;
+    ((TypeFunction*)fd->type)->llvmRetInPtr = true;
 	ec = new VarExp(0, fd);
 	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
 	arguments = new Expressions();
@@ -1551,6 +1553,8 @@
 	assert(size);
 	dup = (ident == Id::dup);
 	fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse);
+    fd->llvmRunTimeHack = true;
+    ((TypeFunction*)fd->type)->llvmRetInPtr = true;
 	ec = new VarExp(0, fd);
 	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
 	arguments = new Expressions();
@@ -1571,6 +1575,7 @@
 	fd = FuncDeclaration::genCfunc(tint32->arrayOf(),
 		(char*)(n->ty == Tbit ? "_adSortBit" : "_adSort"));
     fd->llvmRunTimeHack = true;
+    ((TypeFunction*)fd->type)->llvmRetInPtr = true;
 	ec = new VarExp(0, fd);
 	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
 	arguments = new Expressions();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/aa.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,153 @@
+#include "gen/llvm.h"
+
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+#include "gen/aa.h"
+#include "gen/runtime.h"
+#include "gen/tollvm.h"
+#include "gen/logger.h"
+#include "gen/irstate.h"
+#include "gen/dvalue.h"
+
+// makes sure the key value lives in memory so it can be passed to the runtime functions without problems
+// returns the pointer
+static llvm::Value* to_pkey(DValue* key)
+{
+    Type* keytype = key->getType();
+    bool needmem = !DtoIsPassedByRef(keytype);
+    llvm::Value* pkey;
+    if (key->isIm()) {
+        pkey = key->getRVal();
+    }
+    else if (DVarValue* var = key->isVar()) {
+        if (var->lval) {
+            pkey = key->getLVal();
+            needmem = false;
+        }
+        else {
+            pkey = key->getRVal();
+        }
+    }
+    else if (key->isConst()) {
+        needmem = true;
+        pkey = key->getRVal();
+    }
+    else {
+        assert(0);
+    }
+
+    // give memory
+    if (needmem) {
+        llvm::Value* tmp = new llvm::AllocaInst(DtoType(keytype), "aatmpkeystorage", gIR->topallocapoint());
+        DtoStore(pkey, tmp);
+        pkey = tmp;
+    }
+
+    return pkey;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key)
+{
+    // call:
+    // extern(C) void* _aaGet(AA* aa, TypeInfo keyti, void* pkey, size_t valuesize)
+
+    // first get the runtime function
+    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaGet");
+    const llvm::FunctionType* funcTy = func->getFunctionType();
+
+    // aa param
+    llvm::Value* aaval = aa->getLVal();
+    aaval = DtoBitCast(aaval, funcTy->getParamType(0));
+
+    // keyti param
+    Type* keytype = key->getType();
+    keytype->getTypeInfo(NULL);
+    TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration();
+    assert(tid);
+    DtoResolveDsymbol(Type::typeinfo);
+    DtoForceDeclareDsymbol(tid);
+    assert(tid->llvmValue);
+    llvm::Value* keyti = tid->llvmValue;
+    keyti = DtoBitCast(keyti, funcTy->getParamType(1));
+
+    // pkey param
+    llvm::Value* pkey = to_pkey(key);
+    pkey = DtoBitCast(pkey, funcTy->getParamType(2));
+
+    // valuesize param
+    llvm::Value* valsize = DtoConstSize_t(gTargetData->getTypeSize(DtoType(type)));
+
+    // build arg vector
+    std::vector<llvm::Value*> args;
+    args.push_back(aaval);
+    args.push_back(keyti);
+    args.push_back(pkey);
+    args.push_back(valsize);
+
+    // call runtime
+    llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaGet");
+
+    // cast return value
+    const llvm::Type* targettype = llvm::PointerType::get(DtoType(type));
+    if (ret->getType() != targettype)
+        ret = DtoBitCast(ret, targettype);
+
+    return new DVarValue(type, ret, true);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoAAIn(Type* type, DValue* aa, DValue* key)
+{
+    // call:
+    // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey)
+
+    // first get the runtime function
+    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaIn");
+    const llvm::FunctionType* funcTy = func->getFunctionType();
+
+    Logger::cout() << "_aaIn = " << *func << '\n';
+
+    // aa param
+    llvm::Value* aaval = aa->getRVal();
+    Logger::cout() << "aaval: " << *aaval << '\n';
+    Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n';
+    aaval = DtoBitCast(aaval, funcTy->getParamType(0));
+
+    // keyti param
+    Type* keytype = key->getType();
+    keytype->getTypeInfo(NULL);
+    TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration();
+    assert(tid);
+    DtoResolveDsymbol(Type::typeinfo);
+    DtoForceDeclareDsymbol(tid);
+    assert(tid->llvmValue);
+    llvm::Value* keyti = tid->llvmValue;
+    keyti = DtoBitCast(keyti, funcTy->getParamType(1));
+
+    // pkey param
+    llvm::Value* pkey = to_pkey(key);
+    pkey = DtoBitCast(pkey, funcTy->getParamType(2));
+
+    // build arg vector
+    std::vector<llvm::Value*> args;
+    args.push_back(aaval);
+    args.push_back(keyti);
+    args.push_back(pkey);
+
+    // call runtime
+    llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaIn");
+
+    // cast return value
+    const llvm::Type* targettype = DtoType(type);
+    if (ret->getType() != targettype)
+        ret = DtoBitCast(ret, targettype);
+
+    return new DImValue(type, ret);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/aa.h	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,7 @@
+#ifndef LLVMDC_GEN_AA_H
+#define LLVMDC_GEN_AA_H
+
+DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key);
+DValue* DtoAAIn(Type* type, DValue* aa, DValue* key);
+
+#endif // LLVMDC_GEN_AA_H
--- a/gen/arrays.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/arrays.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -151,11 +151,11 @@
 
 void DtoArrayInit(llvm::Value* ptr, llvm::Value* dim, llvm::Value* val)
 {
-    Logger::println("HELLO");
     Logger::cout() << "array: " << *ptr << " dim: " << *dim << " val: " << *val << '\n';
     const llvm::Type* pt = ptr->getType()->getContainedType(0);
     const llvm::Type* t = val->getType();
     const llvm::Type* finalTy;
+    size_t aggrsz = 0;
     if (size_t arrsz = checkRectArrayInit(pt, finalTy)) {
         assert(finalTy == t);
         llvm::Constant* c = isaConstant(dim);
@@ -164,12 +164,27 @@
         ptr = gIR->ir->CreateBitCast(ptr, llvm::PointerType::get(finalTy), "tmp");
     }
     else if (isaStruct(t)) {
-        assert(0);
+        aggrsz = gTargetData->getTypeSize(t);
+        llvm::Constant* c = isaConstant(val);
+        if (c && c->isNullValue()) {
+            llvm::Value* nbytes;
+            if (aggrsz == 1)
+                nbytes = dim;
+            else
+                nbytes = gIR->ir->CreateMul(dim, DtoConstSize_t(aggrsz), "tmp");
+            DtoMemSetZero(ptr,nbytes);
+            return;
+        }
+        else {
+            ptr = gIR->ir->CreateBitCast(ptr, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+        }
     }
     else {
         assert(t == pt);
     }
 
+    Logger::cout() << "array: " << *ptr << " dim: " << *dim << " val: " << *val << '\n';
+
     std::vector<llvm::Value*> args;
     args.push_back(ptr);
     args.push_back(dim);
@@ -177,7 +192,11 @@
 
     const char* funcname = NULL;
 
-    if (isaPointer(t)) {
+    if (aggrsz) {
+        funcname = "_d_array_init_mem";
+        args.push_back(DtoConstSize_t(aggrsz));
+    }
+    else if (isaPointer(t)) {
         funcname = "_d_array_init_pointer";
 
         const llvm::Type* dstty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
--- a/gen/functions.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/functions.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -44,6 +44,7 @@
     }
     else {
         assert(rt);
+        Type* rtfin = DtoDType(rt);
         if (DtoIsPassedByRef(rt)) {
             rettype = llvm::PointerType::get(DtoType(rt));
             actualRettype = llvm::Type::VoidTy;
--- a/gen/statements.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/statements.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -128,8 +128,8 @@
     Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars());
     LOG_SCOPE;
 
-//     if (global.params.symdebug)
-//         DtoDwarfStopPoint(loc.linnum);
+    if (global.params.symdebug)
+        DtoDwarfStopPoint(loc.linnum);
 
     if (exp != 0) {
         elem* e = exp->toElem(p);
@@ -731,6 +731,18 @@
         assert(0 && "aggregate type is not Tarray or Tsarray");
     }
 
+    if (niters->getType() != keytype)
+    {
+        size_t sz1 = gTargetData->getTypeSize(niters->getType());
+        size_t sz2 = gTargetData->getTypeSize(keytype);
+        if (sz1 < sz2)
+            niters = gIR->ir->CreateZExt(niters, keytype, "foreachtrunckey");
+        else if (sz1 > sz2)
+            niters = gIR->ir->CreateTrunc(niters, keytype, "foreachtrunckey");
+        else
+            niters = gIR->ir->CreateBitCast(niters, keytype, "foreachtrunckey");
+    }
+
     llvm::Constant* delta = 0;
     if (op == TOKforeach) {
         new llvm::StoreInst(zerokey, keyvar, p->scopebb());
--- a/gen/toir.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/toir.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -30,6 +30,7 @@
 #include "gen/typeinf.h"
 #include "gen/complex.h"
 #include "gen/dvalue.h"
+#include "gen/aa.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -66,6 +67,7 @@
                 //allocainst->setAlignment(vd->type->alignsize()); // TODO
                 vd->llvmValue = allocainst;
             }
+
             Logger::cout() << "llvm value for decl: " << *vd->llvmValue << '\n';
             DValue* ie = DtoInitializer(vd->init);
         }
@@ -409,8 +411,13 @@
         else if (p->topexp()->e2 == this) {
             DValue* arr = p->topexp()->v;
             assert(arr);
-            DtoSetArray(arr->getLVal(), clen, arrptr);
-            return new DImValue(type, arr->getLVal(), true);
+            if (arr->isSlice()) {
+                return new DSliceValue(type, clen, arrptr);
+            }
+            else {
+                DtoSetArray(arr->getRVal(), clen, arrptr);
+                return new DImValue(type, arr->getLVal(), true);
+            }
         }
         assert(0);
     }
@@ -490,7 +497,14 @@
 
     if (l->isSlice() || l->isComplex())
         return l;
-    return new DImValue(type, l->getRVal());
+
+    llvm::Value* v;
+    if (l->isVar() && l->isVar()->lval)
+        v = l->getLVal();
+    else
+        v = l->getRVal();
+
+    return new DVarValue(type, v, true);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -893,15 +907,26 @@
             llvm::Value* tlv = topexp->v->getLVal();
             assert(isaStruct(tlv->getType()->getContainedType(0)));
             llargs[j] = tlv;
-            if (DtoIsPassedByRef(tf->next)) {
+            isInPlace = true;
+            /*if (DtoIsPassedByRef(tf->next)) {
                 isInPlace = true;
             }
             else
-            assert(0);
+            assert(0);*/
         }
         else {
             llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint());
         }
+
+        if (dfn && dfn->func && dfn->func->llvmRunTimeHack) {
+            const llvm::Type* rettype = llvm::PointerType::get(DtoType(type));
+            if (llargs[j]->getType() != llfnty->getParamType(j)) {
+                Logger::println("llvmRunTimeHack==true - force casting return value param");
+                Logger::cout() << "casting: " << *llargs[j] << " to type: " << *llfnty->getParamType(j) << '\n';
+                llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
+            }
+        }
+
         ++j;
         ++argiter;
     }
@@ -1004,10 +1029,12 @@
                 llargs[j] = DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
                 // this hack is necessary :/
                 if (dfn && dfn->func && dfn->func->llvmRunTimeHack) {
-                    Logger::println("llvmRunTimeHack==true - force casting argument");
-                    if (llargs[j]->getType() != llfnty->getParamType(j)) {
-                        Logger::cout() << "from: " << *llargs[j]->getType() << " to: " << *llfnty->getParamType(j);
-                        llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
+                    if (llfnty->getParamType(j) != NULL) {
+                        if (llargs[j]->getType() != llfnty->getParamType(j)) {
+                            Logger::println("llvmRunTimeHack==true - force casting argument");
+                            Logger::cout() << "casting: " << *llargs[j] << " to type: " << *llfnty->getParamType(j) << '\n';
+                            llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
+                        }
                     }
                 }
             }
@@ -1024,12 +1051,21 @@
     if (llfnty->getReturnType() != llvm::Type::VoidTy)
         varname = "tmp";
 
-    Logger::cout() << "Calling: " << *funcval->getType() << '\n';
+    Logger::cout() << "Calling: " << *funcval << '\n';
 
     // call the function
     llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
     llvm::Value* retllval = (retinptr) ? llargs[0] : call;
 
+    if (retinptr && dfn && dfn->func && dfn->func->llvmRunTimeHack) {
+        const llvm::Type* rettype = llvm::PointerType::get(DtoType(type));
+        if (retllval->getType() != rettype) {
+            Logger::println("llvmRunTimeHack==true - force casting return value");
+            Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n';
+            retllval = DtoBitCast(retllval, rettype);
+        }
+    }
+
     // set calling convention
     if (dfn && dfn->func) {
         int li = dfn->func->llvmInternal;
@@ -1328,7 +1364,13 @@
         arrptr = new llvm::LoadInst(arrptr,"tmp",p->scopebb());
         arrptr = new llvm::GetElementPtrInst(arrptr,r->getRVal(),"tmp",p->scopebb());
     }
-    assert(arrptr);
+    else if (e1type->ty == Taarray) {
+        return DtoAAIndex(type, l, r);
+    }
+    else {
+        Logger::println("invalid index exp! e1type: %s", e1type->toChars());
+        assert(0);
+    }
     return new DVarValue(type, arrptr, true);
 }
 
@@ -2452,11 +2494,24 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+DValue* InExp::toElem(IRState* p)
+{
+    Logger::print("InExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* key = e1->toElem(p);
+    DValue* aa = e2->toElem(p);
+
+    return DtoAAIn(type, aa, key);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 #define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; }
 //STUB(IdentityExp);
 //STUB(CondExp);
 //STUB(EqualExp);
-STUB(InExp);
+//STUB(InExp);
 //STUB(CmpExp);
 //STUB(AndAndExp);
 //STUB(OrOrExp);
--- a/gen/tollvm.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/tollvm.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -177,8 +177,11 @@
     // associative arrays
     case Taarray:
     {
-        // TODO this is a kludge
-        return llvm::PointerType::get(llvm::Type::Int8Ty);
+        TypeAArray* taa = (TypeAArray*)t;
+        std::vector<const llvm::Type*> types;
+        types.push_back(DtoType(taa->key));
+        types.push_back(DtoType(taa->next));
+        return llvm::PointerType::get(llvm::StructType::get(types));
     }
 
     default:
@@ -1236,6 +1239,32 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+void DtoMemSetZero(llvm::Value* dst, llvm::Value* nbytes)
+{
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    llvm::Value *dstarr;
+    if (dst->getType() == arrty)
+    {
+        dstarr = dst;
+    }
+    else
+    {
+        dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    }
+
+    llvm::Function* fn = (global.params.is64bit) ? LLVM_DeclareMemSet64() : LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = nbytes;
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes)
 {
     assert(dst->getType() == src->getType());
--- a/gen/tollvm.h	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/tollvm.h	Wed Nov 21 04:13:15 2007 +0100
@@ -74,6 +74,7 @@
 void DtoForceDefineDsymbol(Dsymbol* dsym);
 
 // llvm wrappers
+void DtoMemSetZero(llvm::Value* dst, llvm::Value* nbytes);
 void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
 bool DtoCanLoad(llvm::Value* ptr);
 llvm::Value* DtoLoad(llvm::Value* src);
--- a/gen/typinf.cpp	Tue Nov 20 05:29:20 2007 +0100
+++ b/gen/typinf.cpp	Wed Nov 21 04:13:15 2007 +0100
@@ -654,33 +654,69 @@
 
 void TypeInfoAssociativeArrayDeclaration::llvmDeclare()
 {
-    assert(0 && "TypeInfoAssociativeArrayDeclaration");
+    Logger::println("TypeInfoAssociativeArrayDeclaration::toDt() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfoassociativearray;
+    DtoResolveClass(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // create the symbol
+    llvmValue = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
 }
 
 void TypeInfoAssociativeArrayDeclaration::llvmDefine()
 {
-    assert(0 && "TypeInfoAssociativeArrayDeclaration");
+    Logger::println("TypeInfoAssociativeArrayDeclaration::toDt() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfoassociativearray;
+    DtoForceConstInitDsymbol(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // initializer vector
+    std::vector<llvm::Constant*> sinits;
+    // first is always the vtable
+    sinits.push_back(base->llvmVtbl);
+
+    // get type
+    assert(tinfo->ty == Taarray);
+    TypeAArray *tc = (TypeAArray *)tinfo;
+
+    // value typeinfo
+    tc->next->getTypeInfo(NULL);
+
+    // get symbol
+    assert(tc->next->vtinfo);
+    DtoForceDeclareDsymbol(tc->next->vtinfo);
+    llvm::Constant* castbase = isaConstant(tc->next->vtinfo->llvmValue);
+    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(1));
+    sinits.push_back(castbase);
+
+    // key typeinfo
+    tc->index->getTypeInfo(NULL);
+
+    // get symbol
+    assert(tc->index->vtinfo);
+    DtoForceDeclareDsymbol(tc->index->vtinfo);
+    castbase = isaConstant(tc->index->vtinfo->llvmValue);
+    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
+    sinits.push_back(castbase);
+
+    // create the symbol
+    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
+    isaGlobalVar(llvmValue)->setInitializer(tiInit);
 }
 
 void TypeInfoAssociativeArrayDeclaration::toDt(dt_t **pdt)
 {
-    assert(0 && "TypeInfoAssociativeArrayDeclaration");
-
-    /*
-    //printf("TypeInfoAssociativeArrayDeclaration::toDt()\n");
-    dtxoff(pdt, Type::typeinfoassociativearray->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_AssociativeArray
-    dtdword(pdt, 0);                // monitor
-
-    assert(tinfo->ty == Taarray);
-
-    TypeAArray *tc = (TypeAArray *)tinfo;
-
-    tc->next->getTypeInfo(NULL);
-    dtxoff(pdt, tc->next->vtinfo->toSymbol(), 0, TYnptr); // TypeInfo for array of type
-
-    tc->index->getTypeInfo(NULL);
-    dtxoff(pdt, tc->index->vtinfo->toSymbol(), 0, TYnptr); // TypeInfo for array of type
-    */
+    assert(0);
 }
 
 /* ========================================================================= */
--- a/llvmdc.kdevelop	Tue Nov 20 05:29:20 2007 +0100
+++ b/llvmdc.kdevelop	Wed Nov 21 04:13:15 2007 +0100
@@ -98,7 +98,7 @@
       <hidenonlocation>false</hidenonlocation>
     </groups>
     <tree>
-      <hidepatterns>*.bc</hidepatterns>
+      <hidepatterns>*.bc,*.ll</hidepatterns>
       <hidenonprojectfiles>false</hidenonprojectfiles>
     </tree>
   </kdevfileview>
--- a/llvmdc.kdevelop.filelist	Tue Nov 20 05:29:20 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Wed Nov 21 04:13:15 2007 +0100
@@ -100,6 +100,8 @@
 dmd/version.c
 dmd/version.h
 gen
+gen/aa.cpp
+gen/aa.h
 gen/arrays.cpp
 gen/arrays.h
 gen/binops.cpp
@@ -136,6 +138,7 @@
 lphobos
 lphobos/crc32.d
 lphobos/gc
+lphobos/gc/gcbits.d
 lphobos/gc/gclinux.d
 lphobos/gc/gcstub.d
 lphobos/gcstats.d
@@ -145,7 +148,6 @@
 lphobos/internal/aaA.d
 lphobos/internal/adi.d
 lphobos/internal/arrays.d
-lphobos/internal/cmath2.d
 lphobos/internal/contract.d
 lphobos/internal/mem.d
 lphobos/internal/moduleinit.d
@@ -232,6 +234,10 @@
 test
 test/a.d
 test/aa1.d
+test/aa2.d
+test/aa3.d
+test/aa4.d
+test/aa5.d
 test/alignment.d
 test/alloca1.d
 test/arrayinit.d
@@ -240,6 +246,7 @@
 test/arrays11.d
 test/arrays12.d
 test/arrays13.d
+test/arrays14.d
 test/arrays2.d
 test/arrays3.d
 test/arrays4.d
@@ -316,6 +323,7 @@
 test/bug71.d
 test/bug72.d
 test/bug73.d
+test/bug74.d
 test/bug8.d
 test/bug9.d
 test/c.d
@@ -418,6 +426,7 @@
 test/typeinfo10.d
 test/typeinfo11.d
 test/typeinfo12.d
+test/typeinfo13.d
 test/typeinfo2.d
 test/typeinfo3.d
 test/typeinfo4.d
--- a/lphobos/build.sh	Tue Nov 20 05:29:20 2007 +0100
+++ b/lphobos/build.sh	Wed Nov 21 04:13:15 2007 +0100
@@ -51,7 +51,8 @@
 echo "compiling garbage collector"
 llvmdc gc/gclinux.d -c -odobj || exit 1
 llvmdc gc/gcstub.d -c -odobj -Igc || exit 1
-llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcstub.bc ../lib/llvmdcore.bc || exit 1
+llvmdc gc/gcbits.d -c -odobj -Igc || exit 1
+llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcstub.bc obj/gcbits.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling phobos"
 rebuild phobos.d -c -oqobj -dc=llvmdc-posix || exit 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gc/gcbits.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,176 @@
+
+// Copyright (C) 2001-2002 by Digital Mars
+// All Rights Reserved
+// www.digitalmars.com
+// Written by Walter Bright
+
+import std.c.string;
+import std.c.stdlib;
+import std.outofmemory;
+import std.intrinsic;
+
+//version = Asm86;
+version = bitops;
+
+struct GCBits
+{
+    const int BITS_PER_WORD = 32;
+    const int BITS_SHIFT = 5;
+    const int BITS_MASK = 31;
+
+    uint *data = null;
+    uint nwords = 0;	// allocated words in data[] excluding sentinals
+    uint nbits = 0;	// number of bits in data[] excluding sentinals
+
+    void Dtor()
+    {
+	if (data)
+	{
+	    free(data);
+	    data = null;
+	}
+    }
+
+    invariant
+    {
+	if (data)
+	{
+	    assert(nwords * data[0].sizeof * 8 >= nbits);
+	}
+    }
+
+    void alloc(uint nbits)
+    {
+	this.nbits = nbits;
+	nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
+	data = cast(uint *)calloc(nwords + 2, uint.sizeof);
+	if (!data)
+	    _d_OutOfMemory();
+    }
+
+    uint test(uint i)
+    in
+    {
+	assert(i < nbits);
+    }
+    body
+    {
+	//return (cast(bit *)(data + 1))[i];
+	return data[1 + (i >> BITS_SHIFT)] & (1 << (i & BITS_MASK));
+    }
+
+    void set(uint i)
+    in
+    {
+	assert(i < nbits);
+    }
+    body
+    {
+	//(cast(bit *)(data + 1))[i] = 1;
+	data[1 + (i >> BITS_SHIFT)] |= (1 << (i & BITS_MASK));
+    }
+
+    void clear(uint i)
+    in
+    {
+	assert(i < nbits);
+    }
+    body
+    {
+	//(cast(bit *)(data + 1))[i] = 0;
+	data[1 + (i >> BITS_SHIFT)] &= ~(1 << (i & BITS_MASK));
+    }
+
+    uint testClear(uint i)
+    {
+	version (bitops)
+	{
+	    return std.intrinsic.btr(data + 1, i);
+	}
+	else version (Asm86)
+	{
+	    asm
+	    {
+		naked			;
+		mov	EAX,data[EAX]	;
+		mov	ECX,i-4[ESP]	;
+		btr	4[EAX],ECX	;
+		sbb	EAX,EAX		;
+		ret	4		;
+	    }
+	}
+	else
+	{   uint result;
+
+	    //result = (cast(bit *)(data + 1))[i];
+	    //(cast(bit *)(data + 1))[i] = 0;
+
+	    uint *p = &data[1 + (i >> BITS_SHIFT)];
+	    uint mask = (1 << (i & BITS_MASK));
+	    result = *p & mask;
+	    *p &= ~mask;
+	    return result;
+	}
+    }
+
+    void zero()
+    {
+	memset(data + 1, 0, nwords * uint.sizeof);
+    }
+
+    void copy(GCBits *f)
+    in
+    {
+	assert(nwords == f.nwords);
+    }
+    body
+    {
+	memcpy(data + 1, f.data + 1, nwords * uint.sizeof);
+    }
+
+    uint *base()
+    in
+    {
+	assert(data);
+    }
+    body
+    {
+	return data + 1;
+    }
+}
+
+unittest
+{
+    GCBits b;
+
+    b.alloc(786);
+    assert(b.test(123) == 0);
+    assert(b.testClear(123) == 0);
+    b.set(123);
+    assert(b.test(123) != 0);
+    assert(b.testClear(123) != 0);
+    assert(b.test(123) == 0);
+
+    b.set(785);
+    b.set(0);
+    assert(b.test(785) != 0);
+    assert(b.test(0) != 0);
+    b.zero();
+    assert(b.test(785) == 0);
+    assert(b.test(0) == 0);
+
+    GCBits b2;
+    b2.alloc(786);
+    b2.set(38);
+    b.copy(&b2);
+    assert(b.test(38) != 0);
+    b2.Dtor();
+
+    b.Dtor();
+}
+
+/+
+void main()
+{
+}
++/
--- a/lphobos/internal/aaA.d	Tue Nov 20 05:29:20 2007 +0100
+++ b/lphobos/internal/aaA.d	Wed Nov 21 04:13:15 2007 +0100
@@ -27,13 +27,19 @@
  *     distribution.
  */
 
+/*
+ * Modified for LLVMDC by Tomas Lindquist Olsen.
+ * The DMD implementation wont quite work due to the differences in how
+ * structs are handled.
+ */
+
 
 //import std.stdio;
 import std.c.stdarg;
 import std.c.stdio;
 import std.c.stdlib;
 import std.c.string;
-import std.string;
+//import std.string;
 
 import std.outofmemory;
 
@@ -51,17 +57,17 @@
 
 /* This is the type of the return value for dynamic arrays.
  * It should be a type that is returned in registers.
- * Although DMD will return types of Array in registers,
- * gcc will not, so we instead use a 'long'.
  */
-alias long ArrayRet_t;
+alias Array ArrayRet_t;
 
+pragma(LLVM_internal, "notypeinfo")
 struct Array
 {
     size_t length;
     void* ptr;
 }
 
+pragma(LLVM_internal, "notypeinfo")
 struct aaA
 {
     aaA *left;
@@ -71,6 +77,7 @@
     /* value */
 }
 
+pragma(LLVM_internal, "notypeinfo")
 struct BB
 {
     aaA*[] b;
@@ -81,10 +88,7 @@
  * it is completely opaque.
  */
 
-struct AA
-{
-    BB* a;
-}
+alias BB* AA;
 
 /**********************************
  * Align to next pointer boundary, so that
@@ -198,9 +202,9 @@
 	    }
 	}
 
-	if (aa.a)
+	if (aa)
 	{
-	    foreach (e; aa.a.b)
+	    foreach (e; aa.b)
 	    {
 		if (e)
 		    _aaLen_x(e);
@@ -212,7 +216,7 @@
     }
     body
     {
-	return aa.a ? aa.a.nodes : 0;
+	return aa ? aa.nodes : 0;
     }
 
 
@@ -221,7 +225,7 @@
  * Add entry for key if it is not already there.
  */
 
-void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
+void* _aaGet(AA* aa, TypeInfo keyti, void* pkey, size_t valuesize)
     in
     {
 	assert(aa);
@@ -229,32 +233,32 @@
     out (result)
     {
 	assert(result);
-	assert(aa.a);
-	assert(aa.a.b.length);
-	//assert(_aaInAh(*aa.a, key));
+	assert(*aa);
+	assert((*aa).b.length);
+	//assert(_aaInAh(*aa, key));
     }
     body
     {
-	auto pkey = cast(void *)(&valuesize + 1);
+	//auto pkey = cast(void *)(&valuesize + 1);
 	size_t i;
 	aaA* e;
 	auto keysize = aligntsize(keyti.tsize());
 
-	if (!aa.a)
-	    aa.a = new BB();
+	if (!*aa)
+	    *aa = new BB();
 
-	if (!aa.a.b.length)
+	if (!(*aa).b.length)
 	{
 	    alias aaA *pa;
 	    auto len = prime_list[0];
 
-	    aa.a.b = new pa[len];
+	    (*aa).b = new pa[len];
 	}
 
 	auto key_hash = keyti.getHash(pkey);
 	//printf("hash = %d\n", key_hash);
-	i = key_hash % aa.a.b.length;
-	auto pe = &aa.a.b[i];
+	i = key_hash % (*aa).b.length;
+	auto pe = &(*aa).b[i];
 	while ((e = *pe) != null)
 	{
 	    if (key_hash == e.hash)
@@ -275,9 +279,9 @@
 	e.hash = key_hash;
 	*pe = e;
 
-	auto nodes = ++aa.a.nodes;
-	//printf("length = %d, nodes = %d\n", (*aa.a).length, nodes);
-	if (nodes > aa.a.b.length * 4)
+	auto nodes = ++(*aa).nodes;
+	//printf("length = %d, nodes = %d\n", (*aa).length, nodes);
+	if (nodes > (*aa).b.length * 4)
 	{
 	    _aaRehash(aa,keyti);
 	}
@@ -292,22 +296,22 @@
  * Returns null if it is not already there.
  */
 
-void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
+void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void* pkey)
     {
 	//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
-	if (!aa.a)
+	if (!aa)
 	    return null;
 
-	auto pkey = cast(void *)(&valuesize + 1);
+	//auto pkey = cast(void *)(&valuesize + 1);
 	auto keysize = aligntsize(keyti.tsize());
-	auto len = aa.a.b.length;
+	auto len = aa.b.length;
 
 	if (len)
 	{
 	    auto key_hash = keyti.getHash(pkey);
 	    //printf("hash = %d\n", key_hash);
 	    size_t i = key_hash % len;
-	    auto e = aa.a.b[i];
+	    auto e = aa.b[i];
 	    while (e != null)
 	    {
 		if (key_hash == e.hash)
@@ -332,7 +336,7 @@
  *	!=null	in aa, return pointer to value
  */
 
-void* _aaIn(AA aa, TypeInfo keyti, ...)
+void* _aaIn(AA aa, TypeInfo keyti, void* pkey)
     in
     {
     }
@@ -342,19 +346,19 @@
     }
     body
     {
-	if (aa.a)
+	if (aa)
 	{
-	    auto pkey = cast(void *)(&keyti + 1);
+	    //auto pkey = cast(void *)(&keyti + 1);
 
-	    //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
-	    auto len = aa.a.b.length;
+	    //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
+	    auto len = aa.b.length;
 
 	    if (len)
 	    {
 		auto key_hash = keyti.getHash(pkey);
 		//printf("hash = %d\n", key_hash);
 		size_t i = key_hash % len;
-		auto e = aa.a.b[i];
+		auto e = aa.b[i];
 		while (e != null)
 		{
 		    if (key_hash == e.hash)
@@ -380,17 +384,17 @@
  * If key is not in aa[], do nothing.
  */
 
-void _aaDel(AA aa, TypeInfo keyti, ...)
+void _aaDel(AA aa, TypeInfo keyti, void* pkey)
     {
-	auto pkey = cast(void *)(&keyti + 1);
+	//auto pkey = cast(void *)(&keyti + 1);
 	aaA* e;
 
-	if (aa.a && aa.a.b.length)
+	if (aa && aa.b.length)
 	{
 	    auto key_hash = keyti.getHash(pkey);
 	    //printf("hash = %d\n", key_hash);
-	    size_t i = key_hash % aa.a.b.length;
-	    auto pe = &aa.a.b[i];
+	    size_t i = key_hash % aa.b.length;
+	    auto pe = &aa.b[i];
 	    while ((e = *pe) != null)	// null means not found
 	    {
 		if (key_hash == e.hash)
@@ -423,7 +427,7 @@
 			    e.right = null;
 			}
 
-			aa.a.nodes--;
+			aa.nodes--;
 
 			// Should notify GC that e can be free'd now
 			break;
@@ -470,19 +474,19 @@
 	    } while (e != null);
 	}
 
-	if (aa.a)
+	if (aa)
 	{
 	    a.length = _aaLen(aa);
 	    a.ptr = (new void[a.length * valuesize]).ptr;
 	    resi = 0;
-	    foreach (e; aa.a.b)
+	    foreach (e; aa.b)
 	    {
 		if (e)
 		    _aaValues_x(e);
 	    }
 	    assert(resi == a.length);
 	}
-	return *cast(ArrayRet_t*)(&a);
+	return a;
     }
 
 
@@ -493,6 +497,7 @@
 void* _aaRehash(AA* paa, TypeInfo keyti)
     in
     {
+    assert(paa);
 	//_aaInvAh(paa);
     }
     out (result)
@@ -549,9 +554,9 @@
 	}
 
 	//printf("Rehash\n");
-	if (paa.a)
+	if (paa)
 	{
-	    auto aa = paa.a;
+	    auto aa = *paa;
 	    auto len = _aaLen(*paa);
 	    if (len)
 	    {   size_t i;
@@ -573,9 +578,9 @@
 		newb.nodes = aa.nodes;
 	    }
 
-	    *paa.a = newb;
+	    **paa = newb;
 	}
-	return (*paa).a;
+	return *paa;
     }
 
 
@@ -607,20 +612,17 @@
 
 	auto len = _aaLen(aa);
 	if (!len)
-	    return 0;
+	    return ArrayRet_t.init;
 	res = cast(byte[])new void[len * keysize];
 	resi = 0;
-	foreach (e; aa.a.b)
+	foreach (e; aa.b)
 	{
 	    if (e)
 		_aaKeys_x(e);
 	}
 	assert(resi == len);
 
-	Array a;
-	a.length = len;
-	a.ptr = res.ptr;
-	return *cast(ArrayRet_t*)(&a);
+	return Array(len, res.ptr);
     }
 
 
@@ -639,7 +641,7 @@
 body
 {   int result;
 
-    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
 
     int treewalker(aaA* e)
     {	int result;
@@ -666,9 +668,9 @@
 	return result;
     }
 
-    if (aa.a)
+    if (aa)
     {
-	foreach (e; aa.a.b)
+	foreach (e; aa.b)
 	{
 	    if (e)
 	    {
@@ -692,7 +694,7 @@
 body
 {   int result;
 
-    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
 
     int treewalker(aaA* e)
     {	int result;
@@ -719,9 +721,9 @@
 	return result;
     }
 
-    if (aa.a)
+    if (aa)
     {
-	foreach (e; aa.a.b)
+	foreach (e; aa.b)
 	{
 	    if (e)
 	    {
--- a/lphobos/internal/adi.d	Tue Nov 20 05:29:20 2007 +0100
+++ b/lphobos/internal/adi.d	Wed Nov 21 04:13:15 2007 +0100
@@ -51,7 +51,7 @@
  * reversed.
  */
 
-extern (C) long _adReverseChar(char[] a)
+extern (C) char[] _adReverseChar(char[] a)
 {
     if (a.length > 1)
     {
@@ -111,7 +111,7 @@
         hi = hi - 1 + (stridehi - stridelo);
     }
     }
-    return *cast(long*)(&a);
+    return a;
 }
 
 unittest
@@ -147,7 +147,7 @@
  * reversed.
  */
 
-extern (C) long _adReverseWchar(wchar[] a)
+extern (C) wchar[] _adReverseWchar(wchar[] a)
 {
     if (a.length > 1)
     {
@@ -205,7 +205,7 @@
         hi = hi - 1 + (stridehi - stridelo);
     }
     }
-    return *cast(long*)(&a);
+    return a;
 }
 
 unittest
@@ -230,13 +230,8 @@
  * Support for array.reverse property.
  */
 
-extern (C) long _adReverse(Array a, size_t szelem)
-    out (result)
-    {
-    assert(result is *cast(long*)(&a));
-    }
-    body
-    {
+extern (C) Array _adReverse(Array a, size_t szelem)
+{
     if (a.length >= 2)
     {
         byte* tmp;
@@ -272,8 +267,8 @@
             //delete tmp;
         }
     }
-    return *cast(long*)(&a);
-    }
+    return a;
+}
 
 unittest
 {
@@ -364,7 +359,7 @@
  * Sort array of chars.
  */
 
-extern (C) long _adSortChar(char[] a)
+extern (C) char[] _adSortChar(char[] a)
 {
     if (a.length > 1)
     {
@@ -379,14 +374,14 @@
     }
     delete da;
     }
-    return *cast(long*)(&a);
+    return a;
 }
 
 /**********************************************
  * Sort array of wchars.
  */
 
-extern (C) long _adSortWchar(wchar[] a)
+extern (C) wchar[] _adSortWchar(wchar[] a)
 {
     if (a.length > 1)
     {
@@ -401,7 +396,7 @@
     }
     delete da;
     }
-    return *cast(long*)(&a);
+    return a;
 }
 
 /**********************************************
@@ -803,3 +798,41 @@
     assert(a >= e);
 }
 }
+
+/**********************************
+ * Support for array.dup property.
+ */
+
+extern(C)
+void* _d_realloc(void*, size_t);
+
+extern(C)
+Array _adDupT(TypeInfo ti, Array a)
+{
+    Array r;
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();        // array element size
+        auto size = a.length * sizeelem;
+        r.ptr = _d_realloc(null,size);
+        r.length = a.length;
+        memcpy(r.ptr, a.ptr, size);
+    }
+    return r;
+}
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    debug(adi) printf("array.dup.unittest\n");
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+    assert(b[i] == i + 1);
+}
--- a/lphobos/internal/arrays.d	Tue Nov 20 05:29:20 2007 +0100
+++ b/lphobos/internal/arrays.d	Wed Nov 21 04:13:15 2007 +0100
@@ -78,7 +78,7 @@
         *p++ = v;
 }
 
-void _d_array_init(void* a, size_t na, void* v, size_t nv)
+void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
 {
     auto p = a;
     auto end = a + na*nv;
--- a/lphobos/internal/qsort2.d	Tue Nov 20 05:29:20 2007 +0100
+++ b/lphobos/internal/qsort2.d	Wed Nov 21 04:13:15 2007 +0100
@@ -14,6 +14,7 @@
 
 import std.c.stdlib;
 
+pragma(LLVM_internal, "notypeinfo")
 struct Array
 {
     size_t length;
@@ -27,14 +28,14 @@
     return tiglobal.compare(p1, p2);
 }
 
-extern (C) long _adSort(Array a, TypeInfo ti)
+extern (C) Array _adSort(Array a, TypeInfo ti)
 {
     synchronized
     {
 	tiglobal = ti;
 	std.c.stdlib.qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
     }
-    return *cast(long*)(&a);
+    return a;
 }
 
 
--- a/test/aa1.d	Tue Nov 20 05:29:20 2007 +0100
+++ b/test/aa1.d	Wed Nov 21 04:13:15 2007 +0100
@@ -3,4 +3,13 @@
 void main()
 {
     int[int] aai;
+    assert(aai is null);
+    aai[0] = 52;
+    assert(aai !is null);
+    int i = aai[0];
+    assert(i == 52);
+    aai[32] = 123;
+    int j = aai[32];
+    assert(i == 52);
+    assert(j == 123);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aa2.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,12 @@
+module aa2;
+
+void main()
+{
+    long[float] aa;
+    long* p = 2.0f in aa;
+    assert(!p);
+    aa[4f] = 23;
+    p = 4f in aa;
+    assert(p);
+    assert(*p == 23);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aa3.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,24 @@
+module aa3;
+
+void main()
+{
+    int[string] aa;
+    {aa["hello"] = 1;}
+    {int* p = "" in aa;}
+    aa[" worl"] = 2;
+    aa["d"] = 3;
+    aa["thisisgreat"] = 10;
+    int sum;
+    string cat;
+    {
+    foreach(k,v;aa)
+    {
+        printf("int[%.*s] = %d\n", k.length, k.ptr, v);
+        sum += v;
+        cat ~= k;
+    }
+    }
+    assert(sum == 16);
+    printf("cat = %.*s\n", cat.length, cat.ptr);
+    assert(cat.length == 22);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aa4.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,20 @@
+module aa4;
+
+void main()
+{
+    int[int] aa;
+    aa = addkey(aa,42,12);
+    int* p = haskey(aa,42);
+    assert(p && *p == 12);
+}
+
+int[int] addkey(int[int] aa, int key, int val)
+{
+    aa[key] = val;
+    return aa;
+}
+
+int* haskey(int[int] aa, int key)
+{
+    return key in aa;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/aa5.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,9 @@
+module aa5;
+
+void main()
+{
+    int[int] aa;
+    aa[42] = 1;
+    int i = aa[42];
+    assert(i == 1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/arrays14.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,7 @@
+module arrays14;
+
+void main()
+{
+    auto s = "hello world";
+    auto d = s.dup;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/typeinfo13.d	Wed Nov 21 04:13:15 2007 +0100
@@ -0,0 +1,13 @@
+module typeinfo13;
+
+void main()
+{
+    float[long] aa;
+    auto ti = typeid(typeof(aa));
+    assert(ti.toString() == "float[long]");
+    assert(ti.next() is typeid(float));
+    assert(ti.tsize() == size_t.sizeof);
+    auto aati = cast(TypeInfo_AssociativeArray)ti;
+    assert(aati.value is typeid(float));
+    assert(aati.key is typeid(long));
+}