[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... *
This commit is contained in:
Tomas Lindquist Olsen
2008-01-04 01:38:42 +01:00
parent 4428e47a66
commit bc08c6fcb1
44 changed files with 4587 additions and 592 deletions

View File

@@ -547,30 +547,27 @@ MATCH CondExp::implicitConvTo(Type *t)
*/
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 @@ Expression *Expression::castTo(Scope *sc, Type *t)
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 @@ Expression *Expression::castTo(Scope *sc, Type *t)
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 *Expression::castTo(Scope *sc, Type *t)
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 @@ Expression *NullExp::castTo(Scope *sc, Type *t)
}
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 *AddrExp::castTo(Scope *sc, Type *t)
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 @@ Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
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;

View File

@@ -1760,7 +1760,7 @@ Lagain:
em = s->isEnumMember();
if (em)
{
e = em->value;
e = em->value->copy();
e = e->semantic(sc);
return e;
}

View File

@@ -179,7 +179,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t)
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;
}

View File

@@ -57,7 +57,7 @@ Expression *interpret_aaValues(InterState *istate, Expressions *arguments);
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 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
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 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
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 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
{
/* 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 @@ Expression *Expression::interpret(InterState *istate)
{
#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 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d)
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 @@ Expression *DeclarationExp::interpret(InterState *istate)
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 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
*/
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 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
{
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 @@ Expression *CallExp::interpret(InterState *istate)
{
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 *CallExp::interpret(InterState *istate)
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());

View File

@@ -283,15 +283,15 @@ int runLINK()
* 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

View File

@@ -71,7 +71,7 @@ Global::Global()
copyright = "Copyright (c) 1999-2007 by Digital Mars and Tomas Lindquist Olsen";
written = "written by Walter Bright and Tomas Lindquist Olsen";
llvmdc_version = "0.1";
version = "v1.024";
version = "v1.025";
global.structalign = 8;
memset(&params, 0, sizeof(Param));
@@ -167,6 +167,7 @@ Usage:\n\
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
}
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";

View File

@@ -130,6 +130,7 @@ struct Param
char *data_layout;
char disassemble;
char llvmInline;
char llvmAnnotate;
};
struct Global

View File

@@ -5077,7 +5077,6 @@ Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Express
this->ident = ident;
this->storageClass = storageClass;
this->defaultArg = defaultArg;
this->llvmCopy = false;
this->vardecl = 0;
}

View File

@@ -692,7 +692,6 @@ struct Argument : Object
static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
// backend
bool llvmCopy;
VarDeclaration* vardecl;
};

View File

@@ -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 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype
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 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype
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 @@ void DtoDefineFunc(FuncDeclaration* fd)
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 @@ const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl)
}
//////////////////////////////////////////////////////////////////////////////////////////
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));
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -10,6 +10,9 @@ void DtoResolveFunction(FuncDeclaration* fdecl);
void DtoDeclareFunction(FuncDeclaration* fdecl);
void DtoDefineFunc(FuncDeclaration* fd);
DValue* DtoArgument(Argument* fnarg, Expression* argexp);
void DtoVariadicArgument(Expression* argexp, llvm::Value* dst);
void DtoMain();
#endif

View File

@@ -13,30 +13,30 @@ namespace Logger
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 @@ namespace Logger
}
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 @@ namespace Logger
}
void enable()
{
enabled = true;
_enabled = true;
}
void disable()
{
enabled = false;
_enabled = false;
}
bool enabled()
{
return _enabled;
}
void attention(const char* fmt,...)
{

View File

@@ -12,6 +12,7 @@ namespace Logger
void print(const char* fmt, ...);
void enable();
void disable();
bool enabled();
void attention(const char* fmt, ...);

View File

@@ -12,11 +12,22 @@ using namespace llvm;
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 @@ void llvmdc_optimize_module(Module* m, char lvl, bool doinline)
pm.add(createGlobalDCEPass());
}
// -O2
if (lvl >= 2)
{
pm.add(createIPConstantPropagationPass());
@@ -35,10 +47,12 @@ void llvmdc_optimize_module(Module* m, char lvl, bool doinline)
pm.add(createPruneEHPass());
}
// -inline
if (doinline) {
pm.add(createFunctionInliningPass());
}
// -O3
if (lvl >= 3)
{
pm.add(createArgumentPromotionPass());
@@ -73,8 +87,7 @@ void llvmdc_optimize_module(Module* m, char lvl, bool doinline)
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);
}

