changeset 131:5825d48b27d1 trunk

[svn r135] * Merged DMD 1.025 * * Fixed a minor linking order mishap * * Added an command line option -annotate * * Fixed some problems with running optimizations * * Added std.stdio and dependencies to lphobos (still not 100% working, but compiles and links) * * Fixed problems with passing aggregate types to variadic functions * * Added initial code towards full GC support, currently based on malloc and friends, not all the runtime calls the GC yet for memory * * Fixed problems with resolving nested function context pointers for some heavily nested cases * * Redid function argument passing + other minor code cleanups, still lots to do on this end... *
author lindquist
date Fri, 04 Jan 2008 01:38:42 +0100
parents a7dfa0ed966c
children 1700239cab2e
files dmd/cast.c dmd/expression.c dmd/init.c dmd/interpret.c dmd/link.c dmd/mars.c dmd/mars.h dmd/mtype.c dmd/mtype.h gen/functions.cpp gen/functions.h gen/logger.cpp gen/logger.h gen/optimizer.cpp gen/statements.cpp gen/todebug.cpp gen/toir.cpp gen/tollvm.cpp gen/tollvm.h gen/toobj.cpp llvmdc.kdevelop llvmdc.kdevelop.filelist lphobos/build.sh lphobos/gc/gc.d lphobos/gc/gcstub.d lphobos/gc/gcx.d lphobos/llvm/intrinsic.d lphobos/phobos.d lphobos/std/conv.d lphobos/std/format.d lphobos/std/gc.di lphobos/std/stdarg.d lphobos/std/stdio.d lphobos/std/thread.d premake.lua test/asm1.d test/bug79.d test/bug80.d test/calls1.d test/nested11.d test/nested12.d test/stdiotest.d test/stdiotest2.d test/vararg5.d
diffstat 44 files changed, 4591 insertions(+), 596 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/cast.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/cast.c	Fri Jan 04 01:38:42 2008 +0100
@@ -547,30 +547,27 @@
  */
 
 Expression *Expression::castTo(Scope *sc, Type *t)
