From 039bc0880d59804da34c6d467a0781157c6d339f Mon Sep 17 00:00:00 2001 From: Tomas Lindquist Olsen Date: Wed, 24 Oct 2007 01:37:34 +0200 Subject: [PATCH] [svn r58] Fixed cond expression resulting in a non-basic type. Fixed identity expression for dynamic arrays. Revamped the system to keep track of lvalues and rvalues and their relations. Typedef declaration now generate the custom typeinfo. Other bugfixes. --- dmd/aggregate.h | 2 + dmd/struct.c | 1 + gen/arrays.c | 25 +++++++- gen/arrays.h | 2 + gen/irstate.c | 21 +++++-- gen/irstate.h | 20 +++++-- gen/statements.c | 31 ++++++---- gen/toir.c | 110 ++++++++++++++++++++-------------- gen/tollvm.c | 32 +++++++++- gen/tollvm.h | 4 ++ gen/toobj.c | 37 ++++++------ gen/typinf.c | 104 ++++++++++++++++++++++++++++++-- lphobos/internal/objectimpl.d | 6 +- test/bug32.d | 14 +++++ test/bug33.d | 33 ++++++++++ test/condexp1.d | 12 ++++ test/typeinfo3.d | 13 ++++ 17 files changed, 370 insertions(+), 97 deletions(-) create mode 100644 test/bug32.d create mode 100644 test/bug33.d create mode 100644 test/condexp1.d create mode 100644 test/typeinfo3.d diff --git a/dmd/aggregate.h b/dmd/aggregate.h index be629ff3..6a182cba 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -40,6 +40,7 @@ namespace llvm class Type; class Value; class Constant; + class ConstantStruct; } struct AggregateDeclaration : ScopeDsymbol @@ -98,6 +99,7 @@ struct AggregateDeclaration : ScopeDsymbol bool llvmInProgress; llvm::Type* llvmType; llvm::Value* llvmVtbl; + llvm::ConstantStruct* llvmConstVtbl; llvm::Constant* llvmInitZ; virtual void offsetToIndex(Type* t, unsigned os, std::vector& result); // converts a DMD field offsets to LLVM struct index vector diff --git a/dmd/struct.c b/dmd/struct.c index a509b410..64af131d 100644 --- a/dmd/struct.c +++ b/dmd/struct.c @@ -47,6 +47,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) llvmType = NULL; llvmVtbl = NULL; + llvmConstVtbl = NULL; llvmInitZ = NULL; llvmInProgress = false; } diff --git a/gen/arrays.c b/gen/arrays.c index 99704b8d..c52a33d6 100644 --- a/gen/arrays.c +++ b/gen/arrays.c @@ -100,6 +100,7 @@ void LLVM_DtoArrayAssign(llvm::Value* dst, llvm::Value* src) } else { + Logger::cout() << "array assignment type dont match: " << *dst->getType() << '\n' << *src->getType() << '\n'; if (!llvm::isa(src->getType()->getContainedType(0))) { Logger::cout() << "invalid: " << *src << '\n'; @@ -109,7 +110,7 @@ void LLVM_DtoArrayAssign(llvm::Value* dst, llvm::Value* src) llvm::Type* dstty = llvm::PointerType::get(arrty->getElementType()); llvm::Value* dstlen = LLVM_DtoGEPi(dst,0,0,"tmp",gIR->scopebb()); - llvm::Value* srclen = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false); + llvm::Value* srclen = LLVM_DtoConstSize_t(arrty->getNumElements()); new llvm::StoreInst(srclen, dstlen, gIR->scopebb()); llvm::Value* dstptr = LLVM_DtoGEPi(dst,0,1,"tmp",gIR->scopebb()); @@ -551,3 +552,25 @@ llvm::Value* LLVM_DtoArrayCastLength(llvm::Value* len, const llvm::Type* elemty, args.push_back(llvm::ConstantInt::get(LLVM_DtoSize_t(), gTargetData->getTypeSize(newelemty), false)); return new llvm::CallInst(fn, args.begin(), args.end(), "tmp", gIR->scopebb()); } + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Value* LLVM_DtoDynArrayIs(TOK op, llvm::Value* l, llvm::Value* r) +{ + assert(l->getType() == r->getType()); + + llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; + + llvm::Value* ll = gIR->ir->CreateLoad(LLVM_DtoGEPi(l, 0,0, "tmp"),"tmp"); + llvm::Value* rl = gIR->ir->CreateLoad(LLVM_DtoGEPi(r, 0,0, "tmp"),"tmp"); + llvm::Value* b1 = gIR->ir->CreateICmp(pred,ll,rl,"tmp"); + + llvm::Value* lp = gIR->ir->CreateLoad(LLVM_DtoGEPi(l, 0,1, "tmp"),"tmp"); + llvm::Value* rp = gIR->ir->CreateLoad(LLVM_DtoGEPi(r, 0,1, "tmp"),"tmp"); + llvm::Value* b2 = gIR->ir->CreateICmp(pred,lp,rp,"tmp"); + + llvm::Value* b = gIR->ir->CreateAnd(b1,b2,"tmp"); + if (op == TOKnotidentity) + return gIR->ir->CreateNot(b,"tmp"); + else + return b; +} diff --git a/gen/arrays.h b/gen/arrays.h index 6278bb28..41de8232 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -22,7 +22,9 @@ void LLVM_DtoCatArrayElement(llvm::Value* arr, Expression* exp); void LLVM_DtoStaticArrayCopy(llvm::Value* dst, llvm::Value* src); llvm::Value* LLVM_DtoStaticArrayCompare(TOK op, llvm::Value* l, llvm::Value* r); + llvm::Value* LLVM_DtoDynArrayCompare(TOK op, llvm::Value* l, llvm::Value* r); +llvm::Value* LLVM_DtoDynArrayIs(TOK op, llvm::Value* l, llvm::Value* r); llvm::Value* LLVM_DtoArrayCastLength(llvm::Value* len, const llvm::Type* elemty, const llvm::Type* newelemty); diff --git a/gen/irstate.c b/gen/irstate.c index d4dd0704..901cf1ba 100644 --- a/gen/irstate.c +++ b/gen/irstate.c @@ -35,7 +35,6 @@ IRState::IRState() { dmodule = 0; module = 0; - inLvalue = false; emitMain = false; mainFunc = 0; ir.state = this; @@ -71,10 +70,9 @@ IRStruct& IRState::topstruct() return structs.back(); } -llvm::Value* IRState::toplval() +IRExp* IRState::topexp() { - assert(!lvals.empty() && "Lval vector is empty!"); - return lvals.back(); + return exps.empty() ? NULL : &exps.back(); } IRScope& IRState::scope() @@ -153,3 +151,18 @@ IRFunction::IRFunction(FuncDeclaration* fd) func = NULL; allocapoint = NULL; } + +////////////////////////////////////////////////////////////////////////////////////////// + +IRExp::IRExp() +{ + e1 = e2 = NULL; + v = NULL; +} + +IRExp::IRExp(Expression* l, Expression* r, llvm::Value* val) +{ + e1 = l; + e2 = r; + v = val; +} diff --git a/gen/irstate.h b/gen/irstate.h index 312b94dd..135d3cb1 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -88,6 +88,15 @@ struct IRBuilderHelper LLVMBuilder* operator->(); }; +struct IRExp +{ + Expression* e1; + Expression* e2; + llvm::Value* v; + IRExp(); + IRExp(Expression* l, Expression* r, llvm::Value* val); +}; + // represents the module struct IRState { @@ -119,11 +128,10 @@ struct IRState bool emitMain; llvm::Function* mainFunc; - // L-values - bool inLvalue; - typedef std::vector LvalVec; - LvalVec lvals; - llvm::Value* toplval(); + // expression l/r value handling + typedef std::vector ExpVec; + ExpVec exps; + IRExp* topexp(); // basic block scopes std::vector scopes; @@ -141,7 +149,7 @@ struct IRState // might be a better way but it works. problem is I only get a // VarDeclaration for __dollar, but I can't see how to get the // array pointer from this :( - LvalVec arrays; + std::vector arrays; // builder helper IRBuilderHelper ir; diff --git a/gen/statements.c b/gen/statements.c index f71dc14f..1f1e3a53 100644 --- a/gen/statements.c +++ b/gen/statements.c @@ -51,10 +51,10 @@ void ReturnStatement::toIR(IRState* p) Logger::println("ReturnStatement::toIR(%d): %s", rsi++, toChars()); LOG_SCOPE; - IRFunction::FinallyVec& fin = p->func().finallys; - if (exp) { + Logger::println("return type is: %s", exp->type->toChars()); + Type* exptype = LLVM_DtoDType(exp->type); TY expty = exptype->ty; if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) { @@ -63,28 +63,36 @@ void ReturnStatement::toIR(IRState* p) TypeFunction* f = p->topfunctype(); assert(f->llvmRetInPtr && f->llvmRetArg); - p->lvals.push_back(f->llvmRetArg); + p->exps.push_back(IRExp(NULL,exp,f->llvmRetArg)); elem* e = exp->toElem(p); - p->lvals.pop_back(); + p->exps.pop_back(); if (expty == Tstruct) { - if (!e->inplace) { - assert(e->mem); - LLVM_DtoStructCopy(f->llvmRetArg,e->mem); - } + if (!e->inplace) + LLVM_DtoStructCopy(f->llvmRetArg,e->getValue()); } else if (expty == Tdelegate) { - LLVM_DtoDelegateCopy(f->llvmRetArg,e->mem); + if (!e->inplace) + LLVM_DtoDelegateCopy(f->llvmRetArg,e->getValue()); } else if (expty == Tarray) { if (e->type == elem::SLICE) { + assert(e->mem); LLVM_DtoSetArray(f->llvmRetArg,e->arg,e->mem); } - // else the return value is a variable and should already have been assigned by now + else if (!e->inplace) { + if (e->type == elem::NUL) { + LLVM_DtoNullArray(f->llvmRetArg); + } + else { + LLVM_DtoArrayAssign(f->llvmRetArg, e->getValue()); + } + } } else assert(0); + IRFunction::FinallyVec& fin = p->func().finallys; if (fin.empty()) new llvm::ReturnInst(p->scopebb()); else { @@ -98,6 +106,8 @@ void ReturnStatement::toIR(IRState* p) llvm::Value* v = e->getValue(); delete e; Logger::cout() << "return value is '" <<*v << "'\n"; + + IRFunction::FinallyVec& fin = p->func().finallys; if (fin.empty()) { new llvm::ReturnInst(v, p->scopebb()); } @@ -113,6 +123,7 @@ void ReturnStatement::toIR(IRState* p) else { if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) { + IRFunction::FinallyVec& fin = p->func().finallys; if (fin.empty()) { new llvm::ReturnInst(p->scopebb()); } diff --git a/gen/toir.c b/gen/toir.c index e5b01d64..cf1ebf81 100644 --- a/gen/toir.c +++ b/gen/toir.c @@ -377,19 +377,16 @@ elem* StringExp::toElem(IRState* p) if (dtype->ty == Tarray) { llvm::Constant* clen = llvm::ConstantInt::get(LLVM_DtoSize_t(),len,false); - if (p->lvals.empty() || !p->toplval()) { + if (!p->topexp() || p->topexp()->e2 != this) { llvm::Value* tmpmem = new llvm::AllocaInst(LLVM_DtoType(dtype),"tmp",p->topallocapoint()); LLVM_DtoSetArray(tmpmem, clen, arrptr); e->mem = tmpmem; } - else if (llvm::Value* arr = p->toplval()) { - if (llvm::isa(arr)) { - e->val = LLVM_DtoConstantSlice(clen, arrptr); - } - else { - LLVM_DtoSetArray(arr, clen, arrptr); - e->inplace = true; - } + else if (p->topexp()->e2 == this) { + llvm::Value* arr = p->topexp()->v; + assert(arr); + LLVM_DtoSetArray(arr, clen, arrptr); + e->inplace = true; } else assert(0); @@ -453,14 +450,13 @@ elem* AssignExp::toElem(IRState* p) Logger::print("AssignExp::toElem: %s | %s = %s\n", toChars(), e1->type->toChars(), e2->type->toChars()); LOG_SCOPE; - assert(e1 && e2); - p->inLvalue = true; - elem* l = e1->toElem(p); - p->inLvalue = false; + p->exps.push_back(IRExp(e1,e2,NULL)); - p->lvals.push_back(l->mem); - elem* r = e2->toElem(p); - p->lvals.pop_back(); + elem* l = e1->toElem(p); + p->topexp()->v = l->mem; + elem* r = e2->toElem(p); + + p->exps.pop_back(); if (l->type == elem::ARRAYLEN) { @@ -1066,11 +1062,14 @@ elem* CallExp::toElem(IRState* p) Logger::println("hidden struct return"); + IRExp* topexp = p->topexp(); + // hidden struct return arguments if (retinptr) { - if (!p->lvals.empty() && p->toplval()) { - assert(llvm::isa(p->toplval()->getType()->getContainedType(0))); - llargs[j] = p->toplval(); + if (topexp && topexp->e2 == this) { + assert(topexp->v); + assert(llvm::isa(topexp->v->getType()->getContainedType(0))); + llargs[j] = topexp->v; if (LLVM_DtoIsPassedByRef(tf->next)) { e->inplace = true; } @@ -1534,17 +1533,19 @@ elem* StructLiteralExp::toElem(IRState* p) llvm::Value* sptr = 0; // if there is no lval, this is probably a temporary struct literal. correct? - if (p->lvals.empty() || !p->toplval()) + if (!p->topexp() || p->topexp()->e2 != this) { sptr = new llvm::AllocaInst(LLVM_DtoType(type),"tmpstructliteral",p->topallocapoint()); e->mem = sptr; e->type = elem::VAR; } // already has memory - else + else if (p->topexp()->e2 == this) { - sptr = p->toplval(); + sptr = p->topexp()->v; } + else + assert(0); assert(sptr); @@ -1558,9 +1559,9 @@ elem* StructLiteralExp::toElem(IRState* p) Expression* vx = (Expression*)elements->data[i]; if (vx != 0) { - p->lvals.push_back(arrptr); + p->exps.push_back(IRExp(NULL,vx,arrptr)); elem* ve = vx->toElem(p); - p->lvals.pop_back(); + p->exps.pop_back(); if (!ve->inplace) { llvm::Value* val = ve->getValue(); @@ -2042,7 +2043,8 @@ elem* NewExp::toElem(IRState* p) if (arguments->dim == 1) { elem* sz = ((Expression*)arguments->data[0])->toElem(p); llvm::Value* dimval = sz->getValue(); - LLVM_DtoNewDynArray(p->toplval(), dimval, ntype->next); + assert(p->topexp() && p->topexp()->e2 == this && p->topexp()->v); + LLVM_DtoNewDynArray(p->topexp()->v, dimval, ntype->next); delete sz; } else { @@ -2161,7 +2163,7 @@ elem* ArrayLengthExp::toElem(IRState* p) elem* e = new elem; elem* u = e1->toElem(p); - if (p->inLvalue) + if (p->topexp() && p->topexp()->e1 == this) { e->mem = u->mem; e->type = elem::ARRAYLEN; @@ -2372,26 +2374,27 @@ elem* DelegateExp::toElem(IRState* p) elem* e = new elem; elem* u = e1->toElem(p); - + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); - + const llvm::Type* int8ptrty = llvm::PointerType::get(llvm::Type::Int8Ty); - llvm::Value* lval = p->toplval(); + assert(p->topexp() && p->topexp()->e2 == this && p->topexp()->v); + llvm::Value* lval = p->topexp()->v; llvm::Value* context = LLVM_DtoGEP(lval,zero,zero,"tmp",p->scopebb()); llvm::Value* castcontext = new llvm::BitCastInst(u->getValue(),int8ptrty,"tmp",p->scopebb()); new llvm::StoreInst(castcontext, context, p->scopebb()); - + llvm::Value* fptr = LLVM_DtoGEP(lval,zero,one,"tmp",p->scopebb()); - + assert(func->llvmValue); llvm::Value* castfptr = new llvm::BitCastInst(func->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb()); new llvm::StoreInst(castfptr, fptr, p->scopebb()); - + e->inplace = true; - + delete u; return e; } @@ -2415,8 +2418,16 @@ elem* IdentityExp::toElem(IRState* p) else r = v->getValue(); - llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; - e->val = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb()); + Type* t1 = LLVM_DtoDType(e1->type); + + if (t1->ty == Tarray) { + assert(l->getType() == r->getType()); + e->val = LLVM_DtoDynArrayIs(op,l,r); + } + else { + llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; + e->val = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb()); + } e->type = elem::VAL; delete u; @@ -2445,7 +2456,8 @@ elem* CondExp::toElem(IRState* p) Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - const llvm::Type* resty = LLVM_DtoType(type); + Type* dtype = LLVM_DtoDType(type); + const llvm::Type* resty = LLVM_DtoType(dtype); // allocate a temporary for the final result. failed to come up with a better way :/ llvm::BasicBlock* entryblock = &p->topfunc()->front(); @@ -2463,21 +2475,21 @@ elem* CondExp::toElem(IRState* p) p->scope() = IRScope(condtrue, condfalse); elem* u = e1->toElem(p); - new llvm::StoreInst(u->getValue(),resval,p->scopebb()); + LLVM_DtoAssign(dtype, resval, u->getValue()); new llvm::BranchInst(condend,p->scopebb()); delete u; p->scope() = IRScope(condfalse, condend); elem* v = e2->toElem(p); - new llvm::StoreInst(v->getValue(),resval,p->scopebb()); + LLVM_DtoAssign(dtype, resval, v->getValue()); new llvm::BranchInst(condend,p->scopebb()); delete v; p->scope() = IRScope(condend, oldend); elem* e = new elem; - e->val = new llvm::LoadInst(resval,"tmp",p->scopebb()); - e->type = elem::VAL; + e->mem = resval; + e->type = elem::VAR; return e; } @@ -2589,12 +2601,13 @@ elem* ArrayLiteralExp::toElem(IRState* p) Logger::cout() << "array literal has llvm type: " << *t << '\n'; llvm::Value* mem = 0; - if (p->lvals.empty() || !p->toplval()) { + if (!p->topexp() || p->topexp()->e2 != this) { assert(LLVM_DtoDType(type)->ty == Tsarray); mem = new llvm::AllocaInst(t,"tmparrayliteral",p->topallocapoint()); } - else { - mem = p->toplval(); + else if (p->topexp()->e2 == this) { + mem = p->topexp()->v; + assert(mem); if (!llvm::isa(mem->getType()) || !llvm::isa(mem->getType()->getContainedType(0))) { @@ -2602,6 +2615,8 @@ elem* ArrayLiteralExp::toElem(IRState* p) fatal(); } } + else + assert(0); for (unsigned i=0; idim; ++i) { @@ -2657,14 +2672,17 @@ elem* FuncExp::toElem(IRState* p) fd->toObjFile(); llvm::Value* lval = NULL; - if (p->lvals.empty() || p->toplval() == NULL) { + if (!p->topexp() || p->topexp()->e2 != this) { const llvm::Type* dgty = LLVM_DtoType(type); Logger::cout() << "delegate without explicit storage:" << '\n' << *dgty << '\n'; lval = new llvm::AllocaInst(dgty,"dgstorage",p->topallocapoint()); } - else { - lval = p->toplval(); + else if (p->topexp()->e2 == this) { + lval = p->topexp()->v; + assert(lval); } + else + assert(0); elem* e = new elem; diff --git a/gen/tollvm.c b/gen/tollvm.c index bf84b7a4..0a752ad4 100644 --- a/gen/tollvm.c +++ b/gen/tollvm.c @@ -1100,14 +1100,14 @@ llvm::Value* LLVM_DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expr { llvm::Value* retval = 0; - bool haslvals = !gIR->lvals.empty(); + bool haslvals = !gIR->exps.empty(); if (haslvals) - gIR->lvals.push_back(NULL); + gIR->exps.push_back(IRExp(NULL,NULL,NULL)); elem* arg = argexp->toElem(gIR); if (haslvals) - gIR->lvals.pop_back(); + gIR->exps.pop_back(); if (arg->inplace) { assert(arg->mem != 0); @@ -1254,3 +1254,29 @@ void LLVM_DtoAssign(Type* t, llvm::Value* lhs, llvm::Value* rhs) gIR->ir->CreateStore(rhs, lhs); } } + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::ConstantInt* LLVM_DtoConstSize_t(size_t i) +{ + return llvm::ConstantInt::get(LLVM_DtoSize_t(), i, false); +} +llvm::ConstantInt* LLVM_DtoConstUint(unsigned i) +{ + return llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Constant* LLVM_DtoConstString(const char* str) +{ + std::string s(str); + llvm::Constant* init = llvm::ConstantArray::get(s, true); + llvm::GlobalVariable* gvar = new llvm::GlobalVariable( + init->getType(), true,llvm::GlobalValue::InternalLinkage, init, "stringliteral", gIR->module); + llvm::Constant* idxs[2] = { LLVM_DtoConstUint(0), LLVM_DtoConstUint(0) }; + return LLVM_DtoConstantSlice( + LLVM_DtoConstSize_t(s.length()), + llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2) + ); +} diff --git a/gen/tollvm.h b/gen/tollvm.h index 14dba07b..1f4f0558 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -59,4 +59,8 @@ llvm::Value* LLVM_DtoNestedVariable(VarDeclaration* vd); void LLVM_DtoAssign(Type* lhsType, llvm::Value* lhs, llvm::Value* rhs); +llvm::ConstantInt* LLVM_DtoConstSize_t(size_t); +llvm::ConstantInt* LLVM_DtoConstUint(unsigned i); +llvm::Constant* LLVM_DtoConstString(const char*); + #include "enums.h" diff --git a/gen/toobj.c b/gen/toobj.c index fd906b2b..ecbae421 100644 --- a/gen/toobj.c +++ b/gen/toobj.c @@ -363,10 +363,10 @@ void ClassDeclaration::toObjFile() ts->llvmType = structtype; llvmType = structtype; - bool define_vtable = false; + bool needs_definition = false; if (parent->isModule()) { gIR->module->addTypeName(mangle(),ts->llvmType); - define_vtable = (getModule() == gIR->dmodule); + needs_definition = (getModule() == gIR->dmodule); } else { assert(0 && "class parent is not a module"); @@ -418,9 +418,9 @@ void ClassDeclaration::toObjFile() gIR->module->addTypeName(styname, svtbl_ty); svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); - if (define_vtable) { - svtblVar->setInitializer(llvm::ConstantStruct::get(svtbl_ty, sinits)); - } + llvmConstVtbl = llvm::cast(llvm::ConstantStruct::get(svtbl_ty, sinits)); + if (needs_definition) + svtblVar->setInitializer(llvmConstVtbl); llvmVtbl = svtblVar; } @@ -441,25 +441,25 @@ void ClassDeclaration::toObjFile() assert(svtblVar != 0); gIR->topstruct().inits[0] = svtblVar; - _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); + llvmInitZ = _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); assert(_init); std::string initname("_D"); initname.append(mangle()); initname.append("6__initZ"); //Logger::cout() << *_init << '\n'; - llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module); + llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, NULL, initname, gIR->module); ts->llvmInit = initvar; - if (define_vtable) { - initvar->setInitializer(_init); - } - // generate member function definitions - gIR->topstruct().queueFuncs = false; - IRStruct::FuncDeclVec& mfs = gIR->topstruct().funcs; - size_t n = mfs.size(); - for (size_t i=0; itoObjFile(); + if (needs_definition) { + initvar->setInitializer(_init); + // generate member functions + gIR->topstruct().queueFuncs = false; + IRStruct::FuncDeclVec& mfs = gIR->topstruct().funcs; + size_t n = mfs.size(); + for (size_t i=0; itoObjFile(); + } } gIR->classes.pop_back(); @@ -525,9 +525,7 @@ void VarDeclaration::toObjFile() // if extern don't emit initializer if (!(storage_class & STCextern)) { - gIR->lvals.push_back(gvar); _init = LLVM_DtoConstInitializer(t, init); - gIR->lvals.pop_back(); //Logger::cout() << "initializer: " << *_init << '\n'; if (_type != _init->getType()) { @@ -628,7 +626,8 @@ void TypedefDeclaration::toObjFile() LOG_SCOPE; // generate typeinfo - type->getTypeInfo(NULL); + if (!type->builtinTypeInfo()) + type->getTypeInfo(NULL); } /* ================================================================== */ diff --git a/gen/typinf.c b/gen/typinf.c index cdf7f898..863254cc 100644 --- a/gen/typinf.c +++ b/gen/typinf.c @@ -30,6 +30,8 @@ #include "gen/irstate.h" #include "gen/logger.h" #include "gen/runtime.h" +#include "gen/tollvm.h" +#include "gen/arrays.h" /******************************************* * Get a canonicalized form of the TypeInfo for use with the internal @@ -242,10 +244,20 @@ void TypeInfoDeclaration::toObjFile() if (llvmTouched) return; else llvmTouched = true; - Logger::println("Getting typeinfo var: %s", mangle()); - llvmValue = LLVM_D_GetRuntimeGlobal(gIR->module, mangle()); - assert(llvmValue); - Logger::cout() << "Got:" << '\n' << *llvmValue << '\n'; + Logger::println("typeinfo mangle: %s", mangle()); + + if (tinfo->builtinTypeInfo()) { + // this is a declaration of a builtin __initZ var + llvmValue = LLVM_D_GetRuntimeGlobal(gIR->module, mangle()); + assert(llvmValue); + Logger::cout() << "Got typeinfo var:" << '\n' << *llvmValue << '\n'; + } + else { + toDt(NULL); + // this is a specialized typeinfo + //std::vector stypes; + //stypes.push_back( + } } /* ========================================================================= */ @@ -257,7 +269,89 @@ void TypeInfoDeclaration::toDt(dt_t **pdt) void TypeInfoTypedefDeclaration::toDt(dt_t **pdt) { - assert(0 && "TypeInfoTypedefDeclaration"); + Logger::println("TypeInfoTypedefDeclaration::toDt() %s", toChars()); + LOG_SCOPE; + + ClassDeclaration* base = Type::typeinfotypedef; + base->toObjFile(); + + llvm::Constant* initZ = base->llvmInitZ; + assert(initZ); + const llvm::StructType* stype = llvm::cast(initZ->getType()); + + std::vector sinits; + sinits.push_back(initZ->getOperand(0)); + + assert(tinfo->ty == Ttypedef); + TypeTypedef *tc = (TypeTypedef *)tinfo; + TypedefDeclaration *sd = tc->sym; + + // TypeInfo base + //const llvm::PointerType* basept = llvm::cast(initZ->getOperand(1)->getType()); + //sinits.push_back(llvm::ConstantPointerNull::get(basept)); + Logger::println("generating base typeinfo"); + //sd->basetype = sd->basetype->merge(); + sd->basetype->getTypeInfo(NULL); // generate vtinfo + assert(sd->basetype->vtinfo); + if (!sd->basetype->vtinfo->llvmValue) + sd->basetype->vtinfo->toObjFile(); + assert(llvm::isa(sd->basetype->vtinfo->llvmValue)); + llvm::Constant* castbase = llvm::cast(sd->basetype->vtinfo->llvmValue); + castbase = llvm::ConstantExpr::getBitCast(castbase, initZ->getOperand(1)->getType()); + sinits.push_back(castbase); + + // char[] name + char *name = sd->toPrettyChars(); + sinits.push_back(LLVM_DtoConstString(name)); + assert(sinits.back()->getType() == initZ->getOperand(2)->getType()); + + // void[] init + //const llvm::PointerType* initpt = llvm::PointerType::get(llvm::Type::Int8Ty); + //sinits.push_back(LLVM_DtoConstantSlice(LLVM_DtoConstSize_t(0), llvm::ConstantPointerNull::get(initpt))); + sinits.push_back(initZ->getOperand(3)); + + // create the symbol + llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits); + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::InternalLinkage,tiInit,toChars(),gIR->module); + + llvmValue = gvar; + + /* + dtxoff(pdt, Type::typeinfotypedef->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Typedef + dtdword(pdt, 0); // monitor + + assert(tinfo->ty == Ttypedef); + + TypeTypedef *tc = (TypeTypedef *)tinfo; + TypedefDeclaration *sd = tc->sym; + //printf("basetype = %s\n", sd->basetype->toChars()); + + // Put out: + // TypeInfo base; + // char[] name; + // void[] m_init; + + sd->basetype = sd->basetype->merge(); + sd->basetype->getTypeInfo(NULL); // generate vtinfo + assert(sd->basetype->vtinfo); + dtxoff(pdt, sd->basetype->vtinfo->toSymbol(), 0, TYnptr); // TypeInfo for basetype + + char *name = sd->toPrettyChars(); + size_t namelen = strlen(name); + dtdword(pdt, namelen); + dtabytes(pdt, TYnptr, 0, namelen + 1, name); + + // void[] init; + if (tinfo->isZeroInit() || !sd->init) + { // 0 initializer, or the same as the base type + dtdword(pdt, 0); // init.length + dtdword(pdt, 0); // init.ptr + } + else + { + dtdword(pdt, sd->type->size()); // init.length + dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr + */ } void TypeInfoEnumDeclaration::toDt(dt_t **pdt) diff --git a/lphobos/internal/objectimpl.d b/lphobos/internal/objectimpl.d index 2b997a9f..ab68628f 100644 --- a/lphobos/internal/objectimpl.d +++ b/lphobos/internal/objectimpl.d @@ -433,8 +433,6 @@ class TypeInfo OffsetTypeInfo[] offTi() { return null; } } -/+ - class TypeInfo_Typedef : TypeInfo { char[] toString() { return name; } @@ -455,7 +453,7 @@ class TypeInfo_Typedef : TypeInfo size_t tsize() { return base.tsize(); } void swap(void *p1, void *p2) { return base.swap(p1, p2); } - TypeInfo next() { return base.next(); } + TypeInfo next() { return base; } uint flags() { return base.flags(); } void[] init() { return m_init.length ? m_init : base.init(); } @@ -468,6 +466,8 @@ class TypeInfo_Enum : TypeInfo_Typedef { } +/+ + class TypeInfo_Pointer : TypeInfo { char[] toString() { return m_next.toString() ~ "*"; } diff --git a/test/bug32.d b/test/bug32.d new file mode 100644 index 00000000..a6100c83 --- /dev/null +++ b/test/bug32.d @@ -0,0 +1,14 @@ +module bug32; + +struct S +{ + char[] getName() { return name; } + char[] name; +} + +void main() +{ + S s = S("Kyle"); + char[] name = s.name; + printf("%.*s\n", name.length, name.ptr); +} diff --git a/test/bug33.d b/test/bug33.d new file mode 100644 index 00000000..6bf5d542 --- /dev/null +++ b/test/bug33.d @@ -0,0 +1,33 @@ +module bug33; + +extern(C) int memcmp(void*,void*,size_t); + +private int string_cmp(char[] s1, char[] s2) +{ + auto len = s1.length; + if (s2.length < len) + len = s2.length; + int result = memcmp(s1.ptr, s2.ptr, len); + if (result == 0) + result = cast(int)(cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length); + return result; +} + +struct S +{ + char[] toString() + { + return "S"; + } +} + +int func() +{ + S a,b; + return string_cmp(a.toString(),b.toString()); +} + +void main() +{ + assert(func() == 0); +} diff --git a/test/condexp1.d b/test/condexp1.d new file mode 100644 index 00000000..3a67dfec --- /dev/null +++ b/test/condexp1.d @@ -0,0 +1,12 @@ +module condexp1; + +void main() +{ + char[] a = "hello"; + char[] b = "world"; + int i = 42; + { + char[] c = i > 50 ? b : a; + assert(c is a); + } +} diff --git a/test/typeinfo3.d b/test/typeinfo3.d new file mode 100644 index 00000000..9c4e949c --- /dev/null +++ b/test/typeinfo3.d @@ -0,0 +1,13 @@ +module typeinfo3; + +typedef int int_t; + +void main() +{ + int_t i; + auto ti = typeid(typeof(i)); + printf("%s\n",ti.toString.ptr); + assert(ti.toString() == "typeinfo3.int_t"); + assert(ti.next !is null); + assert(ti.next.toString() == "int"); +}