View File

@@ -7,6 +7,7 @@
#include <iostream>
#include "gen/llvm.h"
#include "llvm/InlineAsm.h"
#include "total.h"
#include "init.h"
@@ -129,6 +130,9 @@ void ExpStatement::toIR(IRState* p)
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 ExpStatement::toIR(IRState* p)
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 SynchronizedStatement::toIR(IRState* p)
//////////////////////////////////////////////////////////////////////////////
void AsmStatement::toIR(IRState* p)
{
Logger::println("AsmStatement::toIR(): %s", toChars());
LOG_SCOPE;
error("%s: inline asm is not yet implemented", loc.toChars());
fatal();
assert(!asmcode && !asmalign && !refparam && !naked && !regs);
Token* t = tokens;
assert(t);
std::string asmstr;
do {
Logger::println("token: %s", t->toChars());
asmstr.append(t->toChars());
asmstr.append(" ");
} while (t = t->next);
Logger::println("asm expr = '%s'", asmstr.c_str());
// create function type
std::vector<const llvm::Type*> args;
const llvm::FunctionType* fty = llvm::FunctionType::get(DtoSize_t(), args, false);
// create inline asm callee
llvm::InlineAsm* inasm = llvm::InlineAsm::get(fty, asmstr, "r,r", false);
assert(0);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
@@ -1004,7 +1041,7 @@ STUBST(Statement);
//STUBST(ExpStatement);
//STUBST(CompoundStatement);
//STUBST(ScopeStatement);
STUBST(AsmStatement);
//STUBST(AsmStatement);
//STUBST(TryCatchStatement);
//STUBST(TryFinallyStatement);
STUBST(VolatileStatement);

View File

@@ -120,10 +120,10 @@ llvm::GlobalVariable* DtoDwarfCompileUnit(Module* m, bool define)
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"));

View File

@@ -31,6 +31,7 @@
#include "gen/complex.h"
#include "gen/dvalue.h"
#include "gen/aa.h"
#include "gen/functions.h"
//////////////////////////////////////////////////////////////////////////////////////////
@@ -51,6 +52,9 @@ DValue* DeclarationExp::toElem(IRState* p)
}
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 @@ DValue* AddAssignExp::toElem(IRState* p)
}
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* MinAssignExp::toElem(IRState* p)
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 @@ DValue* MinAssignExp::toElem(IRState* p)
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 @@ DValue* CallExp::toElem(IRState* p)
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 @@ DValue* CallExp::toElem(IRState* p)
// 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 @@ DValue* CallExp::toElem(IRState* p)
}
// va arg function special argument passing
if (va_magic) {
if (va_magic)
{
size_t n = va_intrinsic ? arguments->dim : 1;
for (int i=0; i<n; i++,j++)
{
@@ -989,7 +1006,9 @@ DValue* CallExp::toElem(IRState* p)
}
}
// regular arguments
else {
else
{
// d variadic function?
if (tf->linkage == LINKd && tf->varargs == 1)
{
Logger::println("doing d-style variadic arguments");
@@ -997,53 +1016,71 @@ DValue* CallExp::toElem(IRState* p)
size_t nimplicit = j;
std::vector<const llvm::Type*> vtypes;
std::vector<llvm::Value*> vvalues;
std::vector<llvm::Value*> vtypeinfos;
for (int i=0; i<arguments->dim; i++) {
Argument* fnarg = Argument::getNth(tf->parameters, i);
// build struct with argument types
for (int i=0; i<arguments->dim; i++)
{
Expression* argexp = (Expression*)arguments->data[i];
vvalues.push_back(DtoArgument(NULL, fnarg, argexp));
vtypes.push_back(vvalues.back()->getType());
vtypes.push_back(DtoType(argexp->type));
}
const llvm::StructType* vtype = llvm::StructType::get(vtypes);
Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n';
llvm::Value* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
TypeInfoDeclaration* tidecl = argexp->type->getTypeInfoDeclaration();
DtoForceDeclareDsymbol(tidecl);
assert(tidecl->llvmValue);
vtypeinfos.push_back(tidecl->llvmValue);
// store arguments in the struct
for (int i=0; i<arguments->dim; i++)
{
Expression* argexp = (Expression*)arguments->data[i];
if (global.params.llvmAnnotate)
DtoAnnotation(argexp->toChars());
DtoVariadicArgument(argexp, DtoGEPi(mem,0,i,"tmp"));
}
const llvm::StructType* vtype = llvm::StructType::get(vtypes);
llvm::Value* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
for (unsigned i=0; i<vtype->getNumElements(); ++i)
p->ir->CreateStore(vvalues[i], DtoGEPi(mem,0,i,"tmp"));
//llvm::Constant* typeinfoparam = llvm::ConstantPointerNull::get(isaPointer(llfnty->getParamType(j)));
// 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 (unsigned i=0; i<vtype->getNumElements(); ++i) {
for (int i=0; i<arguments->dim; i++)
{
Expression* argexp = (Expression*)arguments->data[i];
TypeInfoDeclaration* tidecl = argexp->type->getTypeInfoDeclaration();
DtoForceDeclareDsymbol(tidecl);
assert(tidecl->llvmValue);
vtypeinfos.push_back(tidecl->llvmValue);
llvm::Value* v = p->ir->CreateBitCast(vtypeinfos[i], typeinfotype, "tmp");
p->ir->CreateStore(v, DtoGEPi(typeinfomem,0,i,"tmp"));
}
// put data in d-array
llvm::Value* typeinfoarrayparam = new llvm::AllocaInst(llfnty->getParamType(j)->getContainedType(0),"_arguments_array",p->topallocapoint());
p->ir->CreateStore(DtoConstSize_t(vtype->getNumElements()), DtoGEPi(typeinfoarrayparam,0,0,"tmp"));
llvm::Value* casttypeinfomem = p->ir->CreateBitCast(typeinfomem, llvm::PointerType::get(typeinfotype), "tmp");
p->ir->CreateStore(casttypeinfomem, DtoGEPi(typeinfoarrayparam,0,1,"tmp"));
// specify arguments
llargs[j] = typeinfoarrayparam;;
j++;
llargs[j] = p->ir->CreateBitCast(mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
j++;
llargs.resize(nimplicit+2);
}
// normal function
else {
Logger::println("doing normal arguments");
for (int i=0; i<arguments->dim; i++,j++) {
Argument* fnarg = Argument::getNth(tf->parameters, i);
llargs[j] = DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
if (global.params.llvmAnnotate)
DtoAnnotation(((Expression*)arguments->data[i])->toChars());
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
llargs[j] = argval->getRVal();
if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) {
llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
}
// this hack is necessary :/
if (dfn && dfn->func && dfn->func->llvmRunTimeHack) {
if (llfnty->getParamType(j) != NULL) {
@@ -1850,7 +1887,11 @@ DValue* NewExp::toElem(IRState* p)
{
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 @@ void obj_includelib(char*){}
AsmStatement::AsmStatement(Loc loc, Token *tokens) :
Statement(loc)
{
Logger::println("Ignoring AsmStatement");
this->tokens = tokens;
}
Statement *AsmStatement::syntaxCopy()
{

View File

@@ -673,156 +673,12 @@ void DtoAssert(llvm::Value* cond, Loc* loc, DValue* msg)
//////////////////////////////////////////////////////////////////////////////////////////
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 const llvm::Type* get_next_frame_ptr_type(Dsymbol* sc)
}
}
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 @@ static llvm::Value* get_frame_ptr_impl(VarDeclaration* vd, Dsymbol* sc, llvm::Va
{
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 @@ static llvm::Value* get_frame_ptr(VarDeclaration* vd)
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 @@ llvm::Value* DtoNestedVariable(VarDeclaration* vd)
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 @@ llvm::Value* DtoNestedVariable(VarDeclaration* vd)
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 @@ void DtoAssign(DValue* lhs, DValue* rhs)
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 @@ DValue* DtoCastInt(DValue* val, Type* _to)
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 @@ void DtoForceDefineDsymbol(Dsymbol* dsym)
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());
}

View File

@@ -41,10 +41,11 @@ llvm::Value* DtoRealloc(llvm::Value* ptr, llvm::Value* len);
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);
void DtoAnnotation(const char* str);
llvm::ConstantInt* DtoConstSize_t(size_t);
llvm::ConstantInt* DtoConstUint(unsigned i);
llvm::ConstantInt* DtoConstInt(int i);

View File

@@ -137,9 +137,7 @@ void Module::genobjfile()
}
// 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
{

View File

@@ -85,6 +85,7 @@
</ignoredoxygen>
</kdevdoctreeview>
<kdevfilecreate>
<filetypes/>
<useglobaltypes>
<type ext="cpp" />
<type ext="h" />
@@ -191,6 +192,10 @@
<filetype>*.c</filetype>
<filetype>*.cpp</filetype>
<filetype>*.d</filetype>
<filetype>*.di</filetype>
<filetype>build.sh</filetype>
<filetype>premake.lua</filetype>
<filetype>Doxyfile</filetype>
</filetypes>
<blacklist>
<path>dbgtypes.bc.cpp</path>

View File

@@ -1,4 +1,5 @@
# KDevelop Custom Project File List
Doxyfile
demos
demos/gl.d
demos/glfuncs.d
@@ -11,6 +12,7 @@ demos/ray.d
demos/sdl.d
demos/sdldemo1.d
dmd
dmd/Doxyfile
dmd/access.c
dmd/aggregate.h
dmd/array.c
@@ -137,6 +139,7 @@ gen/toobj.cpp
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/compiler.d
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/stdarg.d
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_Ashort.d
lphobos/typeinfo2/ti_C.d
lphobos/typeinfos1.d
lphobos/typeinfos2.d
premake.lua
runalltests.d
test
test/a.d
@@ -258,8 +264,8 @@ test/arrays6.d
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/bug75.d
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/multiarr4.d
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/static_ctor.d
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/vararg1.d
test/vararg2.d
test/vararg3.d
test/vararg4.d
test/vararg5.d
test/virtcall.d
test/with1.d
tester.d

View File

@@ -5,8 +5,8 @@ mkdir -p obj
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 @@ llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || ex
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"

151
lphobos/gc/gc.d Normal file
View File

@@ -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();
}
}

View File

@@ -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");
}
}

243
lphobos/gc/gcx.d Normal file
View File

@@ -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);
}
}

