# HG changeset patch # User lindquist # Date 1194339794 -3600 # Node ID 058d3925950e4cdeefcfdf44617d4c3a61397c49 # Parent 25d4fcce53f4c1cc666fd8c5eb77f50d3326e63a [svn r92] Fixed support for statically initialized unions. lots of bugfixes as cleanups too. diff -r 25d4fcce53f4 -r 058d3925950e dmd/aggregate.h --- a/dmd/aggregate.h Sat Nov 03 14:48:33 2007 +0100 +++ b/dmd/aggregate.h Tue Nov 06 10:03:14 2007 +0100 @@ -45,6 +45,8 @@ class ConstantStruct; } +struct DUnion; + struct AggregateDeclaration : ScopeDsymbol { Type *type; @@ -104,6 +106,7 @@ llvm::ConstantStruct* llvmConstVtbl; llvm::Constant* llvmInitZ; bool llvmHasUnions; + DUnion* llvmUnion; AggregateDeclaration *isAggregateDeclaration() { return this; } }; diff -r 25d4fcce53f4 -r 058d3925950e dmd/struct.c --- a/dmd/struct.c Sat Nov 03 14:48:33 2007 +0100 +++ b/dmd/struct.c Tue Nov 06 10:03:14 2007 +0100 @@ -51,6 +51,7 @@ llvmInitZ = NULL; llvmInProgress = false; llvmHasUnions = false; + llvmUnion = NULL; } enum PROT AggregateDeclaration::prot() diff -r 25d4fcce53f4 -r 058d3925950e gen/arrays.cpp --- a/gen/arrays.cpp Sat Nov 03 14:48:33 2007 +0100 +++ b/gen/arrays.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -251,41 +251,59 @@ ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit) { - Logger::println("arr init begin"); + Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); + LOG_SCOPE; + Type* arrinittype = DtoDType(arrinit->type); Type* t; integer_t tdim; if (arrinittype->ty == Tsarray) { + Logger::println("static array"); TypeSArray* tsa = (TypeSArray*)arrinittype; tdim = tsa->dim->toInteger(); t = tsa; } else if (arrinittype->ty == Tarray) { + Logger::println("dynamic array"); t = arrinittype; tdim = arrinit->dim; } else assert(0); - std::vector inits(tdim, 0); + Logger::println("dim = %u", tdim); + + std::vector inits(tdim, NULL); const llvm::Type* elemty = DtoType(arrinittype->next); assert(arrinit->index.dim == arrinit->value.dim); - for (int i=0,j=0; i < tdim; ++i) + for (unsigned i=0,j=0; i < tdim; ++i) { Initializer* init = 0; Expression* idx = (Expression*)arrinit->index.data[j]; if (idx) { - integer_t k = idx->toInteger(); - if (i == k) - { - init = (Initializer*)arrinit->value.data[j]; - assert(init); - ++j; + // this is pretty weird :/ idx->type turned out NULL for the initializer: + // const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; + // in std.c.linux.socket + if (idx->type) { + //integer_t k = idx->toInteger(); + Logger::println("getting value for exp: %s | %s", idx->toChars(), idx->type->toChars()); + llvm::Constant* cc = idx->toConstElem(gIR); + Logger::println("value gotten"); + assert(cc != NULL); + llvm::ConstantInt* ci = llvm::dyn_cast(cc); + assert(ci != NULL); + uint64_t k = ci->getZExtValue(); + if (i == k) + { + init = (Initializer*)arrinit->value.data[j]; + assert(init); + ++j; + } } } else @@ -294,29 +312,7 @@ ++j; } - llvm::Constant* v = 0; - - if (!init) - { - v = t->next->defaultInit()->toConstElem(gIR); - } - else if (ExpInitializer* ex = init->isExpInitializer()) - { - v = ex->exp->toConstElem(gIR); - } - else if (StructInitializer* si = init->isStructInitializer()) - { - v = DtoConstStructInitializer(si); - } - else if (ArrayInitializer* ai = init->isArrayInitializer()) - { - v = DtoConstArrayInitializer(ai); - } - else if (init->isVoidInitializer()) - { - v = llvm::UndefValue::get(elemty); - } - else + llvm::Constant* v = DtoConstInitializer(t->next, init); assert(v); inits[i] = v; diff -r 25d4fcce53f4 -r 058d3925950e gen/dvalue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/dvalue.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,101 @@ +#include "gen/llvm.h" + +#include "declaration.h" + +#include "gen/tollvm.h" +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/dvalue.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// + +DVarValue::DVarValue(VarDeclaration* vd, llvm::Value* llvmValue, bool lvalue) +{ + var = vd; + val = llvmValue; + rval = 0; + lval = lvalue; + type = var->type; +} + +DVarValue::DVarValue(Type* t, llvm::Value* lv, llvm::Value* rv) +{ + var = 0; + val = lv; + rval = rv; + lval = true; + type = t; +} + +DVarValue::DVarValue(Type* t, llvm::Value* llvmValue, bool lvalue) +{ + var = 0; + val = llvmValue; + rval = 0; + lval = lvalue; + type = t; +} + +llvm::Value* DVarValue::getLVal() +{ + assert(val && lval); + return val; +} + +llvm::Value* DVarValue::getRVal() +{ + assert(rval || val); + if (DtoIsPassedByRef(type)) { + if (rval) return rval; + return val; + } + else { + if (rval) return rval; + Logger::cout() << "val: " << *val << '\n'; + if (llvm::isa(val)) { + if (var && (var->isRef() || var->isOut())) + return DtoLoad(val); + } + else if (!isField() && DtoCanLoad(val)) { + return DtoLoad(val); + } + return val; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// + +DFuncValue::DFuncValue(FuncDeclaration* fd, llvm::Value* v, llvm::Value* vt) +{ + func = fd; + type = func->type; + val = v; + vthis = vt; + cc = (unsigned)-1; +} + +llvm::Value* DFuncValue::getLVal() +{ + assert(0); + return 0; +} + +llvm::Value* DFuncValue::getRVal() +{ + assert(val); + return val; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* DConstValue::getRVal() +{ + assert(c); + return c; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// diff -r 25d4fcce53f4 -r 058d3925950e gen/dvalue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/dvalue.h Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,193 @@ +#ifndef LLVMDC_GEN_DVALUE_H +#define LLVMDC_GEN_DVALUE_H + +/* +These classes are used for generating the IR. They encapsulate D values and +provide a common interface to the most common operations. When more specialized +handling is necessary, they hold enough information to do-the-right-thing (TM) +*/ + +#include +#include "root.h" + +struct Type; +struct Dsymbol; +struct VarDeclaration; +struct FuncDeclaration; + +namespace llvm +{ + class Value; + class Type; + class Constant; +} + +struct DImValue; +struct DConstValue; +struct DNullValue; +struct DVarValue; +struct DFieldValue; +struct DThisValue; +struct DFuncValue; +struct DSliceValue; +struct DArrayLenValue; +struct DLValueCast; + +// base class for d-values +struct DValue : Object +{ + virtual Type* getType() = 0; + + virtual llvm::Value* getLVal() { assert(0); return 0; } + virtual llvm::Value* getRVal() { assert(0); return 0; } + + virtual DImValue* isIm() { return NULL; } + virtual DConstValue* isConst() { return NULL; } + virtual DNullValue* isNull() { return NULL; } + virtual DVarValue* isVar() { return NULL; } + virtual DFieldValue* isField() { return NULL; } + virtual DThisValue* isThis() { return NULL; } + virtual DSliceValue* isSlice() { return NULL; } + virtual DFuncValue* isFunc() { return NULL; } + virtual DArrayLenValue* isArrayLen() { return NULL; } + virtual DLValueCast* isLValueCast() { return NULL; } + + virtual bool inPlace() { return false; } + +protected: + DValue() {} + DValue(const DValue&) { } + DValue& operator=(const DValue&) { return *this; } +}; + +// immediate d-value +struct DImValue : DValue +{ + Type* type; + llvm::Value* val; + bool inplace; + + DImValue(Type* t, llvm::Value* v, bool i = false) { type = t; val = v; inplace = i; } + + virtual llvm::Value* getRVal() { assert(val); return val; } + + virtual Type* getType() { assert(type); return type; } + virtual DImValue* isIm() { return this; } + + virtual bool inPlace() { return inplace; } +}; + +// constant d-value +struct DConstValue : DValue +{ + Type* type; + llvm::Constant* c; + + DConstValue(Type* t, llvm::Constant* con) { type = t; c = con; } + + virtual llvm::Value* getRVal(); + + virtual Type* getType() { assert(type); return type; } + virtual DConstValue* isConst() { return this; } +}; + +// null d-value +struct DNullValue : DConstValue +{ + DNullValue(Type* t, llvm::Constant* con) : DConstValue(t,con) {} + virtual DNullValue* isNull() { return this; } +}; + +// variable d-value +struct DVarValue : DValue +{ + Type* type; + VarDeclaration* var; + llvm::Value* val; + llvm::Value* rval; + bool lval; + + DVarValue(VarDeclaration* vd, llvm::Value* llvmValue, bool lvalue); + DVarValue(Type* vd, llvm::Value* lv, llvm::Value* rv); + DVarValue(Type* t, llvm::Value* llvmValue, bool lvalue); + + virtual llvm::Value* getLVal(); + virtual llvm::Value* getRVal(); + + virtual Type* getType() { assert(type); return type; } + virtual DVarValue* isVar() { return this; } +}; + +// field d-value +struct DFieldValue : DVarValue +{ + DFieldValue(Type* t, llvm::Value* llvmValue, bool l) : DVarValue(t, llvmValue, l) {} + virtual DFieldValue* isField() { return this; } +}; + +// this d-value +struct DThisValue : DVarValue +{ + DThisValue(VarDeclaration* vd, llvm::Value* llvmValue) : DVarValue(vd, llvmValue, true) {} + virtual DThisValue* isThis() { return this; } +}; + +// array length d-value +struct DArrayLenValue : DVarValue +{ + DArrayLenValue(Type* t, llvm::Value* llvmValue) : DVarValue(t, llvmValue, true) {} + virtual DArrayLenValue* isArrayLen() { return this; } +}; + +// slice d-value +struct DSliceValue : DValue +{ + Type* type; + llvm::Value* len; + llvm::Value* ptr; + + DSliceValue(Type* t, llvm::Value* l, llvm::Value* p) { type=t; ptr=p; len=l; } + + virtual Type* getType() { assert(type); return type; } + virtual DSliceValue* isSlice() { return this; } +}; + +// function d-value +struct DFuncValue : DValue +{ + Type* type; + FuncDeclaration* func; + llvm::Value* val; + llvm::Value* vthis; + unsigned cc; + + DFuncValue(FuncDeclaration* fd, llvm::Value* v, llvm::Value* vt = 0); + + virtual llvm::Value* getLVal(); + virtual llvm::Value* getRVal(); + + virtual Type* getType() { assert(type); return type; } + virtual DFuncValue* isFunc() { return this; } +}; + +// l-value cast d-value +struct DLValueCast : DValue +{ + Type* type; + llvm::Value* lval; + llvm::Value* rval; + + DLValueCast(Type* t, llvm::Value* l, llvm::Value* r) { + type = t; + lval = l; + rval = r; + } + + virtual llvm::Value* getLVal() { assert(lval); return lval; } + virtual llvm::Value* getRVal() { assert(rval); return rval; } + + virtual Type* getType() { assert(type); return type; } + virtual DLValueCast* isLValueCast() { return this; } +}; + +#endif // LLVMDC_GEN_DVALUE_H diff -r 25d4fcce53f4 -r 058d3925950e gen/structs.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/structs.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,319 @@ +#include + +#include "gen/llvm.h" + +#include "mtype.h" +#include "aggregate.h" +#include "init.h" +#include "declaration.h" + +#include "gen/irstate.h" +#include "gen/tollvm.h" +#include "gen/arrays.h" +#include "gen/logger.h" +#include "gen/structs.h" + +////////////////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* DtoStructType(Type* t) +{ + assert(0); + std::vector types; + return llvm::StructType::get(types); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* DtoStructZeroInit(llvm::Value* v) +{ + assert(gIR); + uint64_t n = gTargetData->getTypeSize(v->getType()->getContainedType(0)); + //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); + llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemSet32(); + std::vector llargs; + llargs.resize(4); + llargs[0] = sarr; + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false); + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src) +{ + Logger::cout() << "dst = " << *dst << " src = " << *src << '\n'; + assert(dst->getType() == src->getType()); + assert(gIR); + + uint64_t n = gTargetData->getTypeSize(dst->getType()->getContainedType(0)); + //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Constant* DtoConstStructInitializer(StructInitializer* si) +{ + Logger::println("DtoConstStructInitializer: %s", si->toChars()); + LOG_SCOPE; + + const llvm::StructType* structtype = llvm::cast(si->ad->llvmType); + Logger::cout() << "llvm struct type: " << *structtype << '\n'; + + assert(si->value.dim == si->vars.dim); + + std::vector inits; + for (int i = 0; i < si->value.dim; ++i) + { + Initializer* ini = (Initializer*)si->value.data[i]; + assert(ini); + VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; + assert(vd); + llvm::Constant* v = DtoConstInitializer(vd->type, ini); + inits.push_back(DUnionIdx(vd->llvmFieldIndex, vd->llvmFieldIndexOffset, v)); + } + + return si->ad->llvmUnion->getConst(inits); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs) +{ + Logger::println("checking for offset %u type %s:", os, t->toChars()); + LOG_SCOPE; + + if (idxs.empty()) + idxs.push_back(0); + + const llvm::Type* llt = llvm::PointerType::get(DtoType(t)); + const llvm::Type* st = llvm::PointerType::get(DtoType(sd->type)); + if (ptr->getType() != st) { + assert(sd->llvmHasUnions); + ptr = gIR->ir->CreateBitCast(ptr, st, "tmp"); + } + + for (unsigned i=0; ifields.dim; ++i) { + VarDeclaration* vd = (VarDeclaration*)sd->fields.data[i]; + Type* vdtype = DtoDType(vd->type); + Logger::println("found %u type %s", vd->offset, vdtype->toChars()); + assert(vd->llvmFieldIndex >= 0); + if (os == vd->offset && vdtype == t) { + idxs.push_back(vd->llvmFieldIndex); + ptr = DtoGEP(ptr, idxs, "tmp"); + if (ptr->getType() != llt) + ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); + if (vd->llvmFieldIndexOffset) + ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); + return ptr; + } + else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) { + TypeStruct* ts = (TypeStruct*)vdtype; + StructDeclaration* ssd = ts->sym; + idxs.push_back(vd->llvmFieldIndex); + if (vd->llvmFieldIndexOffset) { + Logger::println("has union field offset"); + ptr = DtoGEP(ptr, idxs, "tmp"); + if (ptr->getType() != llt) + ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); + ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); + std::vector tmp; + return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); + } + else { + const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type)); + if (ptr->getType() != sty) { + ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp"); + std::vector tmp; + return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); + } + else { + return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs); + } + } + } + } + + size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0)); + assert(os % llt_sz == 0); + ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); + return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); +} +////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// D UNION HELPER CLASS //////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +DUnion::DUnion() +{ + DUnionField* f = NULL; + IRStruct& topstruct = gIR->topstruct(); + bool unions = false; + for (IRStruct::OffsetMap::iterator i=topstruct.offsets.begin(); i!=topstruct.offsets.end(); ++i) + { + unsigned o = i->first; + IRStruct::Offset* so = &i->second; + const llvm::Type* ft = so->init->getType(); + size_t sz = gTargetData->getTypeSize(ft); + if (f == NULL) { // new field + fields.push_back(DUnionField()); + f = &fields.back(); + f->size = sz; + f->offset = o; + f->init = so->init; + f->initsize = sz; + f->types.push_back(ft); + } + else if (o == f->offset) { // same offset + if (sz > f->size) + f->size = sz; + f->types.push_back(ft); + unions = true; + } + else if (o < f->offset+f->size) { + assert((o+sz) <= (f->offset+f->size)); + unions = true; + } + else { + fields.push_back(DUnionField()); + f = &fields.back(); + f->size = sz; + f->offset = o; + f->init = so->init; + f->initsize = sz; + f->types.push_back(ft); + } + } + + { + LOG_SCOPE; + Logger::println("******** DUnion BEGIN"); + size_t n = fields.size(); + for (size_t i=0; i& out) +{ + assert(nbytes > 0); + std::vector i(nbytes, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); + out.push_back(llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, nbytes), i)); +} + +llvm::Constant* DUnion::getConst(std::vector& in) +{ + std::sort(in.begin(), in.end()); + std::vector out; + + size_t nin = in.size(); + size_t nfields = fields.size(); + + size_t fi = 0; + size_t last = 0; + size_t ii = 0; + size_t os = 0; + + for(;;) + { + if (fi == nfields) break; + + bool nextSame = (ii+1 < nin) && (in[ii+1].idx == fi); + + if (ii < nin && fi == in[ii].idx) + { + size_t s = gTargetData->getTypeSize(in[ii].c->getType()); + if (in[ii].idx == last) + { + size_t nos = in[ii].idxos * s; + if (nos && nos-os) { + assert(nos >= os); + push_nulls(nos-os, out); + } + os = nos + s; + } + else + { + os = s; + } + out.push_back(in[ii].c); + ii++; + if (!nextSame) + { + if (os < fields[fi].size) + push_nulls(fields[fi].size - os, out); + os = 0; + last = fi++; + } + continue; + } + + // default initialize if necessary + if (ii == nin || fi < in[ii].idx) + { + DUnionField& f = fields[fi]; + out.push_back(f.init); + if (f.initsize < f.size) + push_nulls(f.size - f.initsize, out); + last = fi++; + os = 0; + continue; + } + } + + std::vector tys; + size_t nout = out.size(); + for (size_t i=0; igetType()); + + const llvm::StructType* st = llvm::StructType::get(tys); + return llvm::ConstantStruct::get(st, out); +} + + + + + + + + + + + + + + + + + + + + + diff -r 25d4fcce53f4 -r 058d3925950e gen/structs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/structs.h Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,49 @@ +#ifndef LLVMD_GEN_STRUCTS_H +#define LLVMD_GEN_STRUCTS_H + +struct StructInitializer; +const llvm::Type* DtoStructType(Type* t); +llvm::Value* DtoStructZeroInit(llvm::Value* v); +llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src); +llvm::Constant* DtoConstStructInitializer(StructInitializer* si); +llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs); + +struct DUnionField +{ + unsigned offset; + size_t size; + std::vector types; + llvm::Constant* init; + size_t initsize; + + DUnionField() { + offset = 0; + size = 0; + init = NULL; + initsize = 0; + } +}; + +struct DUnionIdx +{ + unsigned idx,idxos; + llvm::Constant* c; + + DUnionIdx() + : idx(0), c(0) {} + DUnionIdx(unsigned _idx, unsigned _idxos, llvm::Constant* _c) + : idx(_idx), idxos(_idxos), c(_c) {} + bool operator<(const DUnionIdx& i) const { + return (idx < i.idx) || (idx == i.idx && idxos < i.idxos); + } +}; + +class DUnion +{ + std::vector fields; +public: + DUnion(); + llvm::Constant* getConst(std::vector& in); +}; + +#endif diff -r 25d4fcce53f4 -r 058d3925950e gen/toir.cpp --- a/gen/toir.cpp Sat Nov 03 14:48:33 2007 +0100 +++ b/gen/toir.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -27,6 +27,7 @@ #include "gen/tollvm.h" #include "gen/runtime.h" #include "gen/arrays.h" +#include "gen/structs.h" #include "gen/dvalue.h" @@ -178,9 +179,12 @@ } else { // take care of forward references of global variables - if (!vd->llvmTouched && vd->isDataseg()) + if (!vd->llvmTouched && (vd->isDataseg() || (vd->storage_class & STCextern))) // !vd->onstack) vd->toObjFile(); - assert(vd->llvmValue); + if (!vd->llvmValue) { + Logger::println("global variable not resolved :/ %s", vd->toChars()); + assert(0); + } return new DVarValue(vd, vd->llvmValue, true); } } @@ -225,7 +229,7 @@ assert(ts->sym->llvmInitZ); return ts->sym->llvmInitZ; } - assert(0 && "Only support const var exp is SymbolDeclaration"); + assert(0 && "Only supported const VarExp is of a SymbolDeclaration"); return NULL; } @@ -247,14 +251,15 @@ LOG_SCOPE; const llvm::Type* t = DtoType(type); if (llvm::isa(t)) { + Logger::println("pointer"); llvm::Constant* i = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)value,false); return llvm::ConstantExpr::getIntToPtr(i, t); } - else if (llvm::isa(t)) { - return llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned()); - } - assert(0); - return NULL; + assert(llvm::isa(t)); + llvm::Constant* c = llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned()); + assert(c); + Logger::cout() << "value = " << *c << '\n'; + return c; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1447,7 +1452,7 @@ if (isslice) { return new DSliceValue(type, rval2, rval); } - else if (u->isLValueCast() || u->isVar()) { + else if (u->isLValueCast() || (u->isVar() && u->isVar()->lval)) { return new DLValueCast(type, u->getLVal(), rval); } else if (p->topexp() && p->topexp()->e1 == this) { @@ -2875,7 +2880,7 @@ STUB(AssocArrayLiteralExp); //STUB(StructLiteralExp); -#define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); assert(0); fatal(); return NULL; } +#define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); fatal(); return NULL; } CONSTSTUB(Expression); //CONSTSTUB(IntegerExp); //CONSTSTUB(RealExp); diff -r 25d4fcce53f4 -r 058d3925950e gen/tollvm.cpp --- a/gen/tollvm.cpp Sat Nov 03 14:48:33 2007 +0100 +++ b/gen/tollvm.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -14,6 +14,7 @@ #include "gen/runtime.h" #include "gen/arrays.h" #include "gen/dvalue.h" +#include "gen/structs.h" bool DtoIsPassedByRef(Type* type) { @@ -375,16 +376,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -const llvm::Type* DtoStructType(Type* t) -{ - assert(0); - std::vector types; - return llvm::StructType::get(types); -} - - -////////////////////////////////////////////////////////////////////////////////////////// - static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false) { assert(bits == 32 || bits == 64); @@ -456,132 +447,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::Value* DtoStructZeroInit(llvm::Value* v) -{ - assert(gIR); - uint64_t n = gTargetData->getTypeSize(v->getType()->getContainedType(0)); - //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); - llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty); - - llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb()); - - llvm::Function* fn = LLVM_DeclareMemSet32(); - std::vector llargs; - llargs.resize(4); - llargs[0] = sarr; - llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false); - llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); - llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); - - llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); - - return ret; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src) -{ - Logger::cout() << "dst = " << *dst << " src = " << *src << '\n'; - assert(dst->getType() == src->getType()); - assert(gIR); - - uint64_t n = gTargetData->getTypeSize(dst->getType()->getContainedType(0)); - //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); - llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); - - llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); - llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb()); - - llvm::Function* fn = LLVM_DeclareMemCpy32(); - std::vector llargs; - llargs.resize(4); - llargs[0] = dstarr; - llargs[1] = srcarr; - llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); - llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); - - return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); -} - -////////////////////////////////////////////////////////////////////////////////////////// -llvm::Constant* DtoConstStructInitializer(StructInitializer* si) -{ - llvm::StructType* structtype = llvm::cast(si->ad->llvmType); - size_t n = structtype->getNumElements(); - - assert(si->value.dim == si->vars.dim); - - std::vector inits; - inits.resize(n, NULL); - for (int i = 0; i < si->value.dim; ++i) - { - Initializer* ini = (Initializer*)si->value.data[i]; - assert(ini); - - VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; - Type* vdtype = DtoDType(vd->type); - assert(vd); - Logger::println("vars[%d] = %s", i, vd->toChars()); - - llvm::Constant* v = 0; - - assert(vd->llvmFieldIndex >= 0); - unsigned idx = vd->llvmFieldIndex; - - if (ExpInitializer* ex = ini->isExpInitializer()) - { - v = ex->exp->toConstElem(gIR); - } - else if (StructInitializer* si = ini->isStructInitializer()) - { - v = DtoConstStructInitializer(si); - } - else if (ArrayInitializer* ai = ini->isArrayInitializer()) - { - v = DtoConstArrayInitializer(ai); - } - else if (ini->isVoidInitializer()) - { - v = llvm::UndefValue::get(structtype->getElementType(idx)); - } - else - assert(v); - - inits[idx] = v; - Logger::cout() << "init[" << idx << "] = " << *v << '\n'; - } - - // fill out nulls - assert(si->ad->llvmInitZ); - if (si->ad->llvmInitZ->isNullValue()) - { - for (int i = 0; i < n; ++i) - { - if (inits[i] == 0) - { - inits[i] = llvm::Constant::getNullValue(structtype->getElementType(i)); - } - } - } - else - { - for (int i = 0; i < n; ++i) - { - if (inits[i] == 0) - { - inits[i] = si->ad->llvmInitZ->getOperand(i); - } - } - } - - return llvm::ConstantStruct::get(structtype, inits); -} - - - -////////////////////////////////////////////////////////////////////////////////////////// - llvm::Value* DtoNullDelegate(llvm::Value* v) { assert(gIR); @@ -1495,65 +1360,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs) -{ - Logger::println("checking for offset %u type %s:", os, t->toChars()); - LOG_SCOPE; - - if (idxs.empty()) - idxs.push_back(0); - - const llvm::Type* llt = llvm::PointerType::get(DtoType(t)); - - for (unsigned i=0; ifields.dim; ++i) { - VarDeclaration* vd = (VarDeclaration*)sd->fields.data[i]; - Type* vdtype = DtoDType(vd->type); - Logger::println("found %u type %s", vd->offset, vdtype->toChars()); - assert(vd->llvmFieldIndex >= 0); - if (os == vd->offset && vdtype == t) { - idxs.push_back(vd->llvmFieldIndex); - ptr = DtoGEP(ptr, idxs, "tmp"); - if (ptr->getType() != llt) - ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); - if (vd->llvmFieldIndexOffset) - ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); - return ptr; - } - else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) { - TypeStruct* ts = (TypeStruct*)vdtype; - StructDeclaration* ssd = ts->sym; - idxs.push_back(vd->llvmFieldIndex); - if (vd->llvmFieldIndexOffset) { - Logger::println("has union field offset"); - ptr = DtoGEP(ptr, idxs, "tmp"); - if (ptr->getType() != llt) - ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); - ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb()); - std::vector tmp; - return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); - } - else { - const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type)); - if (ptr->getType() != sty) { - ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp"); - std::vector tmp; - return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp); - } - else { - return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs); - } - } - } - } - - size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0)); - assert(os % llt_sz == 0); - ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); - return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); -} - -////////////////////////////////////////////////////////////////////////////////////////// - bool DtoIsTemplateInstance(Dsymbol* s) { if (!s) return false; @@ -1563,3 +1369,28 @@ return DtoIsTemplateInstance(s->parent); return false; } + +void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type* t) +{ + // create a flag to make sure initialization only happens once + llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage; + std::string gflagname(gvar->getName()); + gflagname.append("__initflag"); + llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,gIR->module); + + // check flag and do init if not already done + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend); + llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend); + llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false)); + gIR->ir->CreateCondBr(cond, initbb, endinitbb); + gIR->scope() = IRScope(initbb,endinitbb); + DValue* ie = DtoInitializer(init); + if (!ie->inPlace()) { + DValue* dst = new DVarValue(t, gvar, true); + DtoAssign(dst, ie); + } + gIR->ir->CreateStore(DtoConstBool(true), gflag); + gIR->ir->CreateBr(endinitbb); + gIR->scope() = IRScope(endinitbb,oldend); +} diff -r 25d4fcce53f4 -r 058d3925950e gen/tollvm.h --- a/gen/tollvm.h Sat Nov 03 14:48:33 2007 +0100 +++ b/gen/tollvm.h Tue Nov 06 10:03:14 2007 +0100 @@ -3,18 +3,12 @@ // D -> LLVM helpers -struct StructInitializer; struct DValue; const llvm::Type* DtoType(Type* t); bool DtoIsPassedByRef(Type* type); Type* DtoDType(Type* t); -const llvm::Type* DtoStructType(Type* t); -llvm::Value* DtoStructZeroInit(llvm::Value* v); -llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src); -llvm::Constant* DtoConstStructInitializer(StructInitializer* si); - const llvm::FunctionType* DtoFunctionType(Type* t, const llvm::Type* thistype, bool ismain = false); const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl); llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl); @@ -66,9 +60,9 @@ llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0); llvm::Constant* DtoConstBool(bool); -llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs); +bool DtoIsTemplateInstance(Dsymbol* s); -bool DtoIsTemplateInstance(Dsymbol* s); +void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type* t); // llvm wrappers void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes); diff -r 25d4fcce53f4 -r 058d3925950e gen/toobj.cpp --- a/gen/toobj.cpp Sat Nov 03 14:48:33 2007 +0100 +++ b/gen/toobj.cpp Tue Nov 06 10:03:14 2007 +0100 @@ -36,6 +36,7 @@ #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/arrays.h" +#include "gen/structs.h" #include "gen/todebug.h" #include "gen/runtime.h" @@ -287,6 +288,8 @@ gIR->module->addTypeName(mangle(),ts->llvmType); } + llvmUnion = new DUnion; // uses gIR->topstruct() + // generate static data llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; llvm::Constant* _init = 0; @@ -572,6 +575,7 @@ if (aliassym) { + Logger::println("alias sym"); toAlias()->toObjFile(); return; } @@ -608,35 +612,13 @@ Logger::println("Creating global variable"); std::string _name(mangle()); - llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,0,_name,M); - llvmValue = gvar; + bool emitRTstaticInit = false; if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl)) { if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) { _init = DtoConstInitializer(t, NULL); - // create a flag to make sure initialization only happens once - llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage; - std::string gflagname(_name); - gflagname.append("__initflag"); - llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,M); - - // check flag and do init if not already done - llvm::BasicBlock* oldend = gIR->scopeend(); - llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend); - llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend); - llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false)); - gIR->ir->CreateCondBr(cond, initbb, endinitbb); - gIR->scope() = IRScope(initbb,endinitbb); - elem* ie = DtoInitializer(init); - if (!ie->inPlace()) { - DValue* dst = new DVarValue(t, gvar, true); - DtoAssign(dst, ie); - delete dst; - } - gIR->ir->CreateStore(DtoConstBool(true), gflag); - gIR->ir->CreateBr(endinitbb); - gIR->scope() = IRScope(endinitbb,oldend); + emitRTstaticInit = true; } else { _init = DtoConstInitializer(t, init); @@ -668,10 +650,15 @@ //assert(0); } } + } - Logger::cout() << "final init = " << *_init << '\n'; - gvar->setInitializer(_init); - } + if (_init && _init->getType() != _type) + _type = _init->getType(); + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M); + llvmValue = gvar; + + if (emitRTstaticInit) + DtoLazyStaticInit(istempl, gvar, init, t); llvmDModule = gIR->dmodule; diff -r 25d4fcce53f4 -r 058d3925950e lphobos/phobos.d --- a/lphobos/phobos.d Sat Nov 03 14:48:33 2007 +0100 +++ b/lphobos/phobos.d Tue Nov 06 10:03:14 2007 +0100 @@ -3,7 +3,28 @@ import std.array, std.ctype, +std.intrinsic, +std.stdint, std.stdio, std.stdarg, std.uni, -std.utf; \ No newline at end of file +std.utf, + +std.c.fenv, +std.c.locale, +std.c.math, +std.c.process, +std.c.stdarg, +std.c.stddef, +std.c.stdio, +std.c.stdlib, +std.c.string, +std.c.time; + +version(linux) { + import + std.c.linux.linux, + std.c.linux.linuxextern, + std.c.linux.pthread, + std.c.linux.socket; +} diff -r 25d4fcce53f4 -r 058d3925950e lphobos/std/c/linux/linuxextern.d --- a/lphobos/std/c/linux/linuxextern.d Sat Nov 03 14:48:33 2007 +0100 +++ b/lphobos/std/c/linux/linuxextern.d Tue Nov 06 10:03:14 2007 +0100 @@ -12,7 +12,7 @@ module std.c.linux.linuxextern; -extern (C) +extern extern (C) { void* __libc_stack_end; int __data_start; diff -r 25d4fcce53f4 -r 058d3925950e lphobos/std/c/linux/socket.d --- a/lphobos/std/c/linux/socket.d Sat Nov 03 14:48:33 2007 +0100 +++ b/lphobos/std/c/linux/socket.d Tue Nov 06 10:03:14 2007 +0100 @@ -331,7 +331,7 @@ } -const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; +const in6_addr IN6ADDR_ANY; const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; //alias IN6ADDR_ANY IN6ADDR_ANY_INIT; //alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT; diff -r 25d4fcce53f4 -r 058d3925950e test/bug51.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug51.d Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,26 @@ +module bug51; + +import std.stdint; + +union in6_addr +{ + private union _in6_u_t + { + uint8_t[16] u6_addr8; + uint16_t[8] u6_addr16; + uint32_t[4] u6_addr32; + } + _in6_u_t in6_u; + + uint8_t[16] s6_addr8; + uint16_t[8] s6_addr16; + uint32_t[4] s6_addr32; +} + + +const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; +const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; + +void main() +{ +} diff -r 25d4fcce53f4 -r 058d3925950e test/union7.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/union7.d Tue Nov 06 10:03:14 2007 +0100 @@ -0,0 +1,48 @@ +module union7; + +pragma(LLVM_internal, "notypeinfo") +struct Union +{ + union { + double g; + struct { + short s1,s2,s3,s4; + } + } + union { + float f; + long l; + } +} + +Union a = { f:4f }; +Union b = { 3.0, f:2 }; +Union c = { l:42, g:2.0 }; +Union d = { s2:3 }; +Union e = { s1:3, s4:4, l:5 }; + +void main() +{ + assert(a.f == 4f); + assert(a.g !<>= 0.0); + assert((a.l>>>32) == 0); + + assert(b.g == 3.0); + assert(b.f == 2f); + + assert(c.l == 42); + assert(c.g == 2.0); + + assert(d.s1 == 0); + assert(d.s2 == 3); + assert(d.s3 == 0); + assert(d.s4 == 0); + {assert(d.f !<>= 0f);} + {} + assert(e.s1 == 3); + assert(e.s2 == 0); + assert(e.s3 == 0); + {assert(e.s4 == 4);} + {} + assert(e.l == 5); +}