# HG changeset patch # User lindquist # Date 1199407122 -3600 # Node ID 5825d48b27d15f51dbf65bf04fd3792baa1de9b6 # Parent a7dfa0ed966cb7d32413fa4eb1efa88031d577e9 [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... * diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/cast.c --- 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; diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/expression.c --- 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; } diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/init.c --- 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; } diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/interpret.c --- 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()); diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/link.c --- 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 diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/mars.c --- 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(¶ms, 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"; diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/mars.h --- 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 diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/mtype.c --- 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; } diff -r a7dfa0ed966c -r 5825d48b27d1 dmd/mtype.h --- 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; }; diff -r a7dfa0ed966c -r 5825d48b27d1 gen/functions.cpp --- 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)); +} + +////////////////////////////////////////////////////////////////////////////////////////// diff -r a7dfa0ed966c -r 5825d48b27d1 gen/functions.h --- 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 diff -r a7dfa0ed966c -r 5825d48b27d1 gen/logger.cpp --- 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,...) { diff -r a7dfa0ed966c -r 5825d48b27d1 gen/logger.h --- 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, ...); diff -r a7dfa0ed966c -r 5825d48b27d1 gen/optimizer.cpp --- 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); } diff -r a7dfa0ed966c -r 5825d48b27d1 gen/statements.cpp --- 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 #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 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); diff -r a7dfa0ed966c -r 5825d48b27d1 gen/todebug.cpp --- 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")); diff -r a7dfa0ed966c -r 5825d48b27d1 gen/toir.cpp --- 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; ilinkage == LINKd && tf->varargs == 1) { Logger::println("doing d-style variadic arguments"); @@ -997,53 +1016,71 @@ size_t nimplicit = j; std::vector vtypes; - std::vector vvalues; std::vector vtypeinfos; - for (int i=0; idim; i++) { - Argument* fnarg = Argument::getNth(tf->parameters, i); + // build struct with argument types + for (int i=0; idim; i++) + { + Expression* argexp = (Expression*)arguments->data[i]; + 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; idim; i++) + { Expression* argexp = (Expression*)arguments->data[i]; - vvalues.push_back(DtoArgument(NULL, fnarg, argexp)); - vtypes.push_back(vvalues.back()->getType()); - + 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; idim; 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; igetNumElements(); ++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; igetNumElements(); ++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; idim; 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() { diff -r a7dfa0ed966c -r 5825d48b27d1 gen/tollvm.cpp --- 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()); +} diff -r a7dfa0ed966c -r 5825d48b27d1 gen/tollvm.h --- 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); diff -r a7dfa0ed966c -r 5825d48b27d1 gen/toobj.cpp --- 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 { diff -r a7dfa0ed966c -r 5825d48b27d1 llvmdc.kdevelop --- 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 @@ + @@ -191,6 +192,10 @@ *.c *.cpp *.d + *.di + build.sh + premake.lua + Doxyfile dbgtypes.bc.cpp diff -r a7dfa0ed966c -r 5825d48b27d1 llvmdc.kdevelop.filelist --- 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 diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/build.sh --- 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" diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/gc/gc.d --- /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(); +} + +} diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/gc/gcstub.d --- 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"); - } -} diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/gc/gcx.d --- /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); + } +} diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/llvm/intrinsic.d --- 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(); diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/phobos.d --- 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, diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/conv.d --- /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 + * atoi() and atol() by + * checking for overflow and not allowing whitespace. + * + * For conversion to signed types, the grammar recognized is: + *
+$(I Integer):
+    $(I Sign UnsignedInteger)
+    $(I UnsignedInteger)
+
+$(I Sign):
+    $(B +)
+    $(B -)
+ * 
+ * For conversion to signed types, the grammar recognized is: + *
+$(I UnsignedInteger):
+    $(I DecimalDigit)
+    $(I DecimalDigit) $(I UnsignedInteger)
+ * 
+ * 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); +} + diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/format.d --- 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; diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/gc.di --- /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(); +} diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/stdarg.d --- 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; } diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/stdio.d --- 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; + +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; + } +} -void _writef(T)(T t) { - static if (is(T == char)) { - printf("%c", t); +version (DIGITAL_MARS_STDIO) +{ +} +else +{ + // 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*); } - else static if (is(T : char[])) { - printf("%.*s", t.length, t.ptr); + 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*); } - else static if (is(T : long)) { - printf("%ld", t); + + 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); } - else static if (is(T : ulong)) { - printf("%lu", t); + + 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()); } - else static if (is(T : real)) { - printf("%f", t); +} + +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 static if (is(T : Object)) { - _writef(t.toString()); + 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); } - 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); +} + + +/*********************************** + * 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; } -void writef(T...)(T t) +/********************************** + * 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() { - foreach(v;t) _writef(v); + char[] buf; + while (readln(stdin, buf)) + writef("%s", buf); + return 0; } -void writefln(T...)(T t) +--- + */ +size_t readln(FILE* fp, inout char[] buf) { - writef(t, '\n'); + 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); +} + diff -r a7dfa0ed966c -r 5825d48b27d1 lphobos/std/thread.d --- /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; + } + } +} + + +} + diff -r a7dfa0ed966c -r 5825d48b27d1 premake.lua --- 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" } diff -r a7dfa0ed966c -r 5825d48b27d1 test/asm1.d --- /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"); + } +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/bug79.d --- /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; +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/bug80.d --- /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); +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/calls1.d --- /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); +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/nested11.d --- /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); +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/nested12.d --- /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(); +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/stdiotest.d --- 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));}*/ } diff -r a7dfa0ed966c -r 5825d48b27d1 test/stdiotest2.d --- /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); +} diff -r a7dfa0ed966c -r 5825d48b27d1 test/vararg5.d --- /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); +}