View File

@@ -4,10 +4,10 @@ module llvm.intrinsic;
/*
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();

View File

@@ -13,6 +13,7 @@ std.stdarg,
std.stdint,
std.stdio,
std.string,
std.thread,
std.traits,
std.uni,
std.utf,

1578
lphobos/std/conv.d Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -170,15 +170,12 @@ private TypeInfo primitiveTypeInfo(Mangle m)
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 @@ formattedPrint("The answer is %s:", x, 6);
*/
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 doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
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 doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
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 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
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 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
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 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
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 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
return;
}
//printf("primitive type\n");
while (1)
{
m2 = cast(Mangle)ti.classinfo.name[mi];
@@ -897,6 +902,7 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
continue;
default:
//printf("primitive type default handling\n");
TypeInfo ti2 = primitiveTypeInfo(m2);
if (!ti2)
goto Lerror;
@@ -1058,9 +1064,10 @@ void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
}
//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;

193
lphobos/std/gc.di Normal file
View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -1,44 +1,548 @@
// Written in the D programming language.
/* Written by Walter Bright and Andrei Alexandrescu
* www.digitalmars.com
* Placed in the Public Domain.
*/
/********************************
* Standard I/O functions that extend $(B std.c.stdio).
* $(B std.c.stdio) is automatically imported when importing
* $(B std.stdio).
* Macros:
* WIKI=Phobos/StdStdio
*/
module std.stdio;
import std.traits;
public import std.c.stdio;
void _writef(T)(T t) {
static if (is(T == char)) {
printf("%c", t);
import std.format;
import std.utf;
import std.string;
import std.gc;
import std.c.stdlib;
import std.c.string;
import std.c.stddef;
version (DigitalMars)
{
version (Windows)
{
// Specific to the way Digital Mars C does stdio
version = DIGITAL_MARS_STDIO;
}
else static if (is(T : char[])) {
printf("%.*s", t.length, t.ptr);
}
else static if (is(T : long)) {
printf("%ld", t);
}
else static if (is(T : ulong)) {
printf("%lu", t);
}
else static if (is(T : real)) {
printf("%f", t);
}
else static if (is(T : Object)) {
_writef(t.toString());
}
else static if(isArray!(T)) {
_writef('[');
if (t.length) {
_writef(t[0]);
foreach(v; t[1..$]) {
_writef(','); _writef(v);
}
}
_writef(']');
}
else static assert(0, "Cannot writef:"~T.tostring);
}
void writef(T...)(T t)
version (DIGITAL_MARS_STDIO)
{
foreach(v;t) _writef(v);
}
void writefln(T...)(T t)
else
{
writef(t, '\n');
// Specific to the way Gnu C does stdio
version = GCC_IO;
import std.c.linux.linux;
}
version (DIGITAL_MARS_STDIO)
{
extern (C)
{
/* **
* Digital Mars under-the-hood C I/O functions
*/
int _fputc_nlock(int, FILE*);
int _fputwc_nlock(int, FILE*);
int _fgetc_nlock(FILE*);
int _fgetwc_nlock(FILE*);
int __fp_lock(FILE*);
void __fp_unlock(FILE*);
}
alias _fputc_nlock FPUTC;
alias _fputwc_nlock FPUTWC;
alias _fgetc_nlock FGETC;
alias _fgetwc_nlock FGETWC;
alias __fp_lock FLOCK;
alias __fp_unlock FUNLOCK;
}
else version (GCC_IO)
{
/* **
* Gnu under-the-hood C I/O functions; see
* http://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html#I_002fO-on-Streams
*/
extern (C)
{
int fputc_unlocked(int, FILE*);
int fputwc_unlocked(wchar_t, FILE*);
int fgetc_unlocked(FILE*);
int fgetwc_unlocked(FILE*);
void flockfile(FILE*);
void funlockfile(FILE*);
ssize_t getline(char**, size_t*, FILE*);
ssize_t getdelim (char**, size_t*, int, FILE*);
}
alias fputc_unlocked FPUTC;
alias fputwc_unlocked FPUTWC;
alias fgetc_unlocked FGETC;
alias fgetwc_unlocked FGETWC;
alias flockfile FLOCK;
alias funlockfile FUNLOCK;
}
else
{
static assert(0, "unsupported C I/O system");
}
/*********************
* Thrown if I/O errors happen.
*/
class StdioException : Exception
{
uint errno; // operating system error code
this(char[] msg)
{
super(msg);
}
this(uint errno)
{ char* s = strerror(errno);
super(std.string.toString(s).dup);
}
static void opCall(char[] msg)
{
throw new StdioException(msg);
}
static void opCall()
{
throw new StdioException(getErrno());
}
}
private
void writefx(FILE* fp, TypeInfo[] arguments, void* argptr, int newline=false)
{ int orientation;
orientation = fwide(fp, 0);
/* Do the file stream locking at the outermost level
* rather than character by character.
*/
FLOCK(fp);
scope(exit) FUNLOCK(fp);
if (orientation <= 0) // byte orientation or no orientation
{
void putc(dchar c)
{
if (c <= 0x7F)
{
FPUTC(c, fp);
}
else
{ char[4] buf;
char[] b;
b = std.utf.toUTF8(buf, c);
for (size_t i = 0; i < b.length; i++)
FPUTC(b[i], fp);
}
}
std.format.doFormat(&putc, arguments, argptr);
if (newline)
FPUTC('\n', fp);
}
else if (orientation > 0) // wide orientation
{
version (Windows)
{
void putcw(dchar c)
{
assert(isValidDchar(c));
if (c <= 0xFFFF)
{
FPUTWC(c, fp);
}
else
{ wchar[2] buf;
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
FPUTWC(buf[0], fp);
FPUTWC(buf[1], fp);
}
}
}
else version (linux)
{
void putcw(dchar c)
{
FPUTWC(c, fp);
}
}
else
{
static assert(0);
}
std.format.doFormat(&putcw, arguments, argptr);
if (newline)
FPUTWC('\n', fp);
}
}
/***********************************
* Arguments are formatted per the
* $(LINK2 std_format.html#format-string, format strings)
* and written to $(B stdout).
*/
void writef(...)
{
writefx(stdout, _arguments, _argptr, 0);
}
/***********************************
* Same as $(B writef), but a newline is appended
* to the output.
*/
void writefln(...)
{
writefx(stdout, _arguments, _argptr, 1);
}
/***********************************
* Same as $(B writef), but output is sent to the
* stream fp instead of $(B stdout).
*/
void fwritef(FILE* fp, ...)
{
writefx(fp, _arguments, _argptr, 0);
}
/***********************************
* Same as $(B writefln), but output is sent to the
* stream fp instead of $(B stdout).
*/
void fwritefln(FILE* fp, ...)
{
writefx(fp, _arguments, _argptr, 1);
}
/**********************************
* Read line from stream fp.
* Returns:
* null for end of file,
* char[] for line read from fp, including terminating '\n'
* Params:
* fp = input stream
* Throws:
* $(B StdioException) on error
* Example:
* Reads $(B stdin) and writes it to $(B stdout).
---
import std.stdio;
int main()
{
char[] buf;
while ((buf = readln()) != null)
writef("%s", buf);
return 0;
}
---
*/
char[] readln(FILE* fp = stdin)
{
char[] buf;
readln(fp, buf);
return buf;
}
/**********************************
* Read line from stream fp and write it to buf[],
* including terminating '\n'.
*
* This is often faster than readln(FILE*) because the buffer
* is reused each call. Note that reusing the buffer means that
* the previous contents of it need to be copied if needed.
* Params:
* fp = input stream
* buf = buffer used to store the resulting line data. buf
* is resized as necessary.
* Returns:
* 0 for end of file, otherwise
* number of characters read
* Throws:
* $(B StdioException) on error
* Example:
* Reads $(B stdin) and writes it to $(B stdout).
---
import std.stdio;
int main()
{
char[] buf;
while (readln(stdin, buf))
writef("%s", buf);
return 0;
}
---
*/
size_t readln(FILE* fp, inout char[] buf)
{
version (DIGITAL_MARS_STDIO)
{
FLOCK(fp);
scope(exit) FUNLOCK(fp);
if (__fhnd_info[fp._file] & FHND_WCHAR)
{ /* Stream is in wide characters.
* Read them and convert to chars.
*/
static assert(wchar_t.sizeof == 2);
buf.length = 0;
int c2;
for (int c; (c = FGETWC(fp)) != -1; )
{
if ((c & ~0x7F) == 0)
{ buf ~= c;
if (c == '\n')
break;
}
else
{
if (c >= 0xD800 && c <= 0xDBFF)
{
if ((c2 = FGETWC(fp)) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
}
c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
}
std.utf.encode(buf, c);
}
}
if (ferror(fp))
StdioException();
return buf.length;
}
auto sz = std.gc.capacity(buf.ptr);
//auto sz = buf.length;
buf = buf.ptr[0 .. sz];
if (fp._flag & _IONBF)
{
/* Use this for unbuffered I/O, when running
* across buffer boundaries, or for any but the common
* cases.
*/
L1:
char *p;
if (sz)
{
p = buf.ptr;
}
else
{
sz = 64;
p = cast(char*) std.gc.malloc(sz);
std.gc.hasNoPointers(p);
buf = p[0 .. sz];
}
size_t i = 0;
for (int c; (c = FGETC(fp)) != -1; )
{
if ((p[i] = c) != '\n')
{
i++;
if (i < sz)
continue;
buf = p[0 .. i] ~ readln(fp);
return buf.length;
}
else
{
buf = p[0 .. i + 1];
return i + 1;
}
}
if (ferror(fp))
StdioException();
buf = p[0 .. i];
return i;
}
else
{
int u = fp._cnt;
char* p = fp._ptr;
int i;
if (fp._flag & _IOTRAN)
{ /* Translated mode ignores \r and treats ^Z as end-of-file
*/
char c;
while (1)
{
if (i == u) // if end of buffer
goto L1; // give up
c = p[i];
i++;
if (c != '\r')
{
if (c == '\n')
break;
if (c != 0x1A)
continue;
goto L1;
}
else
{ if (i != u && p[i] == '\n')
break;
goto L1;
}
}
if (i > sz)
{
buf = cast(char[])std.gc.malloc(i);
std.gc.hasNoPointers(buf.ptr);
}
if (i - 1)
memcpy(buf.ptr, p, i - 1);
buf[i - 1] = '\n';
if (c == '\r')
i++;
}
else
{
while (1)
{
if (i == u) // if end of buffer
goto L1; // give up
auto c = p[i];
i++;
if (c == '\n')
break;
}
if (i > sz)
{
buf = cast(char[])std.gc.malloc(i);
std.gc.hasNoPointers(buf.ptr);
}
memcpy(buf.ptr, p, i);
}
fp._cnt -= i;
fp._ptr += i;
buf = buf[0 .. i];
return i;
}
}
else version (GCC_IO)
{
if (fwide(fp, 0) > 0)
{ /* Stream is in wide characters.
* Read them and convert to chars.
*/
FLOCK(fp);
scope(exit) FUNLOCK(fp);
version (Windows)
{
buf.length = 0;
int c2;
for (int c; (c = FGETWC(fp)) != -1; )
{
if ((c & ~0x7F) == 0)
{ buf ~= c;
if (c == '\n')
break;
}
else
{
if (c >= 0xD800 && c <= 0xDBFF)
{
if ((c2 = FGETWC(fp)) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
}
c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
}
std.utf.encode(buf, c);
}
}
if (ferror(fp))
StdioException();
return buf.length;
}
else version (linux)
{
buf.length = 0;
for (int c; (c = FGETWC(fp)) != -1; )
{
if ((c & ~0x7F) == 0)
buf ~= c;
else
std.utf.encode(buf, cast(dchar)c);
if (c == '\n')
break;
}
if (ferror(fp))
StdioException();
return buf.length;
}
else
{
static assert(0);
}
}
char *lineptr = null;
size_t n = 0;
auto s = getdelim(&lineptr, &n, '\n', fp);
scope(exit) free(lineptr);
if (s < 0)
{
if (ferror(fp))
StdioException();
buf.length = 0; // end of file
return 0;
}
buf = buf.ptr[0 .. std.gc.capacity(buf.ptr)];
if (s <= buf.length)
{
buf.length = s;
buf[] = lineptr[0 .. s];
}
else
{
buf = lineptr[0 .. s].dup;
}
return s;
}
else
{
static assert(0);
}
}
/** ditto */
size_t readln(inout char[] buf)
{
return readln(stdin, buf);
}

1127
lphobos/std/thread.d Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,11 @@ package.language = "c++"
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" }

19
test/asm1.d Normal file
View File

@@ -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");
}
}

9
test/bug79.d Normal file
View File

@@ -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;
}

10
test/bug80.d Normal file
View File

@@ -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);
}

65
test/calls1.d Normal file
View File

@@ -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);
}

42
test/nested11.d Normal file
View File

@@ -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);
}

21
test/nested12.d Normal file
View File

@@ -0,0 +1,21 @@
module nested12;
void main()
{
func();
}
void func()
{
void a(int i)
{
printf("%d\n", i);
}
void b()
{
a(42);
}
b();
}

View File

@@ -2,7 +2,27 @@ module stdiotest;
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));}*/
}

22
test/stdiotest2.d Normal file
View File

@@ -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);
}

12
test/vararg5.d Normal file
View File

@@ -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);
}