-{   Expression *e;
-    Type *tb;
-
+{
     //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
 #if 0
     printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
 	toChars(), type->toChars(), t->toChars());
 #endif
-    e = this;
-    tb = t->toBasetype();
-    type = type->toBasetype();
-    if (tb != type)
+    if (type == t)
+	return this;
+    Expression *e = this;
+    Type *tb = t->toBasetype();
+    Type *typeb = type->toBasetype();
+    if (tb != typeb)
     {
-	if (tb->ty == Tbit && isBit())
-	    ;
-
 	// Do (type *) cast of (type [dim])
-	else if (tb->ty == Tpointer &&
-	    type->ty == Tsarray
+	if (tb->ty == Tpointer &&
+	    typeb->ty == Tsarray
 	   )
 	{
 	    //printf("Converting [dim] to *\n");
 
-	    if (type->size(loc) == 0)
+	    if (typeb->size(loc) == 0)
 		e = new NullExp(loc);
 	    else
 		e = new AddrExp(loc, e);
@@ -579,8 +576,8 @@
 	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
 	{
 	    TypeDelegate *td = (TypeDelegate *)tb;
-	    TypeFunction *tf = (TypeFunction *)td->next;
-	    return toDelegate(sc, tf->next);
+	    TypeFunction *tf = (TypeFunction *)td->nextOf();
+	    return toDelegate(sc, tf->nextOf());
 	}
 #endif
 	else
@@ -588,6 +585,11 @@
 	    e = new CastExp(loc, e, tb);
 	}
     }
+    else
+    {
+	e = e->copy();	// because of COW for assignment to e->type
+    }
+    assert(e != this);
     e->type = t;
     //printf("Returning: %s\n", e->toChars());
     return e;
@@ -595,47 +597,62 @@
 
 
 Expression *RealExp::castTo(Scope *sc, Type *t)
-{
-    if (type->isreal() && t->isreal())
-	type = t;
-    else if (type->isimaginary() && t->isimaginary())
-	type = t;
-    else
-	return Expression::castTo(sc, t);
-    return this;
+{   Expression *e = this;
+    if (type != t)
+    {
+	if ((type->isreal() && t->isreal()) ||
+	    (type->isimaginary() && t->isimaginary())
+	   )
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
 }
 
 
 Expression *ComplexExp::castTo(Scope *sc, Type *t)
-{
-    if (type->iscomplex() && t->iscomplex())
-	type = t;
-    else
-	return Expression::castTo(sc, t);
-    return this;
+{   Expression *e = this;
+    if (type != t)
+    {
+	if (type->iscomplex() && t->iscomplex())
+	{   e = copy();
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
 }
 
 
 Expression *NullExp::castTo(Scope *sc, Type *t)
-{   Expression *e;
+{   NullExp *e;
     Type *tb;
 
     //printf("NullExp::castTo(t = %p)\n", t);
-    committed = 1;
-    e = this;
+    if (type == t)
+    {
+	committed = 1;
+	return this;
+    }
+    e = (NullExp *)copy();
+    e->committed = 1;
     tb = t->toBasetype();
-    type = type->toBasetype();
-    if (tb != type)
+    e->type = type->toBasetype();
+    if (tb != e->type)
     {
 	// NULL implicitly converts to any pointer type or dynamic array
-	if (type->ty == Tpointer && type->next->ty == Tvoid &&
+	if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
 	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
 	     tb->ty == Tdelegate))
 	{
 #if 0
 	    if (tb->ty == Tdelegate)
 	    {   TypeDelegate *td = (TypeDelegate *)tb;
-		TypeFunction *tf = (TypeFunction *)td->next;
+		TypeFunction *tf = (TypeFunction *)td->nextOf();
 
 		if (!tf->varargs &&
 		    !(tf->arguments && tf->arguments->dim)
@@ -648,8 +665,7 @@
 	}
 	else
 	{
-	    return Expression::castTo(sc, t);
-	    //e = new CastExp(loc, e, tb);
+	    return e->Expression::castTo(sc, t);
 	}
     }
     e->type = t;
@@ -919,23 +935,31 @@
 
 
 Expression *TupleExp::castTo(Scope *sc, Type *t)
-{
-    for (size_t i = 0; i < exps->dim; i++)
-    {   Expression *e = (Expression *)exps->data[i];
-	e = e->castTo(sc, t);
-	exps->data[i] = (void *)e;
+{   TupleExp *e = (TupleExp *)copy();
+    e->exps = (Expressions *)exps->copy();
+    for (size_t i = 0; i < e->exps->dim; i++)
+    {   Expression *ex = (Expression *)e->exps->data[i];
+	ex = ex->castTo(sc, t);
+	e->exps->data[i] = (void *)ex;
     }
-    return this;
+    return e;
 }
 
 
 Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
 {
+#if 0
+    printf("ArrayLiteralExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type == t)
+	return this;
+    ArrayLiteralExp *e = this;
     Type *typeb = type->toBasetype();
     Type *tb = t->toBasetype();
     if ((tb->ty == Tarray || tb->ty == Tsarray) &&
 	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
-	tb->next->toBasetype()->ty != Tvoid)
+	tb->nextOf()->toBasetype()->ty != Tvoid)
     {
 	if (tb->ty == Tsarray)
 	{   TypeSArray *tsa = (TypeSArray *)tb;
@@ -943,46 +967,56 @@
 		goto L1;
 	}
 
+	e = (ArrayLiteralExp *)copy();
+	e->elements = (Expressions *)elements->copy();
 	for (int i = 0; i < elements->dim; i++)
-	{   Expression *e = (Expression *)elements->data[i];
-	    e = e->castTo(sc, tb->next);
-	    elements->data[i] = (void *)e;
+	{   Expression *ex = (Expression *)elements->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->elements->data[i] = (void *)ex;
 	}
-	type = t;
-	return this;
+	e->type = t;
+	return e;
     }
     if (tb->ty == Tpointer && typeb->ty == Tsarray)
     {
-	type = typeb->next->pointerTo();
+	e = (ArrayLiteralExp *)copy();
+	e->type = typeb->nextOf()->pointerTo();
     }
 L1:
-    return Expression::castTo(sc, t);
+    return e->Expression::castTo(sc, t);
 }
 
 Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
 {
+    if (type == t)
+	return this;
+    AssocArrayLiteralExp *e = this;
     Type *typeb = type->toBasetype();
     Type *tb = t->toBasetype();
     if (tb->ty == Taarray && typeb->ty == Taarray &&
-	tb->next->toBasetype()->ty != Tvoid)
+	tb->nextOf()->toBasetype()->ty != Tvoid)
     {
+	e = (AssocArrayLiteralExp *)copy();
+	e->keys = (Expressions *)keys->copy();
+	e->values = (Expressions *)values->copy();
 	assert(keys->dim == values->dim);
 	for (size_t i = 0; i < keys->dim; i++)
-	{   Expression *e = (Expression *)values->data[i];
-	    e = e->castTo(sc, tb->next);
-	    values->data[i] = (void *)e;
+	{   Expression *ex = (Expression *)values->data[i];
+	    ex = ex->castTo(sc, tb->nextOf());
+	    e->values->data[i] = (void *)ex;
 
-	    e = (Expression *)keys->data[i];
-	    e = e->castTo(sc, ((TypeAArray *)tb)->key);
-	    keys->data[i] = (void *)e;
+	    ex = (Expression *)keys->data[i];
+	    ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
+	    e->keys->data[i] = (void *)ex;
 	}
-	type = t;
-	return this;
+	e->type = t;
+	return e;
     }
 L1:
-    return Expression::castTo(sc, t);
+    return e->Expression::castTo(sc, t);
 }
 
+
 Expression *SymOffExp::castTo(Scope *sc, Type *t)
 {
     Type *tb;
--- a/dmd/expression.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/expression.c	Fri Jan 04 01:38:42 2008 +0100
@@ -1760,7 +1760,7 @@
     em = s->isEnumMember();
     if (em)
     {
-	e = em->value;
+	e = em->value->copy();
 	e = e->semantic(sc);
 	return e;
     }
--- a/dmd/init.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/init.c	Fri Jan 04 01:38:42 2008 +0100
@@ -179,7 +179,7 @@
 		s = ad->search(loc, id, 0);
 		if (!s)
 		{
-		    error("'%s' is not a member of '%s'", id->toChars(), t->toChars());
+		    error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
 		    continue;
 		}
 
--- a/dmd/interpret.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/interpret.c	Fri Jan 04 01:38:42 2008 +0100
@@ -57,7 +57,7 @@
 Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments)
 {
 #if LOG
-    printf("FuncDeclaration::interpret() %s\n", toChars());
+    printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars());
     printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun);
 #endif
     if (global.errors)
@@ -161,7 +161,15 @@
 	    else
 	    {	/* Value parameters
 		 */
-		earg = earg->interpret(&istatex);
+		Type *ta = arg->type->toBasetype();
+		if (ta->ty == Tsarray && earg->op == TOKaddress)
+		{
+		    /* Static arrays are passed by a simple pointer.
+		     * Skip past this to get at the actual arg.
+		     */
+		    earg = ((AddrExp *)earg)->e1;
+		}
+		earg = earg->interpret(istate ? istate : &istatex);
 		if (earg == EXP_CANT_INTERPRET)
 		    return NULL;
 		v->value = earg;
@@ -177,13 +185,13 @@
     Expressions valueSaves;
     if (istate)
     {
-	//printf("saving state...\n");
+	//printf("saving local variables...\n");
 	valueSaves.setDim(istate->vars.dim);
 	for (size_t i = 0; i < istate->vars.dim; i++)
 	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
 	    if (v)
 	    {
-		//printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value->toChars());
+		//printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
 		valueSaves.data[i] = v->value;
 		v->value = NULL;
 	    }
@@ -230,10 +238,13 @@
     {
 	/* Restore the variable values
 	 */
+	//printf("restoring local variables...\n");
 	for (size_t i = 0; i < istate->vars.dim; i++)
 	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
 	    if (v)
-		v->value = (Expression *)valueSaves.data[i];
+	    {	v->value = (Expression *)valueSaves.data[i];
+		//printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
+	    }
 	}
     }
 
@@ -904,6 +915,8 @@
 {
 #if LOG
     printf("Expression::interpret() %s\n", toChars());
+    printf("type = %s\n", type->toChars());
+    dump(0);
 #endif
     return EXP_CANT_INTERPRET;
 }
@@ -949,7 +962,11 @@
     SymbolDeclaration *s = d->isSymbolDeclaration();
     if (v)
     {
+#if V2
+	if ((v->isConst() || v->isInvariant()) && v->init && !v->value)
+#else
 	if (v->isConst() && v->init)
+#endif
 	{   e = v->init->toExpression();
 	    if (e && !e->type)
 		e->type = v->type;
@@ -1001,7 +1018,11 @@
 	    else if (v->init->isVoidInitializer())
 		e = NULL;
 	}
+#if V2
+	else if (s == v && (v->isConst() || v->isInvariant()) && v->init)
+#else
 	else if (s == v && v->isConst() && v->init)
+#endif
 	{   e = v->init->toExpression();
 	    if (!e)
 		e = EXP_CANT_INTERPRET;
@@ -1416,8 +1437,16 @@
 	     */
 	    if (v->value && v->value->op == TOKvar)
 	    {
-		ve = (VarExp *)v->value;
-		v = ve->var->isVarDeclaration();
+		VarExp *ve2 = (VarExp *)v->value;
+		if (ve2->var->isSymbolDeclaration())
+		{
+		    /* This can happen if v is a struct initialized to
+		     * 0 using an __initZ SymbolDeclaration from
+		     * TypeStruct::defaultInit()
+		     */
+		}
+		else
+		    v = ve2->var->isVarDeclaration();
 		assert(v);
 	    }
 
@@ -1445,6 +1474,7 @@
 		    {
 			if (i == istate->vars.dim)
 			{   istate->vars.push(v);
+			    //printf("\tadding %s to istate\n", v->toChars());
 			    break;
 			}
 			if (v == (VarDeclaration *)istate->vars.data[i])
@@ -1797,7 +1827,27 @@
     {
 	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
 	if (fd)
-	{   // Inline .dup
+	{
+#if V2
+	    enum BUILTIN b = fd->isBuiltin();
+	    if (b)
+	    {	Expressions args;
+		args.setDim(arguments->dim);
+		for (size_t i = 0; i < args.dim; i++)
+		{
+		    Expression *earg = (Expression *)arguments->data[i];
+		    earg = earg->interpret(istate);
+		    if (earg == EXP_CANT_INTERPRET)
+			return earg;
+		    args.data[i] = (void *)earg;
+		}
+		e = eval_builtin(b, &args);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+	    }
+	    else
+#endif
+	    // Inline .dup
 	    if (fd->ident == Id::adDup && arguments && arguments->dim == 2)
 	    {
 		e = (Expression *)arguments->data[1];
@@ -1812,7 +1862,7 @@
 		Expression *eresult = fd->interpret(istate, arguments);
 		if (eresult)
 		    e = eresult;
-		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid)
+		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
 		    e = EXP_VOID_INTERPRET;
 		else
 		    error("cannot evaluate %s at compile time", toChars());
--- a/dmd/link.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/link.c	Fri Jan 04 01:38:42 2008 +0100
@@ -283,15 +283,15 @@
      * passed with -l.
      */
 
+    //argv.push((void *)"-lphobos");    // turns into /usr/lib/libphobos.a
+    argv.push((void *)"-lpthread");
+    argv.push((void *)"-lm");
+
     std::string corelibpath = global.params.runtimeImppath;
     corelibpath.append("/llvmdcore.bc");
     argv.append(global.params.objfiles);
     argv.push((void *)corelibpath.c_str());
 
-    //argv.push((void *)"-lphobos");    // turns into /usr/lib/libphobos.a
-    //argv.push((void *)"-lpthread");
-    argv.push((void *)"-l=m");
-
     if (!global.params.quiet)
     {
 	// Print it
--- a/dmd/mars.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/mars.c	Fri Jan 04 01:38:42 2008 +0100
@@ -71,7 +71,7 @@
     copyright = "Copyright (c) 1999-2007 by Digital Mars and Tomas Lindquist Olsen";
     written = "written by Walter Bright and Tomas Lindquist Olsen";
     llvmdc_version = "0.1";
-    version = "v1.024";
+    version = "v1.025";
     global.structalign = 8;
 
     memset(&params, 0, sizeof(Param));
@@ -167,6 +167,7 @@
   dmd files.d ... { -switch }\n\
 \n\
   files.d        D source files\n%s\
+  -annotate      annotate the bitcode with human readable source code\n\
   -c             do not link\n\
   -cov           do code coverage analysis\n\
   -D             generate documentation\n\
@@ -290,7 +291,7 @@
     global.params.forceBE = 0;
     global.params.noruntime = 0;
     global.params.novalidate = 0;
-    global.params.optimizeLevel = 2;
+    global.params.optimizeLevel = -1;
     global.params.runtimeImppath = 0;
 
     global.params.defaultlibname = "phobos";
@@ -370,6 +371,7 @@
 	    else if (p[1] == 'O')
         {
             global.params.optimize = 1;
+            global.params.optimizeLevel = 2;
             if (p[2] != 0) {
                 int optlevel = atoi(p+2);
                 if (optlevel < 0 || optlevel > 5) {
@@ -389,6 +391,8 @@
         global.params.novalidate = 1;
         else if (strcmp(p + 1, "dis") == 0)
         global.params.disassemble = 1;
+        else if (strcmp(p + 1, "annotate") == 0)
+        global.params.llvmAnnotate = 1;
 	    else if (p[1] == 'o')
 	    {
 		switch (p[2])
@@ -683,6 +687,7 @@
 
     if (strcmp(global.params.llvmArch,"x86")==0) {
         VersionCondition::addPredefinedGlobalIdent("X86");
+        //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86");
         global.params.isLE = true;
         global.params.is64bit = false;
         tt_arch = "i686";
@@ -690,6 +695,7 @@
     }
     else if (strcmp(global.params.llvmArch,"x86-64")==0) {
         VersionCondition::addPredefinedGlobalIdent("X86_64");
+        //VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64");
         global.params.isLE = true;
         global.params.is64bit = true;
         tt_arch = "x86_64";
--- a/dmd/mars.h	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/mars.h	Fri Jan 04 01:38:42 2008 +0100
@@ -130,6 +130,7 @@
     char *data_layout;
     char disassemble;
     char llvmInline;
+    char llvmAnnotate;
 };
 
 struct Global
--- a/dmd/mtype.c	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/mtype.c	Fri Jan 04 01:38:42 2008 +0100
@@ -5077,7 +5077,6 @@
     this->ident = ident;
     this->storageClass = storageClass;
     this->defaultArg = defaultArg;
-    this->llvmCopy = false;
     this->vardecl = 0;
 }
 
--- a/dmd/mtype.h	Fri Dec 28 23:52:40 2007 +0100
+++ b/dmd/mtype.h	Fri Jan 04 01:38:42 2008 +0100
@@ -692,7 +692,6 @@
     static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
 
     // backend
-    bool llvmCopy;
     VarDeclaration* vardecl;
 };
 
--- a/gen/functions.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/functions.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -16,6 +16,7 @@
 #include "gen/functions.h"
 #include "gen/todebug.h"
 #include "gen/classes.h"
+#include "gen/dvalue.h"
 
 const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain)
 {
@@ -90,13 +91,6 @@
         Type* argT = DtoDType(arg->type);
         assert(argT);
 
-        if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
-            //assert(arg->vardecl);
-            //arg->vardecl->refparam = true;
-        }
-        else
-            arg->llvmCopy = true;
-
         const llvm::Type* at = DtoType(argT);
         if (isaStruct(at)) {
             Logger::println("struct param");
@@ -114,8 +108,8 @@
             paramvec.push_back(llvm::PointerType::get(at));
         }
         else {
-            if (!arg->llvmCopy) {
-                Logger::println("ref param");
+            if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
+                Logger::println("by ref param");
                 at = llvm::PointerType::get(at);
             }
             else {
@@ -509,8 +503,8 @@
                 if (global.params.symdebug) DtoDwarfFuncStart(fd);
 
                 llvm::Value* parentNested = NULL;
-                if (FuncDeclaration* fd2 = fd->toParent()->isFuncDeclaration()) {
-                    if (!fd->isStatic())
+                if (FuncDeclaration* fd2 = fd->toParent2()->isFuncDeclaration()) {
+                    if (!fd->isStatic()) // huh?
                         parentNested = fd2->llvmNested;
                 }
 
@@ -722,3 +716,47 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoArgument(Argument* fnarg, Expression* argexp)
+{
+    Logger::println("DtoArgument");
+    LOG_SCOPE;
+
+    DValue* arg = argexp->toElem(gIR);
+
+    // ref/out arg
+    if (fnarg && ((fnarg->storageClass & STCref) || (fnarg->storageClass & STCout)))
+    {
+        if (arg->isVar() || arg->isLRValue())
+            arg = new DImValue(argexp->type, arg->getLVal(), false);
+        else
+            arg = new DImValue(argexp->type, arg->getRVal(), false);
+    }
+    // aggregate arg
+    else if (DtoIsPassedByRef(argexp->type))
+    {
+        llvm::Value* alloc = new llvm::AllocaInst(DtoType(argexp->type), "tmpparam", gIR->topallocapoint());
+        DVarValue* vv = new DVarValue(argexp->type, alloc, true);
+        DtoAssign(vv, arg);
+        arg = vv;
+    }
+    // normal arg (basic/value type)
+    else
+    {
+        // nothing to do
+    }
+
+    return arg;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoVariadicArgument(Expression* argexp, llvm::Value* dst)
+{
+    Logger::println("DtoVariadicArgument");
+    LOG_SCOPE;
+    DVarValue* vv = new DVarValue(argexp->type, dst, true);
+    DtoAssign(vv, argexp->toElem(gIR));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/functions.h	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/functions.h	Fri Jan 04 01:38:42 2008 +0100
@@ -10,6 +10,9 @@
 void DtoDeclareFunction(FuncDeclaration* fdecl);
 void DtoDefineFunc(FuncDeclaration* fd);
 
+DValue* DtoArgument(Argument* fnarg, Expression* argexp);
+void DtoVariadicArgument(Expression* argexp, llvm::Value* dst);
+
 void DtoMain();
 
 #endif
--- a/gen/logger.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/logger.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -13,30 +13,30 @@
     static std::string indent_str;
     static std::ofstream null_out("/dev/null");
 
-    static bool enabled = false;
+    static bool _enabled = false;
     void indent()
     {
-        if (enabled) {
+        if (_enabled) {
             indent_str += "* ";
         }
     }
     void undent()
     {
-        if (enabled) {
+        if (_enabled) {
             assert(!indent_str.empty());
             indent_str.resize(indent_str.size()-2);
         }
     }
     std::ostream& cout()
     {
-        if (enabled)
+        if (_enabled)
             return std::cout << indent_str;
         else
             return null_out;
     }
     void println(const char* fmt,...)
     {
-        if (enabled) {
+        if (_enabled) {
             printf(indent_str.c_str());
             va_list va;
             va_start(va,fmt);
@@ -47,7 +47,7 @@
     }
     void print(const char* fmt,...)
     {
-        if (enabled) {
+        if (_enabled) {
             printf(indent_str.c_str());
             va_list va;
             va_start(va,fmt);
@@ -57,11 +57,15 @@
     }
     void enable()
     {
-        enabled = true;
+        _enabled = true;
     }
     void disable()
     {
-        enabled = false;
+        _enabled = false;
+    }
+    bool enabled()
+    {
+        return _enabled;
     }
     void attention(const char* fmt,...)
     {
--- a/gen/logger.h	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/logger.h	Fri Jan 04 01:38:42 2008 +0100
@@ -12,6 +12,7 @@
     void print(const char* fmt, ...);
     void enable();
     void disable();
+    bool enabled();
 
     void attention(const char* fmt, ...);
 
--- a/gen/optimizer.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/optimizer.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -12,11 +12,22 @@
 
 void llvmdc_optimize_module(Module* m, char lvl, bool doinline)
 {
+    if (!doinline && lvl < 0)
+        return;
+
     assert(lvl >= 0 && lvl <= 5);
 
     PassManager pm;
     pm.add(new TargetData(m));
 
+    // -O0
+    if (lvl >= 0)
+    {
+        //pm.add(createStripDeadPrototypesPass());
+        pm.add(createGlobalDCEPass());
+    }
+
+    // -O1
     if (lvl >= 1)
     {
         pm.add(createRaiseAllocationsPass());
@@ -26,6 +37,7 @@
         pm.add(createGlobalDCEPass());
     }
 
+    // -O2
     if (lvl >= 2)
     {
         pm.add(createIPConstantPropagationPass());
@@ -35,10 +47,12 @@
         pm.add(createPruneEHPass());
     }
 
+    // -inline
     if (doinline) {
         pm.add(createFunctionInliningPass());
     }
 
+    // -O3
     if (lvl >= 3)
     {
         pm.add(createArgumentPromotionPass());
@@ -73,8 +87,7 @@
         pm.add(createConstantMergePass());
     }
 
-    // level 4 and 5 are linktime optimizations
+    // level -O4 and -O5 are linktime optimizations
 
-    if (lvl > 0 || doinline)
-        pm.run(*m);
+    pm.run(*m);
 }
--- a/gen/statements.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/statements.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -7,6 +7,7 @@
 #include <iostream>
 
 #include "gen/llvm.h"
+#include "llvm/InlineAsm.h"
 
 #include "total.h"
 #include "init.h"
@@ -129,6 +130,9 @@
     Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars());
     LOG_SCOPE;
 
+    if (global.params.llvmAnnotate)
+        DtoAnnotation(exp->toChars());
+
     if (global.params.symdebug)
         DtoDwarfStopPoint(loc.linnum);
 
@@ -146,8 +150,7 @@
 
 void IfStatement::toIR(IRState* p)
 {
-    static int wsi = 0;
-    Logger::println("IfStatement::toIR(%d): %s", wsi++, toChars());
+    Logger::println("IfStatement::toIR()");
     LOG_SCOPE;
 
     DValue* cond_e = condition->toElem(p);
@@ -983,6 +986,40 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+void AsmStatement::toIR(IRState* p)
+{
+    Logger::println("AsmStatement::toIR(): %s", toChars());
+    LOG_SCOPE;
+    error("%s: inline asm is not yet implemented", loc.toChars());
+    fatal();
+
+    assert(!asmcode && !asmalign && !refparam && !naked && !regs);
+
+    Token* t = tokens;
+    assert(t);
+
+    std::string asmstr;
+
+    do {
+        Logger::println("token: %s", t->toChars());
+        asmstr.append(t->toChars());
+        asmstr.append(" ");
+    } while (t = t->next);
+
+    Logger::println("asm expr = '%s'", asmstr.c_str());
+
+    // create function type
+    std::vector<const llvm::Type*> args;
+    const llvm::FunctionType* fty = llvm::FunctionType::get(DtoSize_t(), args, false);
+
+    // create inline asm callee
+    llvm::InlineAsm* inasm = llvm::InlineAsm::get(fty, asmstr, "r,r", false);
+
+    assert(0);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
 //////////////////////////////////////////////////////////////////////////////
 
 #define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
@@ -1004,7 +1041,7 @@
 //STUBST(ExpStatement);
 //STUBST(CompoundStatement);
 //STUBST(ScopeStatement);
-STUBST(AsmStatement);
+//STUBST(AsmStatement);
 //STUBST(TryCatchStatement);
 //STUBST(TryFinallyStatement);
 STUBST(VolatileStatement);
--- a/gen/todebug.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/todebug.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -120,10 +120,10 @@
             DtoConstUint(llvm::LLVMDebugVersion)));
         vals.push_back(dbgToArrTy(GetDwarfAnchor(DW_TAG_compile_unit)));
 
-        vals.push_back(DtoConstUint(DW_LANG_D));
+        vals.push_back(DtoConstUint(DW_LANG_C));// _D)); // doesn't seem to work
         vals.push_back(DtoConstStringPtr(m->srcfile->name->toChars(), "llvm.metadata"));
         std::string srcpath(FileName::path(m->srcfile->name->toChars()));
-        srcpath.append("/");
+        //srcpath.append("/");
         vals.push_back(DtoConstStringPtr(srcpath.c_str(), "llvm.metadata"));
         vals.push_back(DtoConstStringPtr("LLVMDC (http://www.dsource.org/projects/llvmdc)", "llvm.metadata"));
 
--- a/gen/toir.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/toir.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -31,6 +31,7 @@
 #include "gen/complex.h"
 #include "gen/dvalue.h"
 #include "gen/aa.h"
+#include "gen/functions.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -51,6 +52,9 @@
         }
         else
         {
+            if (global.params.llvmAnnotate)
+                DtoAnnotation(toChars());
+
             Logger::println("vdtype = %s", vd->type->toChars());
             // referenced by nested delegate?
             if (vd->nestedref) {
@@ -600,7 +604,16 @@
     }
     DtoAssign(l, res);
 
-    return l;
+    // used as lvalue :/
+    if (p->topexp() && p->topexp()->e1 == this)
+    {
+        assert(!l->isLRValue());
+        return l;
+    }
+    else
+    {
+        return res;
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -650,6 +663,7 @@
 
     DValue* res;
     if (DtoDType(e1->type)->ty == Tpointer) {
+        Logger::println("ptr");
         llvm::Value* tmp = r->getRVal();
         llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false);
         tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb());
@@ -657,9 +671,11 @@
         res = new DImValue(type, tmp);
     }
     else if (t->iscomplex()) {
+        Logger::println("complex");
         res = DtoComplexSub(type, l, r);
     }
     else {
+        Logger::println("basic");
         res = DtoBinSub(l,r);
     }
     DtoAssign(l, res);
@@ -904,7 +920,7 @@
         Logger::cout() << "what are we calling? : " << *funcval << '\n';
     }
     assert(llfnty);
-    Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
+    //Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
 
     // argument handling
     llvm::FunctionType::param_iterator argiter = llfnty->param_begin();
@@ -969,7 +985,7 @@
     // nested call
     else if (dfn && dfn->func && dfn->func->isNested()) {
         Logger::println("Nested Call");
-        llvm::Value* contextptr = p->func()->decl->llvmNested;
+        llvm::Value* contextptr = DtoNestedContext(dfn->func->toParent2()->isFuncDeclaration());
         if (!contextptr)
             contextptr = llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
         llargs[j] = DtoBitCast(contextptr, llvm::PointerType::get(llvm::Type::Int8Ty));
@@ -978,7 +994,8 @@
     }
 
     // va arg function special argument passing
-    if (va_magic) {
+    if (va_magic)
+    {
         size_t n = va_intrinsic ? arguments->dim : 1;
         for (int i=0; i<n; i++,j++)
         {
@@ -989,7 +1006,9 @@
         }
     }
     // regular arguments
-    else {
+    else
+    {
+        // d variadic function?
         if (tf->linkage == LINKd && tf->varargs == 1)
         {
             Logger::println("doing d-style variadic arguments");
@@ -997,53 +1016,71 @@
             size_t nimplicit = j;
 
             std::vector<const llvm::Type*> vtypes;
-            std::vector<llvm::Value*> vvalues;
             std::vector<llvm::Value*> vtypeinfos;
 
-            for (int i=0; i<arguments->dim; i++) {
-                Argument* fnarg = Argument::getNth(tf->parameters, i);
+            // build struct with argument types
+            for (int i=0; i<arguments->dim; i++)
+            {
                 Expression* argexp = (Expression*)arguments->data[i];
-                vvalues.push_back(DtoArgument(NULL, fnarg, argexp));
-                vtypes.push_back(vvalues.back()->getType());
-
+                vtypes.push_back(DtoType(argexp->type));
+            }
+            const llvm::StructType* vtype = llvm::StructType::get(vtypes);
+            Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n';
+            llvm::Value* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
+
+            // store arguments in the struct
+            for (int i=0; i<arguments->dim; i++)
+            {
+                Expression* argexp = (Expression*)arguments->data[i];
+                if (global.params.llvmAnnotate)
+                    DtoAnnotation(argexp->toChars());
+                DtoVariadicArgument(argexp, DtoGEPi(mem,0,i,"tmp"));
+            }
+
+            // build type info array
+            assert(Type::typeinfo->llvmConstInit);
+            const llvm::Type* typeinfotype = llvm::PointerType::get(Type::typeinfo->llvmConstInit->getType());
+            Logger::cout() << "typeinfo ptr type: " << *typeinfotype << '\n';
+            const llvm::ArrayType* typeinfoarraytype = llvm::ArrayType::get(typeinfotype,vtype->getNumElements());
+
+            llvm::Value* typeinfomem = new llvm::AllocaInst(typeinfoarraytype,"_arguments_storage",p->topallocapoint());
+            for (int i=0; i<arguments->dim; i++)
+            {
+                Expression* argexp = (Expression*)arguments->data[i];
                 TypeInfoDeclaration* tidecl = argexp->type->getTypeInfoDeclaration();
                 DtoForceDeclareDsymbol(tidecl);
                 assert(tidecl->llvmValue);
                 vtypeinfos.push_back(tidecl->llvmValue);
-            }
-
-            const llvm::StructType* vtype = llvm::StructType::get(vtypes);
-            llvm::Value* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
-            for (unsigned i=0; i<vtype->getNumElements(); ++i)
-                p->ir->CreateStore(vvalues[i], DtoGEPi(mem,0,i,"tmp"));
-
-            //llvm::Constant* typeinfoparam = llvm::ConstantPointerNull::get(isaPointer(llfnty->getParamType(j)));
-            assert(Type::typeinfo->llvmConstInit);
-            const llvm::Type* typeinfotype = llvm::PointerType::get(Type::typeinfo->llvmConstInit->getType());
-            Logger::cout() << "typeinfo ptr type: " << *typeinfotype << '\n';
-            const llvm::ArrayType* typeinfoarraytype = llvm::ArrayType::get(typeinfotype,vtype->getNumElements());
-            llvm::Value* typeinfomem = new llvm::AllocaInst(typeinfoarraytype,"_arguments_storage",p->topallocapoint());
-            for (unsigned i=0; i<vtype->getNumElements(); ++i) {
                 llvm::Value* v = p->ir->CreateBitCast(vtypeinfos[i], typeinfotype, "tmp");
                 p->ir->CreateStore(v, DtoGEPi(typeinfomem,0,i,"tmp"));
             }
 
+            // put data in d-array
             llvm::Value* typeinfoarrayparam = new llvm::AllocaInst(llfnty->getParamType(j)->getContainedType(0),"_arguments_array",p->topallocapoint());
             p->ir->CreateStore(DtoConstSize_t(vtype->getNumElements()), DtoGEPi(typeinfoarrayparam,0,0,"tmp"));
             llvm::Value* casttypeinfomem = p->ir->CreateBitCast(typeinfomem, llvm::PointerType::get(typeinfotype), "tmp");
             p->ir->CreateStore(casttypeinfomem, DtoGEPi(typeinfoarrayparam,0,1,"tmp"));
 
+            // specify arguments
             llargs[j] = typeinfoarrayparam;;
             j++;
             llargs[j] = p->ir->CreateBitCast(mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
             j++;
             llargs.resize(nimplicit+2);
         }
+        // normal function
         else {
             Logger::println("doing normal arguments");
             for (int i=0; i<arguments->dim; i++,j++) {
                 Argument* fnarg = Argument::getNth(tf->parameters, i);
-                llargs[j] = DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
+                if (global.params.llvmAnnotate)
+                    DtoAnnotation(((Expression*)arguments->data[i])->toChars());
+                DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
+                llargs[j] = argval->getRVal();
+                if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) {
+                    llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
+                }
+
                 // this hack is necessary :/
                 if (dfn && dfn->func && dfn->func->llvmRunTimeHack) {
                     if (llfnty->getParamType(j) != NULL) {
@@ -1850,7 +1887,11 @@
             {
                 Expression* ex = (Expression*)arguments->data[i];
                 Argument* fnarg = Argument::getNth(tf->parameters, i);
-                llvm::Value* a = DtoArgument(fn->getFunctionType()->getParamType(i+1), fnarg, ex);
+                DValue* argval = DtoArgument(fnarg, ex);
+                llvm::Value* a = argval->getRVal();
+                const llvm::Type* aty = fn->getFunctionType()->getParamType(i+1);
+                if (a->getType() != aty) // this param might have type mismatch
+                    a = DtoBitCast(a, aty);
                 ctorargs.push_back(a);
             }
             llvm::CallInst* call = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb());
@@ -2895,7 +2936,7 @@
 AsmStatement::AsmStatement(Loc loc, Token *tokens) :
     Statement(loc)
 {
-    Logger::println("Ignoring AsmStatement");
+    this->tokens = tokens;
 }
 Statement *AsmStatement::syntaxCopy()
 {
--- a/gen/tollvm.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/tollvm.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -673,156 +673,12 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expression* argexp)
-{
-    llvm::Value* retval = 0;
-
-    bool haslvals = !gIR->exps.empty();
-    if (haslvals)
-        gIR->exps.push_back(IRExp(NULL,NULL,NULL));
-
-    DValue* arg = argexp->toElem(gIR);
-
-    if (haslvals)
-        gIR->exps.pop_back();
-
-    if (arg->inPlace()) {
-        retval = arg->getRVal();
-        return retval;
-    }
-
-    Type* realtype = DtoDType(argexp->type);
-    TY argty = realtype->ty;
-    if (DtoIsPassedByRef(realtype)) {
-        if (!fnarg || !fnarg->llvmCopy) {
-            if (DSliceValue* sv = arg->isSlice()) {
-                retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
-                DtoSetArray(retval, DtoArrayLen(sv), DtoArrayPtr(sv));
-            }
-            else if (DComplexValue* cv = arg->isComplex()) {
-                retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
-                DtoComplexSet(retval, cv->re, cv->im);
-            }
-            else {
-                retval = arg->getRVal();
-            }
-        }
-        else {
-            llvm::Value* allocaInst = 0;
-            llvm::BasicBlock* entryblock = &gIR->topfunc()->front();
-
-            const llvm::Type* realtypell = DtoType(realtype);
-            const llvm::PointerType* pty = llvm::PointerType::get(realtypell);
-            if (argty == Tstruct) {
-                allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
-                DValue* dst = new DVarValue(realtype, allocaInst, true);
-                DtoAssign(dst,arg);
-                delete dst;
-            }
-            else if (argty == Tdelegate) {
-                allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
-                DValue* dst = new DVarValue(realtype, allocaInst, true);
-                DtoAssign(dst,arg);
-                delete dst;
-            }
-            else if (argty == Tarray) {
-                if (arg->isSlice()) {
-                    allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint());
-                }
-                else {
-                    allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
-                }
-            }
-            else if (realtype->iscomplex()) {
-                if (arg->isComplex()) {
-                    allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint());
-                }
-                else {
-                    allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
-                }
-            }
-            else
-            assert(0);
-
-            DValue* dst = new DVarValue(realtype, allocaInst, true);
-            DtoAssign(dst,arg);
-            delete dst;
-
-            retval = allocaInst;
-        }
-    }
-    else if (!fnarg || fnarg->llvmCopy) {
-        Logger::println("regular arg");
-        if (DSliceValue* sl = arg->isSlice()) {
-            if (sl->ptr) Logger::cout() << "ptr = " << *sl->ptr << '\n';
-            if (sl->len) Logger::cout() << "len = " << *sl->len << '\n';
-            assert(0);
-        }
-        else if (DComplexValue* cl = arg->isComplex()) {
-            assert(0 && "complex in the wrong place");
-        }
-        else {
-            retval = arg->getRVal();
-        }
-    }
-    else {
-        Logger::println("as ptr arg");
-        retval = arg->getLVal();
-        if (paramtype && retval->getType() != paramtype)
-        {
-            assert(0);
-            /*assert(retval->getType() == paramtype->getContainedType(0));
-            new llvm::StoreInst(retval, arg->getLVal(), gIR->scopebb());
-            retval = arg->getLVal();*/
-        }
-    }
-
-    if (fnarg && paramtype && retval->getType() != paramtype) {
-        // this is unfortunately needed with the way SymOffExp is overused
-        // and static arrays can end up being a pointer to their element type
-        if (arg->isField()) {
-            retval = gIR->ir->CreateBitCast(retval, paramtype, "tmp");
-        }
-        else {
-            Logger::cout() << "got '" << *retval->getType() << "' expected '" << *paramtype << "'\n";
-            assert(0 && "parameter type that was actually passed is invalid");
-        }
-    }
-
-    delete arg;
-
-    return retval;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void print_frame_worker(VarDeclaration* var, Dsymbol* par)
-{
-    if (var->toParent2() == par)
-    {
-        Logger::println("parent found: '%s' kind: '%s'", par->toChars(), par->kind());
-        return;
-    }
-
-    Logger::println("diving into parent: '%s' kind: '%s'", par->toChars(), par->kind());
-    LOG_SCOPE;
-    print_frame_worker(var, par->toParent2());
-}
-
-static void print_nested_frame_list(VarDeclaration* var, Dsymbol* par)
-{
-    Logger::println("PRINTING FRAME LIST FOR NESTED VAR: '%s'", var->toChars());
-    {
-        LOG_SCOPE;
-        print_frame_worker(var, par);
-    }
-    Logger::println("DONE");
-}
-
 static const llvm::Type* get_next_frame_ptr_type(Dsymbol* sc)
 {
     assert(sc->isFuncDeclaration() || sc->isClassDeclaration());
     Dsymbol* p = sc->toParent2();
+    if (!p->isFuncDeclaration() && !p->isClassDeclaration())
+        Logger::println("unexpected parent symbol found while resolving frame pointer - '%s' kind: '%s'", p->toChars(), p->kind());
     assert(p->isFuncDeclaration() || p->isClassDeclaration());
     if (FuncDeclaration* fd = p->isFuncDeclaration())
     {
@@ -841,21 +697,29 @@
     }
 }
 
-static llvm::Value* get_frame_ptr_impl(VarDeclaration* vd, Dsymbol* sc, llvm::Value* v)
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Value* get_frame_ptr_impl(FuncDeclaration* func, Dsymbol* sc, llvm::Value* v)
 {
-    if (vd->toParent2() == sc)
+    LOG_SCOPE;
+    if (sc == func)
     {
         return v;
     }
     else if (FuncDeclaration* fd = sc->isFuncDeclaration())
     {
-        Logger::println("scope is function");
+        Logger::println("scope is function: %s", fd->toChars());
+
+        if (fd->toParent2() == func)
+        {
+            if (!func->llvmNested)
+                return NULL;
+            return DtoBitCast(v, func->llvmNested->getType());
+        }
+
         v = DtoBitCast(v, get_next_frame_ptr_type(fd));
         Logger::cout() << "v = " << *v << '\n';
 
-        if (fd->toParent2() == vd->toParent2())
-            return v;
-
         if (fd->toParent2()->isFuncDeclaration())
         {
             v = DtoGEPi(v, 0,0, "tmp");
@@ -872,33 +736,35 @@
         {
             assert(0);
         }
-        return get_frame_ptr_impl(vd, fd->toParent2(), v);
+        return get_frame_ptr_impl(func, fd->toParent2(), v);
     }
     else if (ClassDeclaration* cd = sc->isClassDeclaration())
     {
-        Logger::println("scope is class");
+        Logger::println("scope is class: %s", cd->toChars());
         /*size_t idx = 2;
         idx += cd->llvmIRStruct->interfaces.size();
         v = DtoGEPi(v,0,idx,"tmp");
         Logger::cout() << "gep = " << *v << '\n';
         v = DtoLoad(v);*/
-        return get_frame_ptr_impl(vd, cd->toParent2(), v);
+        return get_frame_ptr_impl(func, cd->toParent2(), v);
     }
     else
     {
-        Logger::println("symbol: '%s'", sc->toChars());
+        Logger::println("symbol: '%s'", sc->toPrettyChars());
         assert(0);
     }
 }
 
-static llvm::Value* get_frame_ptr(VarDeclaration* vd)
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Value* get_frame_ptr(FuncDeclaration* func)
 {
-    Logger::println("RESOLVING FRAME PTR FOR NESTED VAR: '%s'", vd->toChars());
+    Logger::println("Resolving context pointer for nested function: '%s'", func->toPrettyChars());
     LOG_SCOPE;
     IRFunction* irfunc = gIR->func();
 
-    // in the parent scope already
-    if (vd->toParent2() == irfunc->decl)
+    // in the right scope already
+    if (func == irfunc->decl)
         return irfunc->decl->llvmNested;
 
     // use the 'this' pointer
@@ -906,24 +772,71 @@
     assert(ptr);
 
     // return the fully resolved frame pointer
-    ptr = get_frame_ptr_impl(vd, irfunc->decl, ptr);
-    Logger::cout() << "FOUND: '" << *ptr << "'\n";
+    ptr = get_frame_ptr_impl(func, irfunc->decl, ptr);
+    if (ptr) Logger::cout() << "Found context!" << *ptr;
+    else Logger::cout() << "NULL context!\n";
 
     return ptr;
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoNestedContext(FuncDeclaration* func)
+{
+    // resolve frame ptr
+    llvm::Value* ptr = get_frame_ptr(func);
+    Logger::cout() << "Nested context ptr = ";
+    if (ptr) Logger::cout() << *ptr;
+    else Logger::cout() << "NULL";
+    Logger::cout() << '\n';
+    return ptr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static void print_frame_worker(VarDeclaration* vd, Dsymbol* par)
+{
+    if (vd->toParent2() == par)
+    {
+        Logger::println("found: '%s' kind: '%s'", par->toChars(), par->kind());
+        return;
+    }
+
+    Logger::println("diving into: '%s' kind: '%s'", par->toChars(), par->kind());
+    LOG_SCOPE;
+    print_frame_worker(vd, par->toParent2());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static void print_nested_frame_list(VarDeclaration* vd, Dsymbol* par)
+{
+    Logger::println("Frame pointer list for nested var: '%s'", vd->toPrettyChars());
+    LOG_SCOPE;
+    if (vd->toParent2() != par)
+        print_frame_worker(vd, par);
+    else
+        Logger::println("Found at level 0");
+    Logger::println("Done");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 llvm::Value* DtoNestedVariable(VarDeclaration* vd)
 {
     // log the frame list
     IRFunction* irfunc = gIR->func();
-    print_nested_frame_list(vd, irfunc->decl);
+    if (Logger::enabled)
+        print_nested_frame_list(vd, irfunc->decl);
 
     // resolve frame ptr
-    llvm::Value* ptr = get_frame_ptr(vd);
-    Logger::cout() << "nested ptr = " << *ptr << '\n';
+    FuncDeclaration* func = vd->toParent2()->isFuncDeclaration();
+    assert(func);
+    llvm::Value* ptr = DtoNestedContext(func);
+    assert(ptr && "nested var, but no context");
 
     // we must cast here to be sure. nested classes just have a void*
-    ptr = DtoBitCast(ptr, vd->toParent2()->isFuncDeclaration()->llvmNested->getType());
+    ptr = DtoBitCast(ptr, func->llvmNested->getType());
 
     // index nested var and load (if necessary)
     llvm::Value* v = DtoGEPi(ptr, 0, vd->llvmNestedIndex, "tmp");
@@ -931,7 +844,8 @@
     if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)))
         v = DtoLoad(v);
 
-    Logger::cout() << "FINAL RESULT: " << *v << '\n';
+    // log and return
+    Logger::cout() << "Nested var ptr = " << *v << '\n';
     return v;
 }
 
@@ -940,6 +854,8 @@
 void DtoAssign(DValue* lhs, DValue* rhs)
 {
     Logger::cout() << "DtoAssign(...);\n";
+    LOG_SCOPE;
+
     Type* t = DtoDType(lhs->getType());
     Type* t2 = DtoDType(rhs->getType());
 
@@ -1024,19 +940,15 @@
             DtoComplexAssign(dst, rhs->getRVal());
     }
     else {
-        llvm::Value* l;
-        if (DLRValue* lr = lhs->isLRValue()) {
-            l = lr->getLVal();
-            rhs = DtoCast(rhs, lr->getLType());
-        }
-        else {
-            l = lhs->getLVal();
-        }
+        llvm::Value* l = lhs->getLVal();
         llvm::Value* r = rhs->getRVal();
         Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
         const llvm::Type* lit = l->getType()->getContainedType(0);
-        if (r->getType() != lit) { // :(
-            r = DtoBitCast(r, lit);
+        if (r->getType() != lit) {
+            if (DLRValue* lr = lhs->isLRValue()) // handle lvalue cast assignments
+                r = DtoCast(rhs, lr->getLType())->getRVal();
+            else
+                r = DtoCast(rhs, lhs->getType())->getRVal();
             Logger::cout() << "really assign\nlhs: " << *l << "rhs: " << *r << '\n';
         }
         gIR->ir->CreateStore(r, l);
@@ -1055,34 +967,38 @@
     size_t fromsz = from->size();
     size_t tosz = to->size();
 
-    llvm::Value* rval;
+    llvm::Value* rval = val->getRVal();
+    if (rval->getType() == tolltype) {
+        return new DImValue(_to, rval);
+    }
 
     if (to->isintegral()) {
         if (fromsz < tosz) {
             Logger::cout() << "cast to: " << *tolltype << '\n';
             if (from->isunsigned() || from->ty == Tbool) {
-                rval = new llvm::ZExtInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+                rval = new llvm::ZExtInst(rval, tolltype, "tmp", gIR->scopebb());
             } else {
-                rval = new llvm::SExtInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+                rval = new llvm::SExtInst(rval, tolltype, "tmp", gIR->scopebb());
             }
         }
         else if (fromsz > tosz) {
-            rval = new llvm::TruncInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+            rval = new llvm::TruncInst(rval, tolltype, "tmp", gIR->scopebb());
         }
         else {
-            rval = new llvm::BitCastInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+            rval = new llvm::BitCastInst(rval, tolltype, "tmp", gIR->scopebb());
         }
     }
     else if (to->isfloating()) {
         if (from->isunsigned()) {
-            rval = new llvm::UIToFPInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+            rval = new llvm::UIToFPInst(rval, tolltype, "tmp", gIR->scopebb());
         }
         else {
-            rval = new llvm::SIToFPInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
+            rval = new llvm::SIToFPInst(rval, tolltype, "tmp", gIR->scopebb());
         }
     }
     else if (to->ty == Tpointer) {
-        rval = gIR->ir->CreateIntToPtr(val->getRVal(), tolltype, "tmp");
+        Logger::cout() << "cast pointer: " << *tolltype << '\n';
+        rval = gIR->ir->CreateIntToPtr(rval, tolltype, "tmp");
     }
     else {
         assert(0 && "bad int cast");
@@ -1771,3 +1687,20 @@
 
     DtoDefineDsymbol(dsym);
 }
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoAnnotation(const char* str)
+{
+    std::string s("CODE: ");
+    s.append(str);
+    char* p = &s[0];
+    while (*p)
+    {
+        if (*p == '"')
+            *p = '\'';
+        ++p;
+    }
+    // create a noop with the code as the result name!
+    gIR->ir->CreateAnd(DtoConstSize_t(0),DtoConstSize_t(0),s.c_str());
+}
--- a/gen/tollvm.h	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/tollvm.h	Fri Jan 04 01:38:42 2008 +0100
@@ -41,9 +41,10 @@
 
 void DtoAssert(llvm::Value* cond, Loc* loc, DValue* msg);
 
-llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expression* argexp);
+llvm::Value* DtoNestedContext(FuncDeclaration* func);
+llvm::Value* DtoNestedVariable(VarDeclaration* vd);
 
-llvm::Value* DtoNestedVariable(VarDeclaration* vd);
+void DtoAnnotation(const char* str);
 
 llvm::ConstantInt* DtoConstSize_t(size_t);
 llvm::ConstantInt* DtoConstUint(unsigned i);
--- a/gen/toobj.cpp	Fri Dec 28 23:52:40 2007 +0100
+++ b/gen/toobj.cpp	Fri Jan 04 01:38:42 2008 +0100
@@ -137,9 +137,7 @@
     }
 
     // run optimizer
-    if (global.params.optimize) {
-        llvmdc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline);
-    }
+    llvmdc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline);
 
     // write bytecode
     {
--- a/llvmdc.kdevelop	Fri Dec 28 23:52:40 2007 +0100
+++ b/llvmdc.kdevelop	Fri Jan 04 01:38:42 2008 +0100
@@ -85,6 +85,7 @@
     </ignoredoxygen>
   </kdevdoctreeview>
   <kdevfilecreate>
+    <filetypes/>
     <useglobaltypes>
       <type ext="cpp" />
       <type ext="h" />
@@ -191,6 +192,10 @@
       <filetype>*.c</filetype>
       <filetype>*.cpp</filetype>
       <filetype>*.d</filetype>
+      <filetype>*.di</filetype>
+      <filetype>build.sh</filetype>
+      <filetype>premake.lua</filetype>
+      <filetype>Doxyfile</filetype>
     </filetypes>
     <blacklist>
       <path>dbgtypes.bc.cpp</path>
--- a/llvmdc.kdevelop.filelist	Fri Dec 28 23:52:40 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Fri Jan 04 01:38:42 2008 +0100
@@ -1,4 +1,5 @@
 # KDevelop Custom Project File List
+Doxyfile
 demos
 demos/gl.d
 demos/glfuncs.d
@@ -11,6 +12,7 @@
 demos/sdl.d
 demos/sdldemo1.d
 dmd
+dmd/Doxyfile
 dmd/access.c
 dmd/aggregate.h
 dmd/array.c
@@ -137,6 +139,7 @@
 gen/typeinf.h
 gen/typinf.cpp
 lphobos
+lphobos/build.sh
 lphobos/crc32.d
 lphobos/gc
 lphobos/gc/gcbits.d
@@ -185,6 +188,7 @@
 lphobos/std/conv.d
 lphobos/std/ctype.d
 lphobos/std/format.d
+lphobos/std/gc.di
 lphobos/std/intrinsic.d
 lphobos/std/math.d
 lphobos/std/moduleinit.d
@@ -193,6 +197,7 @@
 lphobos/std/stdint.d
 lphobos/std/stdio.d
 lphobos/std/string.d
+lphobos/std/thread.d
 lphobos/std/traits.d
 lphobos/std/uni.d
 lphobos/std/utf.d
@@ -232,6 +237,7 @@
 lphobos/typeinfo2/ti_C.d
 lphobos/typeinfos1.d
 lphobos/typeinfos2.d
+premake.lua
 runalltests.d
 test
 test/a.d
@@ -258,8 +264,8 @@
 test/arrays7.d
 test/arrays8.d
 test/arrays9.d
+test/asm1.d
 test/assign.d
-test/ast1.d
 test/b.d
 test/bitops.d
 test/bug1.d
@@ -332,9 +338,12 @@
 test/bug76.d
 test/bug77.d
 test/bug78.d
+test/bug79.d
 test/bug8.d
+test/bug80.d
 test/bug9.d
 test/c.d
+test/calls1.d
 test/classes.d
 test/classes10.d
 test/classes11.d
@@ -409,6 +418,8 @@
 test/neg.d
 test/nested1.d
 test/nested10.d
+test/nested11.d
+test/nested12.d
 test/nested2.d
 test/nested3.d
 test/nested4.d
@@ -432,6 +443,7 @@
 test/staticarrays.d
 test/staticvars.d
 test/stdiotest.d
+test/stdiotest2.d
 test/strings1.d
 test/strings2.d
 test/structinit.d
@@ -479,6 +491,7 @@
 test/vararg2.d
 test/vararg3.d
 test/vararg4.d
+test/vararg5.d
 test/virtcall.d
 test/with1.d
 tester.d
--- a/lphobos/build.sh	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/build.sh	Fri Jan 04 01:38:42 2008 +0100
@@ -5,8 +5,8 @@
 rm -f obj/*.bc
 rm -f ../lib/*.bc
 
-LLVMDCFLAGS="-c -odobj"
-REBUILDFLAGS="-dc=llvmdc-posix-internal -c -oqobj"
+LLVMDCFLAGS="-c -odobj -g"
+REBUILDFLAGS="-dc=llvmdc-posix-internal -c -oqobj -g"
 
 echo "compiling contract runtime"
 llvmdc internal/contract.d -c -of../lib/llvmdcore.bc -noruntime || exit 1
@@ -56,12 +56,14 @@
 
 echo "compiling garbage collector"
 llvmdc gc/gclinux.d $LLVMDCFLAGS || exit 1
-llvmdc gc/gcstub.d $LLVMDCFLAGS -Igc || exit 1
+llvmdc gc/gcx.d $LLVMDCFLAGS -Igc || exit 1
 llvmdc gc/gcbits.d $LLVMDCFLAGS -Igc || exit 1
-llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcstub.bc obj/gcbits.bc ../lib/llvmdcore.bc || exit 1
+llvmdc gc/gc.d $LLVMDCFLAGS -Igc || exit 1
+llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcx.bc obj/gcbits.bc obj/gc.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling phobos"
 rebuild phobos.d $REBUILDFLAGS || exit 1
+echo "linking phobos"
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/std.*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "optimizing"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gc/gc.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,151 @@
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+// Storage allocation
+
+module std.gc;
+
+//debug = PRINTF;
+
+public import std.c.stdarg;
+public import std.c.stdlib;
+public import std.c.string;
+public import gcx;
+public import std.outofmemory;
+public import gcstats;
+public import std.thread;
+
+version=GCCLASS;
+
+version (GCCLASS)
+    alias GC gc_t;
+else
+    alias GC* gc_t;
+
+gc_t _gc;
+
+void addRoot(void *p)		      { _gc.addRoot(p); }
+void removeRoot(void *p)	      { _gc.removeRoot(p); }
+void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
+void removeRange(void *pbot)	      { _gc.removeRange(pbot); }
+void fullCollect()		      { _gc.fullCollect(); }
+void fullCollectNoStack()	      { _gc.fullCollectNoStack(); }
+void genCollect()		      { _gc.genCollect(); }
+void minimize()			      { _gc.minimize(); }
+void disable()			      { _gc.disable(); }
+void enable()			      { _gc.enable(); }
+void getStats(out GCStats stats)      { _gc.getStats(stats); }
+void hasPointers(void* p)	      { _gc.hasPointers(p); }
+void hasNoPointers(void* p)	      { _gc.hasNoPointers(p); }
+void setV1_0()			      { _gc.setV1_0(); }
+
+void[] malloc(size_t nbytes)
+{
+    void* p = _gc.malloc(nbytes);
+    return p[0 .. nbytes];
+}
+
+void[] realloc(void* p, size_t nbytes)
+{
+    void* q = _gc.realloc(p, nbytes);
+    return q[0 .. nbytes];
+}
+
+size_t extend(void* p, size_t minbytes, size_t maxbytes)
+{
+    return _gc.extend(p, minbytes, maxbytes);
+}
+
+size_t capacity(void* p)
+{
+    return _gc.capacity(p);
+}
+
+void setTypeInfo(TypeInfo ti, void* p)
+{
+    if (ti.flags() & 1)
+	hasNoPointers(p);
+    else
+	hasPointers(p);
+}
+
+void* getGCHandle()
+{
+    return cast(void*)_gc;
+}
+
+void setGCHandle(void* p)
+{
+    void* oldp = getGCHandle();
+    gc_t g = cast(gc_t)p;
+    if (g.gcversion != gcx.GCVERSION)
+	throw new Error("incompatible gc versions");
+
+    // Add our static data to the new gc
+    GC.scanStaticData(g);
+
+    _gc = g;
+//    return oldp;
+}
+
+void endGCHandle()
+{
+    GC.unscanStaticData(_gc);
+}
+
+extern (C)
+{
+
+void _d_monitorrelease(Object h);
+
+
+void gc_init()
+{
+    version (GCCLASS)
+    {	void* p;
+	ClassInfo ci = GC.classinfo;
+
+	p = std.c.stdlib.malloc(ci.init.length);
+	(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+	_gc = cast(GC)p;
+    }
+    else
+    {
+	_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
+    }
+    _gc.initialize();
+    GC.scanStaticData(_gc);
+    std.thread.Thread.thread_init();
+}
+
+void gc_term()
+{
+    _gc.fullCollectNoStack();
+    _gc.Dtor();
+}
+
+}
--- a/lphobos/gc/gcstub.d	Fri Dec 28 23:52:40 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
- *  Copyright (C) 2004 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
- *
- *  This software is provided 'as-is', without any express or implied
- *  warranty. In no event will the authors be held liable for any damages
- *  arising from the use of this software.
- *
- *  Permission is granted to anyone to use this software for any purpose,
- *  including commercial applications, and to alter it and redistribute it
- *  freely, subject to the following restrictions:
- *
- *  o  The origin of this software must not be misrepresented; you must not
- *     claim that you wrote the original software. If you use this software
- *     in a product, an acknowledgment in the product documentation would be
- *     appreciated but is not required.
- *  o  Altered source versions must be plainly marked as such, and must not
- *     be misrepresented as being the original software.
- *  o  This notice may not be removed or altered from any source
- *     distribution.
- */
-
-// D Garbage Collector stub to prevent linking in gc
-
-module gcx;
-
-//debug=PRINTF;
-
-/***************************************************/
-
-import object;
-
-version (Win32)
-{
-    import win32;
-}
-
-version (linux)
-{
-    import gclinux;
-}
-
-
-//alias GC* gc_t;
-alias GC gc_t;
-
-struct GCStats { }
-
-/* ============================ GC =============================== */
-
-
-//alias int size_t;
-alias void (*GC_FINALIZER)(void *p, void *dummy);
-
-const uint GCVERSION = 1;	// increment every time we change interface
-				// to GC.
-
-class GC
-{
-    uint gcversion = GCVERSION;
-
-    void *gcx;			// implementation
-
-    void initialize()
-    {
-	debug(PRINTF) printf("initialize()\n");
-    }
-
-
-    void Dtor()
-    {
-	debug(PRINTF) printf("Dtor()\n");
-    }
-
-    /+invariant
-    {
-	debug(PRINTF) printf("invariant()\n");
-    }+/
-
-    void *malloc(size_t size)
-    {
-	debug(PRINTF) printf("malloc()\n");
-	return null;
-    }
-
-    void *mallocNoSync(size_t size)
-    {
-	debug(PRINTF) printf("mallocNoSync()\n");
-	return null;
-    }
-
-
-    void *calloc(size_t size, size_t n)
-    {
-	debug(PRINTF) printf("calloc()\n");
-	return null;
-    }
-
-
-    void *realloc(void *p, size_t size)
-    {
-	debug(PRINTF) printf("realloc()\n");
-	return null;
-    }
-
-
-    void free(void *p)
-    {
-	debug(PRINTF) printf("free()\n");
-    }
-
-    size_t capacity(void *p)
-    {
-	debug(PRINTF) printf("capacity()\n");
-	return 0;
-    }
-
-    void check(void *p)
-    {
-	debug(PRINTF) printf("check()\n");
-    }
-
-
-    void setStackBottom(void *p)
-    {
-	debug(PRINTF) printf("setStackBottom()\n");
-    }
-
-    static void scanStaticData(gc_t g)
-    {
-	void *pbot;
-	void *ptop;
-	uint nbytes;
-
-	debug(PRINTF) printf("scanStaticData()\n");
-	//debug(PRINTF) printf("+GC.scanStaticData()\n");
-	os_query_staticdataseg(&pbot, &nbytes);
-	ptop = pbot + nbytes;
-	g.addRange(pbot, ptop);
-	//debug(PRINTF) printf("-GC.scanStaticData()\n");
-    }
-
-    static void unscanStaticData(gc_t g)
-    {
-	void *pbot;
-	uint nbytes;
-
-	debug(PRINTF) printf("unscanStaticData()\n");
-	os_query_staticdataseg(&pbot, &nbytes);
-	g.removeRange(pbot);
-    }
-
-
-    void addRoot(void *p)	// add p to list of roots
-    {
-	debug(PRINTF) printf("addRoot()\n");
-    }
-
-    void removeRoot(void *p)	// remove p from list of roots
-    {
-	debug(PRINTF) printf("removeRoot()\n");
-    }
-
-    void addRange(void *pbot, void *ptop)	// add range to scan for roots
-    {
-	debug(PRINTF) printf("addRange()\n");
-    }
-
-    void removeRange(void *pbot)		// remove range
-    {
-	debug(PRINTF) printf("removeRange()\n");
-    }
-
-    void fullCollect()		// do full garbage collection
-    {
-	debug(PRINTF) printf("fullCollect()\n");
-    }
-
-    void fullCollectNoStack()		// do full garbage collection
-    {
-	debug(PRINTF) printf("fullCollectNoStack()\n");
-    }
-
-    void genCollect()	// do generational garbage collection
-    {
-	debug(PRINTF) printf("genCollect()\n");
-    }
-
-    void minimize()	// minimize physical memory usage
-    {
-	debug(PRINTF) printf("minimize()\n");
-    }
-
-    void setFinalizer(void *p, GC_FINALIZER pFn)
-    {
-	debug(PRINTF) printf("setFinalizer()\n");
-    }
-
-    void enable()
-    {
-	debug(PRINTF) printf("enable()\n");
-    }
-
-    void disable()
-    {
-	debug(PRINTF) printf("disable()\n");
-    }
-
-    void getStats(out GCStats stats)
-    {
-	debug(PRINTF) printf("getStats()\n");
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gc/gcx.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (C) 2004 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+// D Garbage Collector stub to prevent linking in gc
+
+/*
+ * Modified for use as the preliminary GC for LLVMDC (LLVM D Compiler)
+ * by Tomas Lindquist Olsen, Dec 2007
+ */
+
+module gcx;
+
+debug=PRINTF;
+
+/***************************************************/
+
+
+version (Win32)
+{
+    import win32;
+}
+
+version (linux)
+{
+    import gclinux;
+}
+
+import gcstats;
+import stdc = std.c.stdlib;
+
+
+//alias GC* gc_t;
+alias GC gc_t;
+
+//struct GCStats { }
+
+/* ============================ GC =============================== */
+
+
+//alias int size_t;
+alias void (*GC_FINALIZER)(void *p, bool dummy);
+
+const uint GCVERSION = 1;   // increment every time we change interface
+                // to GC.
+
+class GC
+{
+    uint gcversion = GCVERSION;
+
+    void *gcx;          // implementation
+
+    void initialize()
+    {
+    debug(PRINTF) printf("GC initialize()\n");
+    }
+
+
+    void Dtor()
+    {
+    debug(PRINTF) printf("GC Dtor()\n");
+    }
+
+    invariant
+    {
+    debug(PRINTF) printf("GC invariant()\n");
+    }
+
+    void *malloc(size_t size)
+    {
+    debug(PRINTF) printf("GC malloc()\n");
+    return malloc(size);
+    }
+
+    void *mallocNoSync(size_t size)
+    {
+    debug(PRINTF) printf("GC mallocNoSync()\n");
+    return malloc(size);
+    }
+
+
+    void *calloc(size_t size, size_t n)
+    {
+    debug(PRINTF) printf("GC calloc()\n");
+    return calloc(n, size);
+    }
+
+
+    void *realloc(void *p, size_t size)
+    {
+    debug(PRINTF) printf("GC realloc()\n");
+    return realloc(p, size);
+    }
+
+
+    void free(void *p)
+    {
+    debug(PRINTF) printf("GC free()\n");
+    stdc.free(p);
+    }
+
+    size_t capacity(void *p)
+    {
+    debug(PRINTF) printf("GC capacity()\n");
+    return 0;
+    }
+
+    void check(void *p)
+    {
+    debug(PRINTF) printf("GC check()\n");
+    }
+
+
+    void setStackBottom(void *p)
+    {
+    debug(PRINTF) printf("GC setStackBottom()\n");
+    }
+
+    static void scanStaticData(gc_t g)
+    {
+    void *pbot;
+    void *ptop;
+    uint nbytes;
+
+    debug(PRINTF) printf("GC scanStaticData()\n");
+    //debug(PRINTF) printf("+GC.scanStaticData()\n");
+    os_query_staticdataseg(&pbot, &nbytes);
+    ptop = pbot + nbytes;
+    g.addRange(pbot, ptop);
+    //debug(PRINTF) printf("-GC.scanStaticData()\n");
+    }
+
+    static void unscanStaticData(gc_t g)
+    {
+    void *pbot;
+    uint nbytes;
+
+    debug(PRINTF) printf("GC unscanStaticData()\n");
+    os_query_staticdataseg(&pbot, &nbytes);
+    g.removeRange(pbot);
+    }
+
+
+    void addRoot(void *p)   // add p to list of roots
+    {
+    debug(PRINTF) printf("GC addRoot()\n");
+    }
+
+    void removeRoot(void *p)    // remove p from list of roots
+    {
+    debug(PRINTF) printf("GC removeRoot()\n");
+    }
+
+    void addRange(void *pbot, void *ptop)   // add range to scan for roots
+    {
+    debug(PRINTF) printf("GC addRange()\n");
+    }
+
+    void removeRange(void *pbot)        // remove range
+    {
+    debug(PRINTF) printf("GC removeRange()\n");
+    }
+
+    void fullCollect()      // do full garbage collection
+    {
+    debug(PRINTF) printf("GC fullCollect()\n");
+    }
+
+    void fullCollectNoStack()       // do full garbage collection
+    {
+    debug(PRINTF) printf("GC fullCollectNoStack()\n");
+    }
+
+    void genCollect()   // do generational garbage collection
+    {
+    debug(PRINTF) printf("GC genCollect()\n");
+    }
+
+    void minimize() // minimize physical memory usage
+    {
+    debug(PRINTF) printf("GC minimize()\n");
+    }
+
+    void setFinalizer(void *p, GC_FINALIZER pFn)
+    {
+    debug(PRINTF) printf("GC setFinalizer()\n");
+    }
+
+    void enable()
+    {
+    debug(PRINTF) printf("GC enable()\n");
+    }
+
+    void disable()
+    {
+    debug(PRINTF) printf("GC disable()\n");
+    }
+
+    void getStats(out GCStats stats)
+    {
+    debug(PRINTF) printf("GC getStats()\n");
+    }
+
+    void hasPointers(void* p)
+    {
+    debug(PRINTF) printf("GC hasPointers()\n");
+    }
+
+    void hasNoPointers(void* p)
+    {
+    debug(PRINTF) printf("GC hasNoPointers()\n");
+    }
+
+    void setV1_0()
+    {
+    debug(PRINTF) printf("GC setV1_0()\n");
+    assert(0);
+    }
+
+    size_t extend(void* p, size_t minsize, size_t maxsize)
+    {
+    debug(PRINTF) printf("GC extend()\n");
+    assert(0);
+    }
+}
--- a/lphobos/llvm/intrinsic.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/llvm/intrinsic.d	Fri Jan 04 01:38:42 2008 +0100
@@ -4,10 +4,10 @@
 /*
 pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
     void* llvm_returnaddress(uint level);
-
+*/
 pragma(LLVM_internal, "intrinsic", "llvm.frameaddress")
     void* llvm_frameaddress(uint level);
-
+/*
 pragma(LLVM_internal, "intrinsic", "llvm.stacksave")
     void* llvm_stacksave();
 
--- a/lphobos/phobos.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/phobos.d	Fri Jan 04 01:38:42 2008 +0100
@@ -13,6 +13,7 @@
 std.stdint,
 std.stdio,
 std.string,
+std.thread,
 std.traits,
 std.uni,
 std.utf,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/conv.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,1578 @@
+
+// Written in the D programming language.
+
+/*
+ *  Copyright (C) 2002-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *  Some parts contributed by David L. Davis
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/***********
+ * Conversion building blocks. These differ from the C equivalents
+ * <tt>atoi()</tt> and <tt>atol()</tt> by
+ * checking for overflow and not allowing whitespace.
+ *
+ * For conversion to signed types, the grammar recognized is:
+ * <pre>
+$(I Integer):
+    $(I Sign UnsignedInteger)
+    $(I UnsignedInteger)
+
+$(I Sign):
+    $(B +)
+    $(B -)
+ * </pre>
+ * For conversion to signed types, the grammar recognized is:
+ * <pre>
+$(I UnsignedInteger):
+    $(I DecimalDigit)
+    $(I DecimalDigit) $(I UnsignedInteger)
+ * </pre>
+ * Macros:
+ *	WIKI=Phobos/StdConv
+ */
+
+module std.conv;
+
+private import std.string;  // for atof(), toString()
+private import std.c.stdlib;
+private import std.math;  // for fabs(), isnan()
+private import std.stdio; // for writefln() and printf()
+
+
+//debug=conv;		// uncomment to turn on debugging printf's
+
+/* ************* Exceptions *************** */
+
+/**
+ * Thrown on conversion errors, which happens on deviation from the grammar.
+ */
+class ConvError : Error
+{
+    this(char[] s)
+    {
+	super("conversion " ~ s);
+    }
+}
+
+private void conv_error(char[] s)
+{
+    throw new ConvError(s);
+}
+
+/**
+ * Thrown on conversion overflow errors.
+ */
+class ConvOverflowError : Error
+{
+    this(char[] s)
+    {
+	super("Error: overflow " ~ s);
+    }
+}
+
+private void conv_overflow(char[] s)
+{
+    throw new ConvOverflowError(s);
+}
+
+/***************************************************************
+ * Convert character string to the return type.
+ */
+
+int toInt(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    int sign = 0;
+    int v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < int.max/10 || (v == int.max/10 && c + sign <= '7'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else if (c == '-' && i == 0)
+	{
+	    sign = -1;
+	    if (length == 1)
+		goto Lerr;
+	}
+	else if (c == '+' && i == 0)
+	{
+	    if (length == 1)
+		goto Lerr;
+	}
+	else
+	    goto Lerr;
+    }
+    if (sign == -1)
+    {
+	if (cast(uint)v > 0x80000000)
+	    goto Loverflow;
+	v = -v;
+    }
+    else
+    {
+	if (cast(uint)v > 0x7FFFFFFF)
+	    goto Loverflow;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toInt.unittest\n");
+
+    int i;
+
+    i = toInt("0");
+    assert(i == 0);
+
+    i = toInt("+0");
+    assert(i == 0);
+
+    i = toInt("-0");
+    assert(i == 0);
+
+    i = toInt("6");
+    assert(i == 6);
+
+    i = toInt("+23");
+    assert(i == 23);
+
+    i = toInt("-468");
+    assert(i == -468);
+
+    i = toInt("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toInt("-2147483648");
+    assert(i == 0x80000000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"2147483648",
+	"-2147483649",
+	"5656566565",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toInt(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+uint toUint(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    uint v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < uint.max/10 || (v == uint.max/10 && c <= '5'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else
+	    goto Lerr;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUint.unittest\n");
+
+    uint i;
+
+    i = toUint("0");
+    assert(i == 0);
+
+    i = toUint("6");
+    assert(i == 6);
+
+    i = toUint("23");
+    assert(i == 23);
+
+    i = toUint("468");
+    assert(i == 468);
+
+    i = toUint("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toUint("4294967295");
+    assert(i == 0xFFFFFFFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"4294967296",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUint(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+/*******************************************************
+ * ditto
+ */
+
+long toLong(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    int sign = 0;
+    long v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < long.max/10 || (v == long.max/10 && c + sign <= '7'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else if (c == '-' && i == 0)
+	{
+	    sign = -1;
+	    if (length == 1)
+		goto Lerr;
+	}
+	else if (c == '+' && i == 0)
+	{
+	    if (length == 1)
+		goto Lerr;
+	}
+	else
+	    goto Lerr;
+    }
+    if (sign == -1)
+    {
+	if (cast(ulong)v > 0x8000000000000000)
+	    goto Loverflow;
+	v = -v;
+    }
+    else
+    {
+	if (cast(ulong)v > 0x7FFFFFFFFFFFFFFF)
+	    goto Loverflow;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toLong.unittest\n");
+
+    long i;
+
+    i = toLong("0");
+    assert(i == 0);
+
+    i = toLong("+0");
+    assert(i == 0);
+
+    i = toLong("-0");
+    assert(i == 0);
+
+    i = toLong("6");
+    assert(i == 6);
+
+    i = toLong("+23");
+    assert(i == 23);
+
+    i = toLong("-468");
+    assert(i == -468);
+
+    i = toLong("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toLong("-2147483648");
+    assert(i == -0x80000000L);
+
+    i = toLong("9223372036854775807");
+    assert(i == 0x7FFFFFFFFFFFFFFF);
+
+    i = toLong("-9223372036854775808");
+    assert(i == 0x8000000000000000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"9223372036854775808",
+	"-9223372036854775809",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toLong(errors[j]);
+	    printf("l = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ulong toUlong(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    ulong v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < ulong.max/10 || (v == ulong.max/10 && c <= '5'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else
+	    goto Lerr;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUlong.unittest\n");
+
+    ulong i;
+
+    i = toUlong("0");
+    assert(i == 0);
+
+    i = toUlong("6");
+    assert(i == 6);
+
+    i = toUlong("23");
+    assert(i == 23);
+
+    i = toUlong("468");
+    assert(i == 468);
+
+    i = toUlong("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toUlong("4294967295");
+    assert(i == 0xFFFFFFFF);
+
+    i = toUlong("9223372036854775807");
+    assert(i == 0x7FFFFFFFFFFFFFFF);
+
+    i = toUlong("18446744073709551615");
+    assert(i == 0xFFFFFFFFFFFFFFFF);
+
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"18446744073709551616",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUlong(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+short toShort(char[] s)
+{
+    int v = toInt(s);
+
+    if (v != cast(short)v)
+	goto Loverflow;
+
+    return cast(short)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toShort.unittest\n");
+
+    short i;
+
+    i = toShort("0");
+    assert(i == 0);
+
+    i = toShort("+0");
+    assert(i == 0);
+
+    i = toShort("-0");
+    assert(i == 0);
+
+    i = toShort("6");
+    assert(i == 6);
+
+    i = toShort("+23");
+    assert(i == 23);
+
+    i = toShort("-468");
+    assert(i == -468);
+
+    i = toShort("32767");
+    assert(i == 0x7FFF);
+
+    i = toShort("-32768");
+    assert(i == cast(short)0x8000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"32768",
+	"-32769",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toShort(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ushort toUshort(char[] s)
+{
+    uint v = toUint(s);
+
+    if (v != cast(ushort)v)
+	goto Loverflow;
+
+    return cast(ushort)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUshort.unittest\n");
+
+    ushort i;
+
+    i = toUshort("0");
+    assert(i == 0);
+
+    i = toUshort("6");
+    assert(i == 6);
+
+    i = toUshort("23");
+    assert(i == 23);
+
+    i = toUshort("468");
+    assert(i == 468);
+
+    i = toUshort("32767");
+    assert(i == 0x7FFF);
+
+    i = toUshort("65535");
+    assert(i == 0xFFFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"65536",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUshort(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+byte toByte(char[] s)
+{
+    int v = toInt(s);
+
+    if (v != cast(byte)v)
+	goto Loverflow;
+
+    return cast(byte)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toByte.unittest\n");
+
+    byte i;
+
+    i = toByte("0");
+    assert(i == 0);
+
+    i = toByte("+0");
+    assert(i == 0);
+
+    i = toByte("-0");
+    assert(i == 0);
+
+    i = toByte("6");
+    assert(i == 6);
+
+    i = toByte("+23");
+    assert(i == 23);
+
+    i = toByte("-68");
+    assert(i == -68);
+
+    i = toByte("127");
+    assert(i == 0x7F);
+
+    i = toByte("-128");
+    assert(i == cast(byte)0x80);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"128",
+	"-129",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toByte(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ubyte toUbyte(char[] s)
+{
+    uint v = toUint(s);
+
+    if (v != cast(ubyte)v)
+	goto Loverflow;
+
+    return cast(ubyte)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUbyte.unittest\n");
+
+    ubyte i;
+
+    i = toUbyte("0");
+    assert(i == 0);
+
+    i = toUbyte("6");
+    assert(i == 6);
+
+    i = toUbyte("23");
+    assert(i == 23);
+
+    i = toUbyte("68");
+    assert(i == 68);
+
+    i = toUbyte("127");
+    assert(i == 0x7F);
+
+    i = toUbyte("255");
+    assert(i == 0xFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"256",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUbyte(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+float toFloat(in char[] s)
+{
+    float f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toFloat('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtof(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a float");
+    assert(0);
+}
+ 
+unittest
+{
+    debug( conv ) writefln( "conv.toFloat.unittest" );
+    float f;
+    
+    f = toFloat( "123" );
+    assert( f == 123f );
+    f = toFloat( "+123" );
+    assert( f == +123f );
+    f = toFloat( "-123" );
+    assert( f == -123f );
+    f = toFloat( "123e+2" );
+    assert( f == 123e+2f );
+
+    f = toFloat( "123e-2" );
+    assert( f == 123e-2f );
+    f = toFloat( "123." );
+    assert( f == 123.f );
+    f = toFloat( ".456" );
+    assert( f == .456f );
+    
+    // min and max
+    f = toFloat("1.17549e-38");
+    assert(feq(cast(real)f, cast(real)1.17549e-38));
+    assert(feq(cast(real)f, cast(real)float.min));
+    f = toFloat("3.40282e+38");
+    assert(toString(f) == toString(3.40282e+38));
+
+    // nan
+    f = toFloat("nan");
+    assert(toString(f) == toString(float.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+double toDouble(in char[] s)
+{
+    double f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toDouble('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtod(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a double");
+    assert(0);
+}
+
+unittest
+{
+    debug( conv ) writefln( "conv.toDouble.unittest" );
+    double d;
+
+    d = toDouble( "123" );
+    assert( d == 123 );
+    d = toDouble( "+123" );
+    assert( d == +123 );
+    d = toDouble( "-123" );
+    assert( d == -123 );
+    d = toDouble( "123e2" );
+    assert( d == 123e2);
+    d = toDouble( "123e-2" );
+    assert( d == 123e-2 );
+    d = toDouble( "123." );
+    assert( d == 123. );
+    d = toDouble( ".456" );
+    assert( d == .456 );
+    d = toDouble( "1.23456E+2" );
+    assert( d == 1.23456E+2 );
+
+    // min and max
+    d = toDouble("2.22507e-308");
+    assert(feq(cast(real)d, cast(real)2.22507e-308));
+    assert(feq(cast(real)d, cast(real)double.min));
+    d = toDouble("1.79769e+308");
+    assert(toString(d) == toString(1.79769e+308));
+    assert(toString(d) == toString(double.max));
+
+    // nan
+    d = toDouble("nan");
+    assert(toString(d) == toString(double.nan));
+    //assert(cast(real)d == cast(real)double.nan);
+}
+
+/*******************************************************
+ * ditto
+ */
+real toReal(in char[] s)
+{
+    real f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toReal('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtold(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a real");
+    assert(0);
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toReal.unittest");
+    real r;
+
+    r = toReal("123");
+    assert(r == 123L);
+    r = toReal("+123");
+    assert(r == 123L);
+    r = toReal("-123");
+    assert(r == -123L);
+    r = toReal("123e2");
+    assert(feq(r, 123e2L));
+    r = toReal("123e-2");
+    assert(feq(r, 1.23L));
+    r = toReal("123.");
+    assert(r == 123L);
+    r = toReal(".456");
+    assert(r == .456L);
+
+    r = toReal("1.23456e+2");
+    assert(feq(r,  1.23456e+2L));
+    r = toReal(toString(real.max / 2L));
+    assert(toString(r) == toString(real.max / 2L));
+
+    // min and max
+    r = toReal(toString(real.min));
+    assert(toString(r) == toString(real.min));
+    r = toReal(toString(real.max));
+    assert(toString(r) == toString(real.max));
+
+    // nan
+    r = toReal("nan");
+    assert(toString(r) == toString(real.nan));
+    //assert(r == real.nan);
+
+    r = toReal(toString(real.nan));
+    assert(toString(r) == toString(real.nan));
+    //assert(r == real.nan);
+}
+
+version (none)
+{   /* These are removed for the moment because of concern about
+     * what to do about the 'i' suffix. Should it be there?
+     * Should it not? What about 'nan', should it be 'nani'?
+     * 'infinity' or 'infinityi'?
+     * Should it match what toString(ifloat) does with the 'i' suffix?
+     */
+
+/*******************************************************
+ * ditto
+ */
+
+ifloat toIfloat(in char[] s)
+{
+    return toFloat(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIfloat.unittest");
+    ifloat ift;
+    
+    ift = toIfloat(toString(123.45));
+    assert(toString(ift) == toString(123.45i));
+
+    ift = toIfloat(toString(456.77i));
+    assert(toString(ift) == toString(456.77i));
+
+    // min and max
+    ift = toIfloat(toString(ifloat.min));
+    assert(toString(ift) == toString(ifloat.min) );
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.min));
+
+    ift = toIfloat(toString(ifloat.max));
+    assert(toString(ift) == toString(ifloat.max));
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.max));
+   
+    // nan
+    ift = toIfloat("nani");
+    assert(cast(real)ift == cast(real)ifloat.nan);
+
+    ift = toIfloat(toString(ifloat.nan));
+    assert(toString(ift) == toString(ifloat.nan));
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+idouble toIdouble(in char[] s)
+{
+    return toDouble(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIdouble.unittest");
+    idouble id;
+
+    id = toIdouble(toString("123.45"));
+    assert(id == 123.45i);
+
+    id = toIdouble(toString("123.45e+302i"));
+    assert(id == 123.45e+302i);
+
+    // min and max
+    id = toIdouble(toString(idouble.min));
+    assert(toString( id ) == toString(idouble.min));
+    assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re));
+    assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im));
+    
+    id = toIdouble(toString(idouble.max));
+    assert(toString(id) == toString(idouble.max));
+    assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re));
+    assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im));
+    
+    // nan
+    id = toIdouble("nani");
+    assert(cast(real)id == cast(real)idouble.nan);
+
+    id = toIdouble(toString(idouble.nan));
+    assert(toString(id) == toString(idouble.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+ireal toIreal(in char[] s)
+{
+    return toReal(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIreal.unittest");
+    ireal ir;
+
+    ir = toIreal(toString("123.45"));
+    assert(feq(cast(real)ir.re, cast(real)123.45i)); 
+
+    ir = toIreal(toString("123.45e+82i"));
+    assert(toString(ir) == toString(123.45e+82i));
+    //assert(ir == 123.45e+82i);
+
+    // min and max
+    ir = toIreal(toString(ireal.min));
+    assert(toString(ir) == toString(ireal.min));
+    assert(feq(cast(real)ir.re, cast(real)ireal.min.re));
+    assert(feq(cast(real)ir.im, cast(real)ireal.min.im));
+
+    ir = toIreal(toString(ireal.max));
+    assert(toString(ir) == toString(ireal.max));
+    assert(feq(cast(real)ir.re, cast(real)ireal.max.re));
+    //assert(feq(cast(real)ir.im, cast(real)ireal.max.im));
+
+    // nan
+    ir = toIreal("nani");
+    assert(cast(real)ir == cast(real)ireal.nan);
+
+    ir = toIreal(toString(ireal.nan));
+    assert(toString(ir) == toString(ireal.nan));
+}
+
+
+/*******************************************************
+ * ditto
+ */
+cfloat toCfloat(in char[] s)
+{
+    char[] s1;
+    char[] s2;
+    real   r1;
+    real   r2;
+    cfloat cf;
+    bool    b = 0;
+    char*  endptr;
+
+    if (!s.length)
+        goto Lerr;
+    
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+    
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); 
+
+    cf = cast(cfloat)(r1 + (r2 * 1.0i));
+
+    //writefln( "toCfloat() r1=%g, r2=%g, cf=%g, max=%g", 
+    //           r1, r2, cf, cfloat.max);
+    // Currently disabled due to a posted bug where a 
+    // complex float greater-than compare to .max compares 
+    // incorrectly.
+    //if (cf > cfloat.max)
+    //    goto Loverflow;
+
+    return cf;
+
+    Loverflow:
+        conv_overflow(s);
+        
+    Lerr:
+        conv_error(s);
+        return cast(cfloat)0.0e-0+0i;   
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCfloat.unittest");
+    cfloat cf;
+
+    cf = toCfloat(toString("1.2345e-5+0i"));
+    assert(toString(cf) == toString(1.2345e-5+0i));
+    assert(feq(cf, 1.2345e-5+0i));
+
+    // min and max
+    cf = toCfloat(toString(cfloat.min));
+    assert(toString(cf) == toString(cfloat.min));
+
+    cf = toCfloat(toString(cfloat.max));
+    assert(toString(cf) == toString(cfloat.max));
+   
+    // nan ( nan+nani )
+    cf = toCfloat("nani");
+    //writefln("toCfloat() cf=%g, cf=\"%s\", nan=%s", 
+    //         cf, toString(cf), toString(cfloat.nan));
+    assert(toString(cf) == toString(cfloat.nan));
+
+    cf = toCdouble("nan+nani");
+    assert(toString(cf) == toString(cfloat.nan));
+
+    cf = toCfloat(toString(cfloat.nan));
+    assert(toString(cf) == toString(cfloat.nan));
+    assert(feq(cast(creal)cf, cast(creal)cfloat.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+cdouble toCdouble(in char[] s)
+{
+    char[]  s1;
+    char[]  s2;
+    real    r1;
+    real    r2;
+    cdouble cd;
+    bool     b = 0;
+    char*   endptr;
+
+    if (!s.length)
+        goto Lerr;
+    
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); //atof(s2);
+
+    cd = cast(cdouble)(r1 + (r2 * 1.0i));
+ 
+    //Disabled, waiting on a bug fix.
+    //if (cd > cdouble.max)  //same problem the toCfloat() having
+    //    goto Loverflow;
+
+    return cd;
+
+    Loverflow:
+        conv_overflow(s);
+        
+    Lerr:
+        conv_error(s);
+        return cast(cdouble)0.0e-0+0i; 
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCdouble.unittest");
+    cdouble cd;
+
+    cd = toCdouble(toString("1.2345e-5+0i"));
+    assert(toString( cd ) == toString(1.2345e-5+0i));
+    assert(feq(cd, 1.2345e-5+0i));
+
+    // min and max
+    cd = toCdouble(toString(cdouble.min));
+    assert(toString(cd) == toString(cdouble.min));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.min));
+
+    cd = toCdouble(toString(cdouble.max));
+    assert(toString( cd ) == toString(cdouble.max));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.max));
+
+    // nan ( nan+nani )
+    cd = toCdouble("nani");
+    assert(toString(cd) == toString(cdouble.nan));
+
+    cd = toCdouble("nan+nani");
+    assert(toString(cd) == toString(cdouble.nan));
+
+    cd = toCdouble(toString(cdouble.nan));
+    assert(toString(cd) == toString(cdouble.nan));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+creal toCreal(in char[] s)
+{
+    char[] s1;
+    char[] s2;
+    real   r1;
+    real   r2;
+    creal  cr;
+    bool    b = 0;
+    char*  endptr;
+
+    if (!s.length)
+        goto Lerr;
+
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+ 
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); //atof(s2);
+
+    //writefln("toCreal() r1=%g, r2=%g, s1=\"%s\", s2=\"%s\", nan=%g", 
+    //          r1, r2, s1, s2, creal.nan);
+   
+    if (s1 =="nan" && s2 == "nani")
+        cr = creal.nan;
+    else if (r2 != 0.0)
+        cr = cast(creal)(r1 + (r2 * 1.0i));
+    else
+        cr = cast(creal)(r1 + 0.0i);    
+    
+    return cr;
+
+    Lerr:
+        conv_error(s);
+        return cast(creal)0.0e-0+0i;    
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCreal.unittest");
+    creal cr;
+
+    cr = toCreal(toString("1.2345e-5+0i"));
+    assert(toString(cr) == toString(1.2345e-5+0i));
+    assert(feq(cr, 1.2345e-5+0i));
+
+    cr = toCreal(toString("0.0e-0+0i"));
+    assert(toString(cr) == toString(0.0e-0+0i));
+    assert(cr == 0.0e-0+0i);
+    assert(feq(cr, 0.0e-0+0i));
+    
+    cr = toCreal("123");
+    assert(cr == 123);
+
+    cr = toCreal("+5");
+    assert(cr == 5);
+ 
+    cr = toCreal("-78");
+    assert(cr == -78);
+
+    // min and max
+    cr = toCreal(toString(creal.min));
+    assert(toString(cr) == toString(creal.min));
+    assert(feq(cr, creal.min));
+    
+    cr = toCreal(toString(creal.max));
+    assert(toString(cr) == toString(creal.max));
+    assert(feq(cr, creal.max));
+
+    // nan ( nan+nani )
+    cr = toCreal("nani");
+    assert(toString(cr) == toString(creal.nan));
+
+    cr = toCreal("nan+nani");
+    assert(toString(cr) == toString(creal.nan));
+
+    cr = toCreal(toString(cdouble.nan));
+    assert(toString(cr) == toString(creal.nan));
+    assert(feq(cr, creal.nan));
+}
+
+}
+
+/* **************************************************************
+ * Splits a complex float (cfloat, cdouble, and creal) into two workable strings.
+ * Grammar:
+ * ['+'|'-'] string floating-point digit {digit}
+ */
+private bool getComplexStrings(in char[] s, out char[] s1, out char[] s2)
+{
+    int len = s.length;
+
+    if (!len) 
+        goto Lerr;
+
+    // When "nan" or "nani" just return them.
+    if (s == "nan" || s == "nani" || s == "nan+nani")
+    {
+        s1 = "nan";
+        s2 = "nani";
+        return 1;
+    }
+    
+    // Split the original string out into two strings.
+    for (int i = 1; i < len; i++)
+        if ((s[i - 1] != 'e' && s[i - 1] != 'E') && s[i] == '+')
+        {
+            s1 = s[0..i];
+            if (i + 1 < len - 1)
+                s2 = s[i + 1..len - 1];
+            else 
+                s2 = "0e+0i";
+            
+            break;
+        }   
+
+    // Handle the case when there's only a single value 
+    // to work with, and set the other string to zero.
+    if (!s1.length)
+    {
+        s1 = s;
+        s2 = "0e+0i";
+    }
+ 
+    //writefln( "getComplexStrings() s=\"%s\", s1=\"%s\", s2=\"%s\", len=%d", 
+    //           s, s1, s2, len );
+   
+    return 1;
+
+    Lerr:
+        // Display the original string in the error message.
+        conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\"" ~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\"");
+        return 0;
+}
+
+// feq() functions now used only in unittesting
+
+/* ***************************************
+ * Main function to compare reals with given precision
+ */
+private bool feq(in real rx, in real ry, in real precision)
+{
+    if (rx == ry)
+        return 1;
+    
+    if (isnan(rx))
+        return cast(bool)isnan(ry);
+
+    if (isnan(ry))
+        return 0;
+       
+    return cast(bool)(fabs(rx - ry) <= precision);
+}
+
+/* ***************************************
+ * (Note: Copied here from std.math's mfeq() function for unittesting)
+ * Simple function to compare two floating point values
+ * to a specified precision.
+ * Returns:
+ *  1   match
+ *  0   nomatch
+ */
+private bool feq(in real r1, in real r2)
+{
+    if (r1 == r2)
+        return 1;
+    
+    if (isnan(r1))
+        return cast(bool)isnan(r2);
+
+    if (isnan(r2))
+        return 0;
+        
+    return cast(bool)(feq(r1, r2, 0.000001L));
+} 
+ 
+/* ***************************************
+ * compare ireals with given precision
+ */
+private bool feq(in ireal r1, in ireal r2)
+{
+    real rx = cast(real)r1;
+    real ry = cast(real)r2;
+
+    if (rx == ry)
+        return 1;
+    
+    if (isnan(rx)) 
+        return cast(bool)isnan(ry);
+
+    if (isnan(ry))
+        return 0;
+    
+    return feq(rx, ry, 0.000001L);
+} 
+
+/* ***************************************
+ * compare creals with given precision
+ */
+private bool feq(in creal r1, in creal r2)
+{
+    real r1a = fabs(cast(real)r1.re - cast(real)r2.re);
+    real r2b = fabs(cast(real)r1.im - cast(real)r2.im);
+
+    if ((cast(real)r1.re == cast(real)r2.re) &&
+        (cast(real)r1.im == cast(real)r2.im))
+        return 1;
+    
+    if (isnan(r1a))
+        return cast(bool)isnan(r2b);
+
+    if (isnan(r2b))
+        return 0;
+
+    return feq(r1a, r2b, 0.000001L);
+}
+
--- a/lphobos/std/format.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/std/format.d	Fri Jan 04 01:38:42 2008 +0100
@@ -170,15 +170,12 @@
       ti = typeid(idouble);break;
     case Mangle.Tireal:
       ti = typeid(ireal);break;
-    /+
-    // No complex in LLVMDC yes
     case Mangle.Tcfloat:
       ti = typeid(cfloat);break;
     case Mangle.Tcdouble:
       ti = typeid(cdouble);break;
     case Mangle.Tcreal:
       ti = typeid(creal);break;
-    +/
     case Mangle.Tchar:
       ti = typeid(char);break;
     case Mangle.Twchar:
@@ -450,7 +447,8 @@
  */
 
 void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
-{   int j;
+{   //printf("doFormat(...)\n");
+    int j;
     TypeInfo ti;
     Mangle m;
     uint flags;
@@ -503,7 +501,7 @@
 
 	void putstr(char[] s)
 	{
-	    //printf("flags = x%x\n", flags);
+	    //printf("flags = 0x%x\n", flags);
 	    int prepad = 0;
 	    int postpad = 0;
 	    int padding = field_width - (strlen(prefix) + s.length);
@@ -539,7 +537,8 @@
 
 	void putreal(real v)
 	{
-	    //printf("putreal %Lg\n", vreal);
+	    //printf("putreal %Lg\n", vreal); // no 80 bit float
+        //printf("putreal %g\n", vreal);
 
 	    switch (fc)
 	    {
@@ -593,9 +592,11 @@
 		format[i + 0] = '*';
 		format[i + 1] = '.';
 		format[i + 2] = '*';
-		format[i + 3] = 'L';
-		format[i + 4] = fc;
-		format[i + 5] = 0;
+        format[i + 3] = fc;
+        format[i + 4] = 0;
+		//format[i + 3] = 'L'; // no 80 bit yet
+		//format[i + 4] = fc;
+		//format[i + 5] = 0;
 		if (!(flags & FLprecision))
 		    precision = -1;
 		while (1)
@@ -638,7 +639,8 @@
 	  auto tiSave = ti;
 	  auto mSave = m;
 	  ti = valti;
-	  //printf("\n%.*s\n", valti.classinfo.name);
+      auto className = valti.classinfo.name;
+	  printf("\n%.*s\n", className.length, className.ptr);
 	  m = getMan(valti);
 	  while (len--)
 	  {
@@ -831,10 +833,12 @@
 		goto Lcomplex;
 
 	    case Mangle.Tsarray:
+        //printf("static array\n");
 		putArray(argptr, (cast(TypeInfo_StaticArray)ti).len, (cast(TypeInfo_StaticArray)ti).next);
 		return;
 
 	    case Mangle.Tarray:
+        //printf("dynamic array\n");
 		int mi = 10;
 	        if (ti.classinfo.name.length == 14 &&
 		    ti.classinfo.name[9..14] == "Array") 
@@ -863,6 +867,7 @@
 		  return;
 		}
 
+        //printf("primitive type\n");
 		while (1)
 		{
 		    m2 = cast(Mangle)ti.classinfo.name[mi];
@@ -897,6 +902,7 @@
 			    continue;
 
 			default:
+                //printf("primitive type default handling\n");
 			    TypeInfo ti2 = primitiveTypeInfo(m2);
 			    if (!ti2)
 			      goto Lerror;
@@ -1058,9 +1064,10 @@
     }
 
 
+    //printf("arguments length: %u\n", arguments.length);
     for (j = 0; j < arguments.length; )
     {	ti = arguments[j++];
-	//printf("test1: '%.*s' %d\n", ti.classinfo.name, ti.classinfo.name.length);
+	//printf("test1: '%.*s' %d\n", ti.classinfo.name.length, ti.classinfo.name.ptr, ti.classinfo.name.length);
 	//ti.print();
 
 	flags = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/gc.di	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,193 @@
+
+/*
+ *  Copyright (C) 1999-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+/**
+ * The garbage collector normally works behind the scenes without needing any
+ * specific interaction. These functions are for advanced applications that
+ * benefit from tuning the operation of the collector.
+ * Macros:
+ *	WIKI=Phobos/StdGc
+ */
+
+module std.gc;
+
+import gcstats;
+
+/**
+ * Add p to list of roots. Roots are references to memory allocated by the
+ collector that are maintained in memory outside the collector pool. The garbage
+ collector will by default look for roots in the stacks of each thread, the
+ registers, and the default static data segment. If roots are held elsewhere,
+ use addRoot() or addRange() to tell the collector not to free the memory it
+ points to.
+ */
+void addRoot(void *p);		// add p to list of roots
+
+/**
+ * Remove p from list of roots.
+ */
+void removeRoot(void *p);	// remove p from list of roots
+
+/**
+ * Add range to scan for roots.
+ */
+void addRange(void *pbot, void *ptop);	// add range to scan for roots
+
+/**
+ * Remove range.
+ */
+void removeRange(void *pbot);		// remove range
+
+/**
+ * Mark a gc allocated block of memory as possibly containing pointers.
+ */
+void hasPointers(void* p);
+
+/**
+ * Mark a gc allocated block of memory as definitely NOT containing pointers.
+ */
+void hasNoPointers(void* p);
+
+/**
+ * Mark a gc allocated block of memory pointed to by p as being populated with
+ * an array of TypeInfo ti (as many as will fit).
+ */
+void setTypeInfo(TypeInfo ti, void* p);
+
+/**
+ * Allocate nbytes of uninitialized data.
+ * The allocated memory will be scanned for pointers during
+ * a gc collection cycle, unless
+ * it is followed by a call to hasNoPointers().
+ */
+void[] malloc(size_t nbytes);
+
+/**
+ * Resize allocated memory block pointed to by p to be at least nbytes long.
+ * It will try to resize the memory block in place.
+ * If nbytes is 0, the memory block is free'd.
+ * If p is null, the memory block is allocated using malloc.
+ * The returned array may not be at the same location as the original
+ * memory block.
+ * The allocated memory will be scanned for pointers during
+ * a gc collection cycle, unless
+ * it is followed by a call to hasNoPointers().
+ */
+void[] realloc(void* p, size_t nbytes);
+
+/**
+ * Attempt to enlarge the memory block pointed to by p
+ * by at least minbytes beyond its current capacity,
+ * up to a maximum of maxbytes.
+ * Returns:
+ *	0 if could not extend p,
+ *	total size of entire memory block if successful.
+ */
+size_t extend(void* p, size_t minbytes, size_t maxbytes);
+
+/**
+ * Returns capacity (size of the memory block) that p
+ * points to the beginning of.
+ * If p does not point into the gc memory pool, or does
+ * not point to the beginning of an allocated memory block,
+ * 0 is returned.
+ */
+size_t capacity(void* p);
+
+/**
+ * Set gc behavior to match that of 1.0.
+ */
+void setV1_0();
+
+/***********************************
+ * Run a full garbage collection cycle.
+ *
+ * The collector normally runs synchronously with a storage allocation request
+ (i.e. it never happens when in code that does not allocate memory). In some
+ circumstances, for example when a particular task is finished, it is convenient
+ to explicitly run the collector and free up all memory used by that task. It
+ can also be helpful to run a collection before starting a new task that would
+ be annoying if it ran a collection in the middle of that task. Explicitly
+ running a collection can also be done in a separate very low priority thread,
+ so that if the program is idly waiting for input, memory can be cleaned up.
+ */
+
+void fullCollect();
+
+/***********************************
+ * Run a generational garbage collection cycle.
+ * Takes less time than a fullcollect(), but isn't
+ * as effective.
+ */
+
+void genCollect();
+
+void genCollectNoStack();
+
+/**
+ * Minimizes physical memory usage
+ */
+void minimize();
+
+/***************************************
+ * disable() temporarily disables garbage collection cycle, enable()
+ * then reenables them.
+ *
+ * This is used for brief time critical sections of code, so the amount of time
+ * it will take is predictable.
+ * If the collector runs out of memory while it is disabled, it will throw an
+ * std.outofmemory.OutOfMemoryException.
+ * The disable() function calls can be nested, but must be
+ * matched with corresponding enable() calls.
+ * By default collections are enabled.
+ */
+
+void disable();
+
+/**
+ * ditto
+ */
+void enable();
+
+void getStats(out GCStats stats);
+
+/***************************************
+ * Get handle to the collector.
+ */
+
+void* getGCHandle();
+
+/***************************************
+ * Set handle to the collector.
+ */
+
+void setGCHandle(void* p);
+
+void endGCHandle();
+
+extern (C)
+{
+    void gc_init();
+    void gc_term();
+}
--- a/lphobos/std/stdarg.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/std/stdarg.d	Fri Jan 04 01:38:42 2008 +0100
@@ -6,14 +6,16 @@
 
 /* This is for use with variable argument lists with extern(D) linkage. */
 
+/* Modified for LLVMDC (LLVM D Compiler) by Tomas Lindquist Olsen, 2007 */
+
 module std.stdarg;
 
 alias void* va_list;
 
-T va_arg(T)(inout va_list vp)
+T va_arg(T)(ref va_list vp)
 {
-    static assert((T.sizeof & (T.sizeof -1)) == 0);
-    va_list vptmp = cast(va_list)((cast(size_t)vp + T.sizeof - 1) &  ~(T.sizeof - 1));
+    size_t size = T.sizeof > size_t.sizeof ? size_t.sizeof : T.sizeof;
+    va_list vptmp = cast(va_list)((cast(size_t)vp + size - 1) &  ~(size - 1));
     vp = vptmp + T.sizeof;
     return *cast(T*)vptmp;
 }
--- a/lphobos/std/stdio.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/std/stdio.d	Fri Jan 04 01:38:42 2008 +0100
@@ -1,44 +1,548 @@
+
+// Written in the D programming language.
+
+/* Written by Walter Bright and Andrei Alexandrescu
+ * www.digitalmars.com
+ * Placed in the Public Domain.
+ */
+
+/********************************
+ * Standard I/O functions that extend $(B std.c.stdio).
+ * $(B std.c.stdio) is automatically imported when importing
+ * $(B std.stdio).
+ * Macros:
+ *	WIKI=Phobos/StdStdio
+ */
+
 module std.stdio;
 
-import std.traits;
+public import std.c.stdio;
 
-void _writef(T)(T t) {
-    static if (is(T == char)) {
-        printf("%c", t);
+import std.format;
+import std.utf;
+import std.string;
+import std.gc;
+import std.c.stdlib;
+import std.c.string;
+import std.c.stddef;
+
+
+version (DigitalMars)
+{
+    version (Windows)
+    {
+	// Specific to the way Digital Mars C does stdio
+	version = DIGITAL_MARS_STDIO;
     }
-    else static if (is(T : char[])) {
-        printf("%.*s", t.length, t.ptr);
-    }
-    else static if (is(T : long)) {
-        printf("%ld", t);
-    }
-    else static if (is(T : ulong)) {
-        printf("%lu", t);
-    }
-    else static if (is(T : real)) {
-        printf("%f", t);
-    }
-    else static if (is(T : Object)) {
-        _writef(t.toString());
-    }
-    else static if(isArray!(T)) {
-        _writef('[');
-        if (t.length) {
-            _writef(t[0]);
-            foreach(v; t[1..$]) {
-                _writef(','); _writef(v);
-            }
-        }
-        _writef(']');
-    }
-    else static assert(0, "Cannot writef:"~T.tostring);
 }
 
-void writef(T...)(T t)
+version (DIGITAL_MARS_STDIO)
 {
-    foreach(v;t) _writef(v);
 }
-void writefln(T...)(T t)
+else
 {
-    writef(t, '\n');
+    // Specific to the way Gnu C does stdio
+    version = GCC_IO;
+    import std.c.linux.linux;
 }
+
+version (DIGITAL_MARS_STDIO)
+{
+    extern (C)
+    {
+	/* **
+	 * Digital Mars under-the-hood C I/O functions
+	 */
+	int _fputc_nlock(int, FILE*);
+	int _fputwc_nlock(int, FILE*);
+	int _fgetc_nlock(FILE*);
+	int _fgetwc_nlock(FILE*);
+	int __fp_lock(FILE*);
+	void __fp_unlock(FILE*);
+    }
+    alias _fputc_nlock FPUTC;
+    alias _fputwc_nlock FPUTWC;
+    alias _fgetc_nlock FGETC;
+    alias _fgetwc_nlock FGETWC;
+
+    alias __fp_lock FLOCK;
+    alias __fp_unlock FUNLOCK;
+}
+else version (GCC_IO)
+{
+    /* **
+     * Gnu under-the-hood C I/O functions; see
+     * http://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html#I_002fO-on-Streams
+     */
+    extern (C)
+    {
+	int fputc_unlocked(int, FILE*);
+	int fputwc_unlocked(wchar_t, FILE*);
+	int fgetc_unlocked(FILE*);
+	int fgetwc_unlocked(FILE*);
+	void flockfile(FILE*);
+	void funlockfile(FILE*);
+	ssize_t getline(char**, size_t*, FILE*);
+	ssize_t getdelim (char**, size_t*, int, FILE*);
+    }
+
+    alias fputc_unlocked FPUTC;
+    alias fputwc_unlocked FPUTWC;
+    alias fgetc_unlocked FGETC;
+    alias fgetwc_unlocked FGETWC;
+
+    alias flockfile FLOCK;
+    alias funlockfile FUNLOCK;
+}
+else
+{
+    static assert(0, "unsupported C I/O system");
+}
+
+
+/*********************
+ * Thrown if I/O errors happen.
+ */
+class StdioException : Exception
+{
+    uint errno;			// operating system error code
+
+    this(char[] msg)
+    {
+	super(msg);
+    }
+
+    this(uint errno)
+    {	char* s = strerror(errno);
+	super(std.string.toString(s).dup);
+    }
+
+    static void opCall(char[] msg)
+    {
+	throw new StdioException(msg);
+    }
+
+    static void opCall()
+    {
+	throw new StdioException(getErrno());
+    }
+}
+
+private
+void writefx(FILE* fp, TypeInfo[] arguments, void* argptr, int newline=false)
+{   int orientation;
+
+    orientation = fwide(fp, 0);
+
+    /* Do the file stream locking at the outermost level
+     * rather than character by character.
+     */
+    FLOCK(fp);
+    scope(exit) FUNLOCK(fp);
+
+    if (orientation <= 0)		// byte orientation or no orientation
+    {
+	void putc(dchar c)
+	{
+	    if (c <= 0x7F)
+	    {
+		FPUTC(c, fp);
+	    }
+	    else
+	    {   char[4] buf;
+		char[] b;
+
+		b = std.utf.toUTF8(buf, c);
+		for (size_t i = 0; i < b.length; i++)
+		    FPUTC(b[i], fp);
+	    }
+	}
+
+	std.format.doFormat(&putc, arguments, argptr);
+	if (newline)
+	    FPUTC('\n', fp);
+    }
+    else if (orientation > 0)		// wide orientation
+    {
+	version (Windows)
+	{
+	    void putcw(dchar c)
+	    {
+		assert(isValidDchar(c));
+		if (c <= 0xFFFF)
+		{
+		    FPUTWC(c, fp);
+		}
+		else
+		{   wchar[2] buf;
+
+		    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+		    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+		    FPUTWC(buf[0], fp);
+		    FPUTWC(buf[1], fp);
+		}
+	    }
+	}
+	else version (linux)
+	{
+	    void putcw(dchar c)
+	    {
+		FPUTWC(c, fp);
+	    }
+	}
+	else
+	{
+	    static assert(0);
+	}
+
+	std.format.doFormat(&putcw, arguments, argptr);
+	if (newline)
+	    FPUTWC('\n', fp);
+    }
+}
+
+
+/***********************************
+ * Arguments are formatted per the
+ * $(LINK2 std_format.html#format-string, format strings)
+ * and written to $(B stdout).
+ */
+
+void writef(...)
+{
+    writefx(stdout, _arguments, _argptr, 0);
+}
+
+/***********************************
+ * Same as $(B writef), but a newline is appended
+ * to the output.
+ */
+
+void writefln(...)
+{
+    writefx(stdout, _arguments, _argptr, 1);
+}
+
+/***********************************
+ * Same as $(B writef), but output is sent to the
+ * stream fp instead of $(B stdout).
+ */
+
+void fwritef(FILE* fp, ...)
+{
+    writefx(fp, _arguments, _argptr, 0);
+}
+
+/***********************************
+ * Same as $(B writefln), but output is sent to the
+ * stream fp instead of $(B stdout).
+ */
+
+void fwritefln(FILE* fp, ...)
+{
+    writefx(fp, _arguments, _argptr, 1);
+}
+
+/**********************************
+ * Read line from stream fp.
+ * Returns:
+ *	null for end of file,
+ *	char[] for line read from fp, including terminating '\n'
+ * Params:
+ *	fp = input stream
+ * Throws:
+ *	$(B StdioException) on error
+ * Example:
+ *	Reads $(B stdin) and writes it to $(B stdout).
+---
+import std.stdio;
+
+int main()
+{
+    char[] buf;
+    while ((buf = readln()) != null)
+	writef("%s", buf);
+    return 0;
+}
+---
+ */
+char[] readln(FILE* fp = stdin)
+{
+    char[] buf;
+    readln(fp, buf);
+    return buf;
+}
+
+/**********************************
+ * Read line from stream fp and write it to buf[],
+ * including terminating '\n'.
+ *
+ * This is often faster than readln(FILE*) because the buffer
+ * is reused each call. Note that reusing the buffer means that
+ * the previous contents of it need to be copied if needed.
+ * Params:
+ *	fp = input stream
+ *	buf = buffer used to store the resulting line data. buf
+ *		is resized as necessary.
+ * Returns:
+ *	0 for end of file, otherwise
+ *	number of characters read
+ * Throws:
+ *	$(B StdioException) on error
+ * Example:
+ *	Reads $(B stdin) and writes it to $(B stdout).
+---
+import std.stdio;
+
+int main()
+{
+    char[] buf;
+    while (readln(stdin, buf))
+	writef("%s", buf);
+    return 0;
+}
+---
+ */
+size_t readln(FILE* fp, inout char[] buf)
+{
+    version (DIGITAL_MARS_STDIO)
+    {
+	FLOCK(fp);
+	scope(exit) FUNLOCK(fp);
+
+	if (__fhnd_info[fp._file] & FHND_WCHAR)
+	{   /* Stream is in wide characters.
+	     * Read them and convert to chars.
+	     */
+	    static assert(wchar_t.sizeof == 2);
+	    buf.length = 0;
+	    int c2;
+	    for (int c; (c = FGETWC(fp)) != -1; )
+	    {
+		if ((c & ~0x7F) == 0)
+		{   buf ~= c;
+		    if (c == '\n')
+			break;
+		}
+		else
+		{
+		    if (c >= 0xD800 && c <= 0xDBFF)
+		    {
+			if ((c2 = FGETWC(fp)) != -1 ||
+			    c2 < 0xDC00 && c2 > 0xDFFF)
+			{
+			    StdioException("unpaired UTF-16 surrogate");
+			}
+			c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+		    }
+		    std.utf.encode(buf, c);
+		}
+	    }
+	    if (ferror(fp))
+		StdioException();
+	    return buf.length;
+	}
+
+	auto sz = std.gc.capacity(buf.ptr);
+	//auto sz = buf.length;
+	buf = buf.ptr[0 .. sz];
+	if (fp._flag & _IONBF)
+	{
+	    /* Use this for unbuffered I/O, when running
+	     * across buffer boundaries, or for any but the common
+	     * cases.
+	     */
+	 L1:
+	    char *p;
+
+	    if (sz)
+	    {
+		p = buf.ptr;
+	    }
+	    else
+	    {
+		sz = 64;
+		p = cast(char*) std.gc.malloc(sz);
+		std.gc.hasNoPointers(p);
+		buf = p[0 .. sz];
+	    }
+	    size_t i = 0;
+	    for (int c; (c = FGETC(fp)) != -1; )
+	    {
+		if ((p[i] = c) != '\n')
+		{
+		    i++;
+		    if (i < sz)
+			continue;
+		    buf = p[0 .. i] ~ readln(fp);
+		    return buf.length;
+		}
+		else
+		{
+		    buf = p[0 .. i + 1];
+		    return i + 1;
+		}
+	    }
+	    if (ferror(fp))
+		StdioException();
+	    buf = p[0 .. i];
+	    return i;
+	}
+	else
+	{
+	    int u = fp._cnt;
+	    char* p = fp._ptr;
+	    int i;
+	    if (fp._flag & _IOTRAN)
+	    {   /* Translated mode ignores \r and treats ^Z as end-of-file
+		 */
+		char c;
+		while (1)
+		{
+		    if (i == u)		// if end of buffer
+			goto L1;	// give up
+		    c = p[i];
+		    i++;
+		    if (c != '\r')
+		    {
+			if (c == '\n')
+			    break;
+			if (c != 0x1A)
+			    continue;
+			goto L1;
+		    }
+		    else
+		    {   if (i != u && p[i] == '\n')
+			    break;
+			goto L1;
+		    }
+		}
+		if (i > sz)
+		{
+		    buf = cast(char[])std.gc.malloc(i);
+		    std.gc.hasNoPointers(buf.ptr);
+		}
+		if (i - 1)
+		    memcpy(buf.ptr, p, i - 1);
+		buf[i - 1] = '\n';
+		if (c == '\r')
+		    i++;
+	    }
+	    else
+	    {
+		while (1)
+		{
+		    if (i == u)		// if end of buffer
+			goto L1;	// give up
+		    auto c = p[i];
+		    i++;
+		    if (c == '\n')
+			break;
+		}
+		if (i > sz)
+		{
+		    buf = cast(char[])std.gc.malloc(i);
+		    std.gc.hasNoPointers(buf.ptr);
+		}
+		memcpy(buf.ptr, p, i);
+	    }
+	    fp._cnt -= i;
+	    fp._ptr += i;
+	    buf = buf[0 .. i];
+	    return i;
+	}
+    }
+    else version (GCC_IO)
+    {
+	if (fwide(fp, 0) > 0)
+	{   /* Stream is in wide characters.
+	     * Read them and convert to chars.
+	     */
+	    FLOCK(fp);
+	    scope(exit) FUNLOCK(fp);
+	    version (Windows)
+	    {
+		buf.length = 0;
+		int c2;
+		for (int c; (c = FGETWC(fp)) != -1; )
+		{
+		    if ((c & ~0x7F) == 0)
+		    {   buf ~= c;
+			if (c == '\n')
+			    break;
+		    }
+		    else
+		    {
+			if (c >= 0xD800 && c <= 0xDBFF)
+			{
+			    if ((c2 = FGETWC(fp)) != -1 ||
+				c2 < 0xDC00 && c2 > 0xDFFF)
+			    {
+				StdioException("unpaired UTF-16 surrogate");
+			    }
+			    c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+			}
+			std.utf.encode(buf, c);
+		    }
+		}
+		if (ferror(fp))
+		    StdioException();
+		return buf.length;
+	    }
+	    else version (linux)
+	    {
+		buf.length = 0;
+		for (int c; (c = FGETWC(fp)) != -1; )
+		{
+		    if ((c & ~0x7F) == 0)
+			buf ~= c;
+		    else
+			std.utf.encode(buf, cast(dchar)c);
+		    if (c == '\n')
+			break;
+		}
+		if (ferror(fp))
+		    StdioException();
+		return buf.length;
+	    }
+	    else
+	    {
+		static assert(0);
+	    }
+	}
+
+	char *lineptr = null;
+	size_t n = 0;
+	auto s = getdelim(&lineptr, &n, '\n', fp);
+	scope(exit) free(lineptr);
+	if (s < 0)
+	{
+	    if (ferror(fp))
+		StdioException();
+	    buf.length = 0;		// end of file
+	    return 0;
+	}
+	buf = buf.ptr[0 .. std.gc.capacity(buf.ptr)];
+	if (s <= buf.length)
+	{
+	    buf.length = s;
+	    buf[] = lineptr[0 .. s];
+	}
+	else
+	{
+	    buf = lineptr[0 .. s].dup;
+	}
+	return s;
+    }
+    else
+    {
+	static assert(0);
+    }
+}
+
+/** ditto */
+size_t readln(inout char[] buf)
+{
+    return readln(stdin, buf);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/thread.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,1127 @@
+// Written in the D programming language
+
+/*
+ *  Copyright (C) 2002-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/**************************
+ * The thread module defines the class $(B Thread).
+ *
+ * $(B Thread) is the basis
+ * for writing multithreaded applications. Each thread
+ * has a unique instance of class $(B Thread) associated with it.
+ * It is important to use the $(B Thread) class to create and manage
+ * threads as the garbage collector needs to know about all the threads.
+ * Macros:
+ *	WIKI=Phobos/StdThread
+ */
+
+module std.thread;
+
+import std.c.stdio;
+
+//debug=thread;
+
+/* ================================ Win32 ================================= */
+
+version (Win32)
+{
+
+private import std.c.windows.windows;
+
+extern (Windows) alias uint (*stdfp)(void *);
+
+extern (C)
+    thread_hdl _beginthreadex(void* security, uint stack_size,
+	stdfp start_addr, void* arglist, uint initflag,
+	thread_id* thrdaddr);
+
+/**
+ * The type of the thread handle used by the operating system.
+ * For Windows, it is equivalent to a HANDLE from windows.d.
+ */
+alias HANDLE thread_hdl;
+
+alias uint thread_id;
+
+/**
+ * Thrown for errors.
+ */
+class ThreadError : Error
+{
+    this(char[] s)
+    {
+	super("Thread error: " ~ s);
+    }
+}
+
+/**
+ * One of these is created for each thread.
+ */
+class Thread
+{
+    /**
+     * Constructor used by classes derived from Thread that override main(). 
+     * The optional stacksize parameter default value of 0 will cause threads
+     * to be created with the default size for the executable - Dave Fladebo
+     */
+    this(size_t stacksize = 0)
+    {
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Constructor used by classes derived from Thread that override run().
+     */
+    this(int (*fp)(void *), void *arg, size_t stacksize = 0)
+    {
+	this.fp = fp;
+	this.arg = arg;
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Constructor used by classes derived from Thread that override run().
+     */
+    this(int delegate() dg, size_t stacksize = 0)
+    {
+	this.dg = dg;
+	this.stacksize = stacksize;
+    }
+
+    /**
+     * Destructor
+     *
+     * If the thread hasn't been joined yet, detach it.
+     */
+    ~this()
+    {
+        if (state != TS.FINISHED)
+            CloseHandle(hdl);
+    }
+
+    /**
+     * The handle to this thread assigned by the operating system. This is set
+     * to thread_id.init if the thread hasn't been started yet.
+     */
+    thread_hdl hdl;
+
+    void* stackBottom;
+
+    /**
+     * Create a new thread and start it running. The new thread initializes
+     * itself and then calls run(). start() can only be called once.
+     */
+    void start()
+    {
+	if (state != TS.INITIAL)
+	    error("already started");
+
+	synchronized (Thread.classinfo)
+	{
+	    for (int i = 0; 1; i++)
+	    {
+		if (i == allThreads.length)
+		    error("too many threads");
+		if (!allThreads[i])
+		{   allThreads[i] = this;
+		    idx = i;
+		    if (i >= allThreadsDim)
+			allThreadsDim = i + 1;
+		    break;
+		}
+	    }
+	    nthreads++;
+	}
+
+	state = TS.RUNNING;
+	hdl = _beginthreadex(null, cast(uint)stacksize, &threadstart, cast(void*)this, 0, &id);
+	if (hdl == cast(thread_hdl)0)
+	{   state = TS.FINISHED;
+	    synchronized (Thread.classinfo) allThreads[idx] = null;
+	    idx = -1;
+	    error("failed to start");
+	}
+    }
+
+    /**
+     * Entry point for a thread. If not overridden, it calls the function
+     * pointer fp and argument arg passed in the constructor, or the delegate
+     * dg.
+     * Returns: the thread exit code, which is normally 0.
+     */
+    int run()
+    {
+	if (fp)
+	    return fp(arg);
+	else if (dg)
+	    return dg();
+	assert(0);
+    }
+
+    /*****************************
+     * Wait for this thread to terminate.
+     * Simply returns if thread has already terminated.
+     * Throws: $(B ThreadError) if the thread hasn't begun yet or
+     * is called on itself.
+     */
+    void wait()
+    {
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{   DWORD dw;
+
+	    dw = WaitForSingleObject(hdl, 0xFFFFFFFF);
+            state = TS.FINISHED;
+            CloseHandle(hdl);
+            hdl = null;
+	}
+    }
+
+    /******************************
+     * Wait for this thread to terminate or until milliseconds time has
+     * elapsed, whichever occurs first.
+     * Simply returns if thread has already terminated.
+     * Throws: $(B ThreadError) if the thread hasn't begun yet or
+     * is called on itself.
+     */
+    void wait(uint milliseconds)
+    {
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{   DWORD dw;
+
+	    dw = WaitForSingleObject(hdl, milliseconds);
+            state = TS.FINISHED;
+            CloseHandle(hdl);
+            hdl = null;
+	}
+    }
+
+    /**
+     * The state of a thread.
+     */
+    enum TS
+    {
+	INITIAL,	/// The thread hasn't been started yet.
+	RUNNING,	/// The thread is running or paused.
+	TERMINATED,	/// The thread has ended.
+        FINISHED        /// The thread has been cleaned up
+    }
+
+    /**
+     * Returns the state of a thread.
+     */
+    TS getState()
+    {
+	return state;
+    }
+
+    /**
+     * The priority of a thread.
+     */
+    enum PRIORITY
+    {
+	INCREASE,	/// Increase thread priority
+	DECREASE,	/// Decrease thread priority
+	IDLE,		/// Assign thread low priority
+	CRITICAL	/// Assign thread high priority
+    }
+
+    /**
+     * Adjust the priority of this thread.
+     * Throws: ThreadError if cannot set priority
+     */
+    void setPriority(PRIORITY p)
+    {
+	int nPriority;
+
+	switch (p)
+	{
+	    case PRIORITY.INCREASE:
+		nPriority = THREAD_PRIORITY_ABOVE_NORMAL;
+		break;
+	    case PRIORITY.DECREASE:
+		nPriority = THREAD_PRIORITY_BELOW_NORMAL;
+		break;
+	    case PRIORITY.IDLE:
+		nPriority = THREAD_PRIORITY_IDLE;
+		break;
+	    case PRIORITY.CRITICAL:
+		nPriority = THREAD_PRIORITY_TIME_CRITICAL;
+		break;
+	    default:
+		assert(0);
+	}
+
+	if (SetThreadPriority(hdl, nPriority) == THREAD_PRIORITY_ERROR_RETURN)
+	    error("set priority");
+    }
+
+    /**
+     * Returns true if this thread is the current thread.
+     */
+    bool isSelf()
+    {
+	//printf("id = %d, self = %d\n", id, pthread_self());
+	return (id == GetCurrentThreadId());
+    }
+
+    /**
+     * Returns a reference to the Thread for the thread that called the
+     * function.
+     */
+    static Thread getThis()
+    {
+	//printf("getThis(), allThreadsDim = %d\n", allThreadsDim);
+        thread_id id = GetCurrentThreadId();
+        for (int i = 0; i < allThreadsDim; i++)
+        {
+            Thread t = allThreads[i];
+            if (t && id == t.id)
+            {
+                return t;
+            }
+        }
+	printf("didn't find it\n");
+	assert(0);
+    }
+
+    /**
+     * Returns an array of all the threads currently running.
+     */
+    static Thread[] getAll()
+    {
+	synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
+    }
+
+    /**
+     * Suspend execution of this thread.
+     */
+    void pause()
+    {
+	if (state != TS.RUNNING || SuspendThread(hdl) == 0xFFFFFFFF)
+	    error("cannot pause");
+    }
+
+    /**
+     * Resume execution of this thread.
+     */
+    void resume()
+    {
+	if (state != TS.RUNNING || ResumeThread(hdl) == 0xFFFFFFFF)
+	    error("cannot resume");
+    }
+
+    /**
+     * Suspend execution of all threads but this thread.
+     */
+    static void pauseAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                    thread_id thisid = GetCurrentThreadId();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                    {
+                        Thread t = allThreads[i];
+                        if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.pause();
+                }
+            }
+        }
+    }
+
+    /**
+     * Resume execution of all paused threads.
+     */
+    static void resumeAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                thread_id thisid = GetCurrentThreadId();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.resume();
+                }
+            }
+        }
+    }
+
+    /**
+     * Give up the remainder of this thread's time slice.
+     */
+    static void yield()
+    {
+	Sleep(0);
+    }
+
+    /**
+     *
+     */
+    static uint nthreads = 1;
+
+  private:
+
+    static uint allThreadsDim;
+    static Thread[0x400] allThreads;	// length matches value in C runtime
+
+    TS state;
+    int idx = -1;			// index into allThreads[]
+    thread_id id;
+    size_t stacksize = 0;
+
+    int (*fp)(void *);
+    void *arg;
+
+    int delegate() dg;
+
+    void error(char[] msg)
+    {
+	throw new ThreadError(msg);
+    }
+
+
+    /* ***********************************************
+     * This is just a wrapper to interface between C rtl and Thread.run().
+     */
+
+    extern (Windows) static uint threadstart(void *p)
+    {
+	Thread t = cast(Thread)p;
+	int result;
+
+	debug (thread) printf("Starting thread %d\n", t.idx);
+	t.stackBottom = os_query_stackBottom();
+	try
+	{
+	    result = t.run();
+	}
+	catch (Object o)
+	{
+	    fprintf(stderr, "Error: %.*s\n", o.toString());
+	    result = 1;
+	}
+
+	debug (thread) printf("Ending thread %d\n", t.idx);
+	t.state = TS.TERMINATED;
+        synchronized (Thread.classinfo)
+        {
+            allThreads[t.idx] = null;
+            t.idx = -1;
+            nthreads--;
+        }
+	return result;
+    }
+
+
+    /**************************************
+     * Create a Thread for global main().
+     */
+
+    public static void thread_init()
+    {
+	Thread t = new Thread();
+
+	t.state = TS.RUNNING;
+	t.id = GetCurrentThreadId();
+	t.hdl = Thread.getCurrentThreadHandle();
+	t.stackBottom = os_query_stackBottom();
+
+	assert(!allThreads[0]);
+	allThreads[0] = t;
+	allThreadsDim = 1;
+	t.idx = 0;
+    }
+
+    static ~this()
+    {
+	if (allThreadsDim)
+	{
+	    CloseHandle(allThreads[0].hdl);
+	    allThreads[0].hdl = GetCurrentThread();
+	}
+    }
+          
+    /********************************************
+     * Returns the handle of the current thread.
+     * This is needed because GetCurrentThread() always returns -2 which
+     * is a pseudo-handle representing the current thread.
+     * The returned thread handle is a windows resource and must be explicitly
+     * closed.
+     * Many thanks to Justin (jhenzie@mac.com) for figuring this out
+     * and providing the fix.
+     */
+    static thread_hdl getCurrentThreadHandle()
+    {
+	thread_hdl currentThread = GetCurrentThread();
+	thread_hdl actualThreadHandle;
+
+	//thread_hdl currentProcess = cast(thread_hdl)-1;
+	thread_hdl currentProcess = GetCurrentProcess(); // http://www.digitalmars.com/drn-bin/wwwnews?D/21217
+
+
+	uint access = cast(uint)0x00000002;
+
+	DuplicateHandle(currentProcess, currentThread, currentProcess,
+			 &actualThreadHandle, cast(uint)0, TRUE, access);
+
+	return actualThreadHandle;
+     }
+}
+
+
+/**********************************************
+ * Determine "bottom" of stack (actually the top on Win32 systems).
+ */
+
+void *os_query_stackBottom()
+{
+    asm
+    {
+	naked			;
+	mov	EAX,FS:4	;
+	ret			;
+    }
+}
+
+}
+
+/* ================================ linux ================================= */
+
+version (linux)
+{
+
+private import std.c.linux.linux;
+private import std.c.linux.linuxextern;
+private import llvm.intrinsic;
+
+alias uint pthread_t;
+extern (C) alias void (*__sighandler_t)(int);
+
+struct sigset_t
+{
+    uint __val[1024 / (8 * uint.sizeof)];
+}
+
+struct sigaction_t
+{
+    __sighandler_t sa_handler;
+    sigset_t sa_mask;
+    int sa_flags;
+    void (*sa_restorer)();
+}
+
+struct pthread_attr_t
+{
+    int __detachstate;
+    int __schedpolicy;
+    struct __schedparam
+    {
+	int __sched_priority;
+    }
+    int __inheritsched;
+    int __scope;
+    size_t __guardsize;
+    int __stackaddr_set;
+    void *__stackaddr;
+    size_t __stacksize;
+}
+
+unittest
+{
+    assert(sigset_t.sizeof  == 128);
+    assert(sigaction_t.sizeof == 140);
+    assert(sem_t.sizeof == 16);
+}
+
+extern (C)
+{
+    int pthread_create(pthread_t*, void*, void* (*)(void*), void*);
+    int pthread_join(pthread_t, void**);
+    int pthread_kill(pthread_t, int);
+    pthread_t pthread_self();
+    int pthread_equal(pthread_t, pthread_t);
+    int pthread_attr_init(pthread_attr_t*);
+    int pthread_attr_setstacksize(pthread_attr_t *, size_t);
+    int pthread_cancel(pthread_t);
+    int pthread_setcancelstate(int, int*);
+    int pthread_setcanceltype(int, int*);
+    int sched_yield();
+    int sigfillset(sigset_t*);
+    int sigdelset(sigset_t*, int);
+    int sigaction(int, sigaction_t*, sigaction_t*);
+    int sigsuspend(sigset_t*);
+
+    enum
+    {
+	PTHREAD_CANCEL_ENABLE,
+	PTHREAD_CANCEL_DISABLE
+    }
+
+    enum
+    {
+	PTHREAD_CANCEL_DEFERRED,
+	PTHREAD_CANCEL_ASYNCHRONOUS
+    }
+}
+
+class ThreadError : Error
+{
+    this(char[] s)
+    {
+	super("Thread error: " ~ s);
+    }
+}
+
+class Thread
+{
+    // The optional stacksize parameter default value of 0 will cause threads
+    //  to be created with the default pthread size - Dave Fladebo
+    this(size_t stacksize = 0)
+    {
+	init(stacksize);
+    }
+
+    this(int (*fp)(void *), void *arg, size_t stacksize = 0)
+    {
+	this.fp = fp;
+	this.arg = arg;
+	init(stacksize);
+    }
+
+    this(int delegate() dg, size_t stacksize = 0)
+    {
+	this.dg = dg;
+	init(stacksize);
+    }
+
+    ~this()
+    {
+	pthread_cond_destroy(&waitCond);
+	pthread_mutex_destroy(&waitMtx);
+        if (state != TS.FINISHED)
+            pthread_detach(id);
+    }
+
+    pthread_t id;
+    void* stackBottom;
+    void* stackTop;
+
+    void start()
+    {
+	if (state != TS.INITIAL)
+	    error("already started");
+
+	synchronized (Thread.classinfo)
+	{
+	    for (int i = 0; 1; i++)
+	    {
+		if (i == allThreads.length)
+		    error("too many threads");
+		if (!allThreads[i])
+		{   allThreads[i] = this;
+		    idx = i;
+		    if (i >= allThreadsDim)
+			allThreadsDim = i + 1;
+		    break;
+		}
+	    }
+	    nthreads++;
+	}
+
+	state = TS.RUNNING;
+	//printf("creating thread x%x\n", this);
+	//result = pthread_create(&id, null, &threadstart, this);
+	// Create with thread attributes to allow non-default stack size - Dave Fladebo
+	int result = pthread_create(&id, &threadAttrs, &threadstart, cast(void*)this);
+	if (result)
+	{   state = TS.FINISHED;
+	    synchronized (Thread.classinfo) allThreads[idx] = null;
+	    idx = -1;
+	    error("failed to start");	// BUG: should report errno
+	}
+	//printf("t = x%x, id = %d\n", this, id);
+    }
+
+    int run()
+    {
+	if (fp)
+	    return fp(arg);
+	else if (dg)
+	    return dg();
+	assert(0);
+    }
+
+    void wait()
+    {
+	if (isSelf)
+	    error("wait on self");
+
+	if (state != TS.FINISHED)
+	{
+	    void *value;
+
+	    int result = pthread_join(id, &value);
+            state = TS.FINISHED;
+	    if (result)
+		error("failed to wait");
+	}
+    }
+
+    void wait(uint milliseconds)
+    {
+	// Implemented for POSIX systems by Dave Fladebo
+	if (isSelf)
+	    error("wait on self");
+	if (state != TS.FINISHED)
+	{
+	    timespec ts; 
+	    timeval  tv;
+
+	    pthread_mutex_lock(&waitMtx);
+	    gettimeofday(&tv, null);
+	    ts.tv_sec = cast(__time_t)tv.tv_sec + cast(__time_t)(milliseconds / 1_000);
+	    ts.tv_nsec = (tv.tv_usec * 1_000) + ((milliseconds % 1_000) * 1_000_000);
+	    if (ts.tv_nsec > 1_000_000_000)
+	    {
+		ts.tv_sec += 1;
+		ts.tv_nsec -= 1_000_000_000;
+	    }
+	    if (pthread_cond_timedwait(&waitCond, &waitMtx, &ts))
+	    {
+		int oldstate, oldtype;
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+
+		if (pthread_cancel(id))     // thread was not completed in the timeout period, cancel it
+		{
+		    pthread_mutex_unlock(&waitMtx);
+		    error("cannot terminate thread via timed wait");
+		}
+
+		pthread_setcancelstate(oldstate, null);
+		pthread_setcanceltype(oldtype, null);
+
+		state = TS.TERMINATED;
+                synchronized (Thread.classinfo)
+                {
+                    allThreads[idx] = null;
+                    idx = -1;
+                    nthreads--;
+                }
+
+		pthread_mutex_unlock(&waitMtx);
+	    }
+	    else
+	    {
+		pthread_mutex_unlock(&waitMtx);
+		wait();	// condition has been signalled as complete (see threadstart()), terminate normally
+	    }
+	}
+    }
+
+    enum TS
+    {
+	INITIAL,        // created
+	RUNNING,        // running
+	TERMINATED,     // execution finished
+        FINISHED        // pthread_join()'ed
+    }
+
+    TS getState()
+    {
+	return state;
+    }
+
+    enum PRIORITY
+    {
+	INCREASE,
+	DECREASE,
+	IDLE,
+	CRITICAL
+    }
+
+    void setPriority(PRIORITY p)
+    {
+	/+ not implemented
+	int nPriority;
+
+	switch (p)
+	{
+	    case PRIORITY.INCREASE:
+		nPriority = THREAD_PRIORITY_ABOVE_NORMAL;
+		break;
+	    case PRIORITY.DECREASE:
+		nPriority = THREAD_PRIORITY_BELOW_NORMAL;
+		break;
+	    case PRIORITY.IDLE:
+		nPriority = THREAD_PRIORITY_IDLE;
+		break;
+	    case PRIORITY.CRITICAL:
+		nPriority = THREAD_PRIORITY_TIME_CRITICAL;
+		break;
+	}
+
+	if (SetThreadPriority(hdl, nPriority) == THREAD_PRIORITY_ERROR_RETURN)
+	    error("set priority");
+	+/
+    }
+
+    int isSelf()
+    {
+	//printf("id = %d, self = %d\n", id, pthread_self());
+	return pthread_equal(pthread_self(), id);
+    }
+
+    static Thread getThis()
+    {
+	//printf("getThis(), allThreadsDim = %d\n", allThreadsDim);
+        pthread_t id = pthread_self();
+        //printf("id = %d\n", id);
+        for (int i = 0; i < allThreadsDim; i++)
+        {
+            Thread t = allThreads[i];
+            //printf("allThreads[%d] = x%x, id = %d\n", i, t, (t ? t.id : 0));
+            if (t && pthread_equal(id, t.id))
+            {
+                return t;
+            }
+        }
+	printf("didn't find it\n");
+	assert(null);
+    }
+
+    static Thread[] getAll()
+    {
+	synchronized (Thread.classinfo) return allThreads[0 .. allThreadsDim];
+    }
+
+    void pause()
+    {
+	if (state == TS.RUNNING)
+	{
+	    if (pthread_kill(id, SIGUSR1))
+		error("cannot pause");
+	    else
+		sem_wait(&flagSuspend);	// wait for acknowledgement
+	}
+	else
+	    error("cannot pause");
+    }
+
+    void resume()
+    {
+	if (state == TS.RUNNING)
+	{
+	    if (pthread_kill(id, SIGUSR2))
+		error("cannot resume");
+	}
+	else
+	    error("cannot resume");
+    }
+
+    static void pauseAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                pthread_t thisid = pthread_self();
+                int npause = 0;
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && !pthread_equal(thisid, t.id) && t.state == TS.RUNNING)
+                    {
+                        if (pthread_kill(t.id, SIGUSR1))
+                            t.error("cannot pause");
+                        else
+                            npause++;	// count of paused threads
+                    }
+                }
+
+                // Wait for each paused thread to acknowledge
+                while (npause--)
+                {
+                    sem_wait(&flagSuspend);
+                }
+            }
+        }
+    }
+
+    static void resumeAll()
+    {
+        synchronized (Thread.classinfo)
+        {
+            if (nthreads > 1)
+            {
+                pthread_t thisid = pthread_self();
+
+                for (int i = 0; i < allThreadsDim; i++)
+                {
+                    Thread t = allThreads[i];
+                    if (t && t.id != thisid && t.state == TS.RUNNING)
+                        t.resume();
+                }
+            }
+        }
+    }
+
+    static void yield()
+    {
+	sched_yield();
+    }
+
+    static uint nthreads = 1;
+
+  private:
+
+    static uint allThreadsDim;
+
+    // Set max to Windows equivalent for compatibility.
+    // pthread_create will fail gracefully if stack limit
+    // is reached prior to allThreads max.
+    static Thread[0x400] allThreads;
+
+    static sem_t flagSuspend;
+
+    TS state;
+    int idx = -1;			// index into allThreads[]
+    int flags = 0;
+
+    pthread_attr_t threadAttrs;
+    pthread_mutex_t waitMtx;
+    pthread_cond_t waitCond;
+
+    int (*fp)(void *);
+    void *arg;
+
+    int delegate() dg;
+
+    void error(char[] msg)
+    {
+	throw new ThreadError(msg);
+    }
+
+    void init(size_t stackSize)
+    {
+	// set to default values regardless
+	// passing this as the 2nd arg. for pthread_create()
+	// w/o setting an attribute is equivalent to passing null.
+	pthread_attr_init(&threadAttrs);
+	if (stackSize > 0)
+	{
+	    if (pthread_attr_setstacksize(&threadAttrs,stackSize))
+		error("cannot set stack size");
+	}
+
+	if (pthread_mutex_init(&waitMtx, null))
+	    error("cannot initialize wait mutex");
+
+	if (pthread_cond_init(&waitCond, null))
+	    error("cannot initialize wait condition");
+    }
+
+    /************************************************
+     * This is just a wrapper to interface between C rtl and Thread.run().
+     */
+
+    extern (C) static void *threadstart(void *p)
+    {
+	Thread t = cast(Thread)p;
+	int result;
+
+	debug (thread) printf("Starting thread x%x (%d)\n", t, t.idx);
+
+	// Need to set t.id here, because thread is off and running
+	// before pthread_create() sets it.
+	t.id = pthread_self();
+
+	t.stackBottom = getESP();
+	try
+	{
+	    if(t.state == TS.RUNNING)
+		pthread_cond_signal(&t.waitCond);     // signal the wait condition (see the timed wait function)
+	    result = t.run();
+	}
+	catch (Object o)
+	{
+	    fprintf(stderr, "Error: %.*s\n", o.toString());
+	    result = 1;
+	}
+
+	debug (thread) printf("Ending thread %d\n", t.idx);
+	t.state = TS.TERMINATED;
+        synchronized (Thread.classinfo)
+        {
+            allThreads[t.idx] = null;
+            t.idx = -1;
+            nthreads--;
+        }
+	return cast(void*)result;
+    }
+
+
+    /**************************************
+     * Create a Thread for global main().
+     */
+
+    public static void thread_init()
+    {
+	Thread t = new Thread();
+
+	t.state = TS.RUNNING;
+	t.id = pthread_self();
+
+	version (none)
+	{
+	    // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
+	    static void** libc_stack_end;
+
+	    if (libc_stack_end == libc_stack_end.init)
+	    {
+		void* handle = dlopen(null, RTLD_NOW);
+		libc_stack_end = cast(void **)dlsym(handle, "__libc_stack_end");
+		dlclose(handle);
+	    }
+	    t.stackBottom = *libc_stack_end;
+	}
+	else
+	{
+	    t.stackBottom = cast(void*)__libc_stack_end;
+	}
+
+	assert(!allThreads[0]);
+	allThreads[0] = t;
+	allThreadsDim = 1;
+	t.idx = 0;
+
+	/* Install signal handlers so we can suspend/resume threads
+	 */
+
+	int result;
+	sigaction_t sigact;
+	result = sigfillset(&sigact.sa_mask);
+	if (result)
+	    goto Lfail;
+	sigact.sa_handler = &pauseHandler;
+	result = sigaction(SIGUSR1, &sigact, null);
+	if (result)
+	    goto Lfail;
+	sigact.sa_handler = &resumeHandler;
+	result = sigaction(SIGUSR2, &sigact, null);
+	if (result)
+	    goto Lfail;
+
+	result = sem_init(&flagSuspend, 0, 0);
+	if (result)
+	    goto Lfail;
+
+	return;
+
+      Lfail:
+	t.error("cannot initialize threads");
+    }
+
+    /**********************************
+     * This gets called when a thread gets SIGUSR1.
+     */
+
+    extern (C) static void pauseHandler(int sig)
+    {	int result;
+
+	// Save all registers on the stack so they'll be scanned by the GC
+	version(none) asm
+	{
+	    pusha	;
+	}
+
+	assert(sig == SIGUSR1);
+
+	sigset_t sigmask;
+	result = sigfillset(&sigmask);
+	assert(result == 0);
+	result = sigdelset(&sigmask, SIGUSR2);
+	assert(result == 0);
+
+	Thread t = getThis();
+	t.stackTop = getESP();
+	t.flags &= ~1;
+	// Release the semaphore _after_ stackTop is set
+	sem_post(&flagSuspend);
+	while (1)
+	{
+	    sigsuspend(&sigmask);	// suspend until SIGUSR2
+	    if (t.flags & 1)		// ensure it was resumeHandler()
+		break;
+	}
+
+	// Restore all registers
+	version(none) asm
+	{
+	    popa	;
+	}
+    }
+
+    /**********************************
+     * This gets called when a thread gets SIGUSR2.
+     */
+
+    extern (C) static void resumeHandler(int sig)
+    {
+	Thread t = getThis();
+
+	t.flags |= 1;
+    }
+
+    public static void* getESP()
+    {
+    version(D_InlineAsm_X86)
+    {
+	asm
+	{   naked	;
+	    mov EAX,ESP	;
+	    ret		;
+	}
+    }
+    else
+    {
+        void* p = llvm_frameaddress(0);
+        assert(p !is null);
+        return p;
+    }
+    }
+}
+
+
+}
+
--- a/premake.lua	Fri Dec 28 23:52:40 2007 +0100
+++ b/premake.lua	Fri Jan 04 01:38:42 2008 +0100
@@ -24,7 +24,11 @@
 package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.cpp") }
 package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" }
 package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" }
-package.linkoptions = { "`llvm-config --libs all`", "`llvm-config --ldflags`" }
+package.linkoptions = {
+    -- long but it's faster than just 'all'
+    "`llvm-config --libs core asmparser bitreader bitwriter support target transformutils scalaropts ipo instrumentation x86 powerpc`",
+    "`llvm-config --ldflags`"
+}
 package.defines = { "IN_LLVM", "_DH" }
 package.config.Release.defines = { "LLVMD_NO_LOGGER" }
 package.config.Debug.buildoptions = { "-g -O0" }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/asm1.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,19 @@
+module asm1;
+
+void main()
+{
+    version(LLVM_InlineAsm_X86_64)
+    {
+        long x;
+        asm
+        {
+            mov RAX, 42L;
+            mov x, RAX;
+        }
+        printf("x = %ld\n", x);
+    }
+    else
+    {
+        static assert(0, "no llvm inline asm for this platform yet");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug79.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,9 @@
+module bug79;
+import std.c.linux.linux;
+void main()
+{
+    timespec ts; 
+    ts.tv_nsec -= 1;
+    //auto t = ts.tv_nsec - 1;
+    //t -= 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug80.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,10 @@
+module bug80;
+
+void main()
+{
+    byte b = 10;
+    int i = b += 2;
+    printf("byte=%d int=%d\n", b, i);
+    assert(b == 12);
+    assert(i == 12);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/calls1.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,65 @@
+module calls1;
+import std.stdarg;
+void main()
+{
+    {int a = byVal1(3);}
+    {int a = void; byRef1(a);}
+    {char[] c = void; refType(c);}
+    {char[] c = void; refTypeByRef(c);}
+    {S s = void; structByVal(s);}
+    {S s = void; structByRef(s);}
+    {S s = void; structByPtr(&s);}
+    {printf("c-varargs %d %d %d\n", 1,2,3);}
+    {int i=3; float f=24.7; dvararg(i,f);}
+    {char[] s = "hello"; dvarargRefTy(s);}
+    {char[] ss = "hello world!"; dvarargRefTy(ss);}
+}
+
+int byVal1(int a)
+{
+    return a;
+}
+
+void byRef1(ref int a)
+{
+    a = 3;
+}
+
+void refType(char[] s)
+{
+}
+
+void refTypeByRef(ref char[] s)
+{
+}
+
+struct S
+{
+    float f;
+    double d;
+    long l;
+    byte b;
+}
+
+void structByVal(S s)
+{
+}
+
+void structByRef(ref S s)
+{
+}
+
+void structByPtr(S* s)
+{
+}
+
+void dvararg(...)
+{
+    printf("%d %.1f\n", va_arg!(int)(_argptr), va_arg!(float)(_argptr));
+}
+
+void dvarargRefTy(...)
+{
+    char[] s = va_arg!(char[])(_argptr);
+    printf("%.*s\n", s.length, s.ptr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nested11.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,42 @@
+module nested11;
+
+void main()
+{
+    int i;
+
+    void f()
+    {
+        i++;
+
+        void g()
+        {
+            i++;
+
+            void h()
+            {
+                printf("i = %d\n", i);
+            }
+
+            h();
+        }
+
+        g();
+    }
+
+    f();
+    assert(i == 2);
+
+    void foo()
+    {
+        i = 42;
+    }
+
+    void bar()
+    {
+        foo();
+    }
+
+    bar();
+    printf("i = %d\n", i);
+    assert(i == 42);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nested12.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,21 @@
+module nested12;
+
+void main()
+{
+    func();
+}
+
+void func()
+{
+    void a(int i)
+    {
+        printf("%d\n", i);
+    }
+
+    void b()
+    {
+        a(42);
+    }
+
+    b();
+}
--- a/test/stdiotest.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/test/stdiotest.d	Fri Jan 04 01:38:42 2008 +0100
@@ -2,7 +2,27 @@
 
 import std.stdio;
 
+T typed(T)(T x)
+{
+    return x;
+}
+
 void main()
 {
-    writefln("hello world",42,'x');
+    /*char[] str = "hello";
+    writefln(str);
+
+    writefln("hello world");*/
+
+    char[] fmt = "%s";
+    writefln(2.0f);
+
+    /*{writefln(typed!(byte)(1));}
+    {writefln(typed!(short)(2));}
+    {writefln(typed!(int)(3));}
+    {writefln(typed!(long)(-4));}
+    {writefln(typed!(ulong)(5));}
+    {writefln("%f", typed!(float)(6));}
+    {writefln("%f", typed!(double)(7));}
+    {writefln("%f", typed!(real)(8));}*/
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/stdiotest2.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,22 @@
+module stdiotest2;
+import std.stdio;
+void main()
+{
+    int[4] v = [1,2,3,4];
+    {
+        writefln("%s", v);
+        {
+            int[] dv = v;
+            {writefln("%s", dv);}
+        }
+    }
+
+    {
+        writefln(v);
+        {
+            //int[] dv = v;
+            //{writefln(dv);}
+        }
+    }
+    //writefln(1,2,3,4.56,"hello",v);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/vararg5.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,12 @@
+module vararg5;
+import std.stdarg;
+void func(...)
+{
+    char[] str = va_arg!(char[])(_argptr);
+    {printf("%.*s\n", str.length, str.ptr);}
+}
+void main()
+{
+    char[] str = "hello";
+    func(str);
+}