Mercurial > projects > ldc
view gen/toir.c @ 54:28e99b04a132 trunk
[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.
author | lindquist |
---|---|
date | Wed, 24 Oct 2007 01:37:34 +0200 |
parents | 06ccc817acd4 |
children | 0ccfae271c45 |
line wrap: on
line source
// Backend stubs /* DMDFE backend stubs * This file contains the implementations of the backend routines. * For dmdfe these do nothing but print a message saying the module * has been parsed. Substitute your own behaviors for these routimes. */ #include <stdio.h> #include <math.h> #include <sstream> #include <fstream> #include <iostream> #include "gen/llvm.h" #include "total.h" #include "init.h" #include "symbol.h" #include "mtype.h" #include "hdrgen.h" #include "port.h" #include "gen/irstate.h" #include "gen/elem.h" #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/runtime.h" #include "gen/arrays.h" ////////////////////////////////////////////////////////////////////////////////////////// elem* DeclarationExp::toElem(IRState* p) { Logger::print("DeclarationExp::toElem: %s | T=%s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; // variable declaration if (VarDeclaration* vd = declaration->isVarDeclaration()) { Logger::println("VarDeclaration"); // static if (vd->isDataseg()) { vd->toObjFile(); } else { Logger::println("vdtype = %s", vd->type->toChars()); // referenced by nested delegate? if (vd->nestedref) { Logger::println("has nestedref set"); vd->llvmValue = p->func().decl->llvmNested; assert(vd->llvmValue); assert(vd->llvmNestedIndex >= 0); } // normal stack variable else { // allocate storage on the stack const llvm::Type* lltype = LLVM_DtoType(vd->type); llvm::AllocaInst* allocainst = new llvm::AllocaInst(lltype, vd->toChars(), p->topallocapoint()); //allocainst->setAlignment(vd->type->alignsize()); // TODO vd->llvmValue = allocainst; } LLVM_DtoInitializer(vd->init); } } // struct declaration else if (StructDeclaration* s = declaration->isStructDeclaration()) { Logger::println("StructDeclaration"); s->toObjFile(); } // function declaration else if (FuncDeclaration* f = declaration->isFuncDeclaration()) { Logger::println("FuncDeclaration"); f->toObjFile(); } // alias declaration else if (AliasDeclaration* a = declaration->isAliasDeclaration()) { Logger::println("AliasDeclaration"); assert(0); } else if (EnumDeclaration* e = declaration->isEnumDeclaration()) { // do nothing } // unsupported declaration else { error("Only Var/Struct-Declaration is supported for DeclarationExp"); assert(0); } return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* VarExp::toElem(IRState* p) { Logger::print("VarExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; assert(var); if (VarDeclaration* vd = var->isVarDeclaration()) { Logger::println("VarDeclaration"); if (vd->nestedref) { Logger::println("has nested ref"); } // needed to take care of forward references of global variables if (!vd->llvmTouched && vd->isDataseg()) vd->toObjFile(); if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) { Logger::println("TypeInfoDeclaration"); } // this must be a dollar expression or some other magic value // or it could be a forward declaration of a global variable if (!vd->llvmValue) { assert(!vd->nestedref); Logger::println("special - no llvmValue"); // dollar if (!p->arrays.empty()) { llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); //llvm::Value* tmp = new llvm::GetElementPtrInst(p->arrays.back(),zero,zero,"tmp",p->scopebb()); llvm::Value* tmp = LLVM_DtoGEP(p->arrays.back(),zero,zero,"tmp",p->scopebb()); e->val = new llvm::LoadInst(tmp,"tmp",p->scopebb()); e->type = elem::VAL; } // typeinfo else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) { assert(0); } // global forward ref else { Logger::println("unsupported: %s\n", vd->toChars()); assert(0 && "only magic supported is typeinfo"); } return e; } // function parameter if (vd->storage_class & STCparameter) { assert(!vd->nestedref); Logger::println("function param"); if (vd->storage_class & (STCref | STCout)) { e->mem = vd->llvmValue; e->type = elem::VAR; } else { if (LLVM_DtoIsPassedByRef(vd->type)) { e->mem = vd->llvmValue; e->type = elem::VAR; } else { if (llvm::isa<llvm::Argument>(vd->llvmValue)) { e->val = vd->llvmValue; e->type = elem::VAL; e->vardecl = vd; } else if (llvm::isa<llvm::AllocaInst>(vd->llvmValue)) { e->mem = vd->llvmValue; e->type = elem::VAR; } else assert(0); } } } else { // nested variable if (vd->nestedref) { e->mem = LLVM_DtoNestedVariable(vd); } // normal local variable else { if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) { Logger::println("typeinfo varexp"); const llvm::Type* vartype = LLVM_DtoType(type); if (tid->llvmValue->getType() != llvm::PointerType::get(vartype)) { e->mem = p->ir->CreateBitCast(tid->llvmValue, vartype, "tmp"); } else { e->mem = tid->llvmValue; } Logger::cout() << "got:" << '\n' << *tid->llvmValue << "returned:" << '\n' << *e->mem << '\n'; } else { e->mem = vd->llvmValue; } } e->vardecl = vd; e->type = elem::VAR; } } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) { Logger::println("FuncDeclaration"); if (fdecl->llvmValue == 0) { fdecl->toObjFile(); } e->val = fdecl->llvmValue; e->type = elem::FUNC; e->funcdecl = fdecl; } else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration()) { // this seems to be the static initialiser for structs Type* sdecltype = LLVM_DtoDType(sdecl->type); Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct* ts = (TypeStruct*)sdecltype; e->mem = ts->llvmInit; assert(e->mem); e->type = elem::VAR; } else { assert(0 && "Unimplemented VarExp type"); } assert(e->mem || e->val); return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* VarExp::toConstElem(IRState* p) { Logger::print("VarExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (SymbolDeclaration* sdecl = var->isSymbolDeclaration()) { // this seems to be the static initialiser for structs Type* sdecltype = LLVM_DtoDType(sdecl->type); Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct* ts = (TypeStruct*)sdecltype; assert(ts->sym->llvmInitZ); return ts->sym->llvmInitZ; } assert(0 && "Only support const var exp is SymbolDeclaration"); return NULL; } ////////////////////////////////////////////////////////////////////////////////////////// elem* IntegerExp::toElem(IRState* p) { Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; e->val = toConstElem(p); e->type = elem::CONST; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* IntegerExp::toConstElem(IRState* p) { Logger::print("IntegerExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; const llvm::Type* t = LLVM_DtoType(type); if (llvm::isa<llvm::PointerType>(t)) { llvm::Constant* i = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)value,false); return llvm::ConstantExpr::getIntToPtr(i, t); } else if (llvm::isa<llvm::IntegerType>(t)) { return llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned()); } assert(0); return NULL; } ////////////////////////////////////////////////////////////////////////////////////////// elem* RealExp::toElem(IRState* p) { Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; e->val = toConstElem(p); e->type = elem::CONST; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* RealExp::toConstElem(IRState* p) { Logger::print("RealExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; const llvm::Type* fty = LLVM_DtoType(type); if (type->ty == Tfloat32) return llvm::ConstantFP::get(fty,float(value)); else if (type->ty == Tfloat64 || type->ty == Tfloat80) return llvm::ConstantFP::get(fty,double(value)); assert(0); return NULL; } ////////////////////////////////////////////////////////////////////////////////////////// elem* NullExp::toElem(IRState* p) { Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars()); LOG_SCOPE; elem* e = new elem; e->val = toConstElem(p); e->type = elem::NUL; //Logger::cout() << "null value is now " << *e->val << '\n'; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* NullExp::toConstElem(IRState* p) { Logger::print("NullExp::toConstElem(type=%s): %s\n", type->toChars(),toChars()); LOG_SCOPE; const llvm::Type* t = LLVM_DtoType(type); if (type->ty == Tarray) { assert(llvm::isa<llvm::StructType>(t)); return llvm::ConstantAggregateZero::get(t); } else { return llvm::Constant::getNullValue(t); } assert(0); return NULL; } ////////////////////////////////////////////////////////////////////////////////////////// elem* StringExp::toElem(IRState* p) { Logger::print("StringExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; Type* dtype = LLVM_DtoDType(type); assert(dtype->next->ty == Tchar && "Only char is supported"); assert(sz == 1); const llvm::Type* ct = LLVM_DtoType(dtype->next); //printf("ct = %s\n", type->next->toChars()); const llvm::ArrayType* at = llvm::ArrayType::get(ct,len+1); uint8_t* str = (uint8_t*)string; std::string cont((char*)str, len); llvm::Constant* _init = llvm::ConstantArray::get(cont,true); llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage; llvm::GlobalVariable* gvar = new llvm::GlobalVariable(at,true,_linkage,_init,"stringliteral",gIR->module); llvm::ConstantInt* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Constant* idxs[2] = { zero, zero }; llvm::Constant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); elem* e = new elem; if (dtype->ty == Tarray) { llvm::Constant* clen = llvm::ConstantInt::get(LLVM_DtoSize_t(),len,false); 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 (p->topexp()->e2 == this) { llvm::Value* arr = p->topexp()->v; assert(arr); LLVM_DtoSetArray(arr, clen, arrptr); e->inplace = true; } else assert(0); } else if (dtype->ty == Tsarray) { const llvm::Type* dstType = llvm::PointerType::get(llvm::ArrayType::get(ct, len)); e->mem = new llvm::BitCastInst(gvar, dstType, "tmp", gIR->scopebb()); } else if (dtype->ty == Tpointer) { e->mem = arrptr; } else { assert(0); } e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* StringExp::toConstElem(IRState* p) { Logger::print("StringExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; uint8_t* str = (uint8_t*)string; std::string cont((char*)str, len); Type* t = LLVM_DtoDType(type); llvm::Constant* _init = llvm::ConstantArray::get(cont,true); if (t->ty == Tsarray) { return _init; } llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage; llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_init->getType(),true,_linkage,_init,"stringliteral",gIR->module); llvm::ConstantInt* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Constant* idxs[2] = { zero, zero }; llvm::Constant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); if (t->ty == Tpointer) { return arrptr; } if (t->ty == Tarray) { llvm::Constant* clen = llvm::ConstantInt::get(LLVM_DtoSize_t(),len,false); return LLVM_DtoConstantSlice(clen, arrptr); } assert(0); return NULL; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AssignExp::toElem(IRState* p) { Logger::print("AssignExp::toElem: %s | %s = %s\n", toChars(), e1->type->toChars(), e2->type->toChars()); LOG_SCOPE; p->exps.push_back(IRExp(e1,e2,NULL)); elem* l = e1->toElem(p); p->topexp()->v = l->mem; elem* r = e2->toElem(p); p->exps.pop_back(); if (l->type == elem::ARRAYLEN) { LLVM_DtoResizeDynArray(l->mem, r->getValue()); delete r; delete l; return 0; } // handle function argument - allocate temp storage for it :/ annoying if (l->mem == 0) { assert(l->val); if (llvm::isa<llvm::Argument>(l->val)) LLVM_DtoGiveArgumentStorage(l); else { Logger::cout() << "here it comes... " << *l->val << '\n'; assert(0); } } //e->val = l->store(r->getValue()); Type* e1type = LLVM_DtoDType(e1->type); Type* e2type = LLVM_DtoDType(e2->type); TY e1ty = e1type->ty; TY e2ty = e2type->ty; elem* e = new elem; e->type = elem::VAR; // struct if (e1ty == Tstruct) { e->mem = l->mem; // struct + struct if (e2ty == Tstruct) { // struct literals do the assignment themselvs (in place) if (!r->inplace) { LLVM_DtoStructCopy(l->mem,r->getValue()); } else { e->inplace = true; } } // struct + const int else if (e2type->isintegral()){ IntegerExp* iexp = (IntegerExp*)e2; assert(iexp->value == 0 && "Only integral struct initializer allowed is zero"); LLVM_DtoStructZeroInit(l->mem); } // :x else assert(0 && "struct = unknown"); } else if (e1ty == Tsarray) { assert(0 && "static array not supported"); } else if (e1ty == Tarray) { if (e2type->isscalar() || e2type->ty == Tclass){ LLVM_DtoArrayInit(l->mem, r->getValue()); } else if (e2ty == Tarray) { //new llvm::StoreInst(r->val,l->val,p->scopebb()); if (r->type == elem::NUL) { llvm::Constant* c = llvm::cast<llvm::Constant>(r->val); assert(c->isNullValue()); LLVM_DtoNullArray(l->mem); e->mem = l->mem; } else if (r->type == elem::SLICE) { if (l->type == elem::SLICE) { LLVM_DtoArrayCopy(l,r); e->type = elem::SLICE; e->mem = l->mem; e->arg = l->arg; } else { LLVM_DtoSetArray(l->mem,r->arg,r->mem); e->mem = l->mem; } } else { // new expressions write directly to the array reference // so do string literals e->mem = l->mem; if (!r->inplace) { assert(r->mem); LLVM_DtoArrayAssign(l->mem, r->mem); } else { e->inplace = true; } } } else assert(0); } else if (e1ty == Tpointer) { e->mem = l->mem; if (e2ty == Tpointer) { llvm::Value* v = r->field ? r->mem : r->getValue(); Logger::cout() << "*=*: " << *v << ", " << *l->mem << '\n'; new llvm::StoreInst(v, l->mem, p->scopebb()); } else assert(0); } else if (e1ty == Tclass) { if (e2ty == Tclass) { llvm::Value* tmp = r->getValue(); Logger::cout() << "tmp: " << *tmp << " ||| " << *l->mem << '\n'; // assignment to this in constructor special case if (l->isthis) { FuncDeclaration* fdecl = p->func().decl; // respecify the this param if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar)) fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", p->topallocapoint()); new llvm::StoreInst(tmp, fdecl->llvmThisVar, p->scopebb()); e->mem = fdecl->llvmThisVar; } // regular class ref -> class ref assignment else { new llvm::StoreInst(tmp, l->mem, p->scopebb()); e->mem = l->mem; } } else assert(0); } else if (e1ty == Tdelegate) { Logger::println("Assigning to delegate"); if (e2ty == Tdelegate) { if (r->type == elem::NUL) { llvm::Constant* c = llvm::cast<llvm::Constant>(r->val); if (c->isNullValue()) { LLVM_DtoNullDelegate(l->mem); e->mem = l->mem; } else assert(0); } else if (r->inplace) { // do nothing e->inplace = true; e->mem = l->mem; } else { LLVM_DtoDelegateCopy(l->mem, r->getValue()); e->mem = l->mem; } } else assert(0); } // !struct && !array && !pointer && !class else { Logger::cout() << *l->mem << '\n'; new llvm::StoreInst(r->getValue(),l->mem,p->scopebb()); e->mem = l->mem; } delete r; delete l; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AddExp::toElem(IRState* p) { Logger::print("AddExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(type); Type* e1type = LLVM_DtoDType(e1->type); Type* e2type = LLVM_DtoDType(e2->type); if (e1type != e2type) { if (e1type->ty == Tpointer && e1type->next->ty == Tstruct) { //assert(l->field); assert(r->type == elem::CONST); llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->val); TypeStruct* ts = (TypeStruct*)e1type->next; std::vector<unsigned> offsets(1,0); ts->sym->offsetToIndex(t->next, cofs->getZExtValue(), offsets); e->mem = LLVM_DtoGEP(l->getValue(), offsets, "tmp", p->scopebb()); e->type = elem::VAR; e->field = true; } else if (e1->type->ty == Tpointer) { e->val = new llvm::GetElementPtrInst(l->getValue(), r->getValue(), "tmp", p->scopebb()); e->type = elem::VAR; } else { assert(0); } } else { e->val = llvm::BinaryOperator::createAdd(l->getValue(), r->getValue(), "tmp", p->scopebb()); e->type = elem::VAL; } delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AddAssignExp::toElem(IRState* p) { Logger::print("AddAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* e1type = LLVM_DtoDType(e1->type); elem* e = new elem; llvm::Value* val = 0; if (e1type->ty == Tpointer) { val = e->mem = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb()); } else { val = e->val = llvm::BinaryOperator::createAdd(l->getValue(),r->getValue(),"tmp",p->scopebb()); } /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; if (llvm::isa<llvm::PointerType>(storeVal->getType()) && storeVal->getType()->getContainedType(0) != tmp->getType()) { tmp = LLVM_DtoPointedType(storeVal, tmp); }*/ if (l->mem == 0) LLVM_DtoGiveArgumentStorage(l); new llvm::StoreInst(val,l->mem,p->scopebb()); e->type = elem::VAR; delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* MinExp::toElem(IRState* p) { Logger::print("MinExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); llvm::Value* left = l->getValue(); if (llvm::isa<llvm::PointerType>(left->getType())) left = new llvm::PtrToIntInst(left,LLVM_DtoSize_t(),"tmp",p->scopebb()); llvm::Value* right = r->getValue(); if (llvm::isa<llvm::PointerType>(right->getType())) right = new llvm::PtrToIntInst(right,LLVM_DtoSize_t(),"tmp",p->scopebb()); e->val = llvm::BinaryOperator::createSub(left,right,"tmp",p->scopebb()); e->type = elem::VAL; const llvm::Type* totype = LLVM_DtoType(type); if (e->val->getType() != totype) { assert(0); assert(llvm::isa<llvm::PointerType>(e->val->getType())); assert(llvm::isa<llvm::IntegerType>(totype)); e->val = new llvm::IntToPtrInst(e->val,totype,"tmp",p->scopebb()); } delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* MinAssignExp::toElem(IRState* p) { Logger::print("MinAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* e1type = LLVM_DtoDType(e1->type); llvm::Value* tmp = 0; if (e1type->ty == Tpointer) { tmp = r->getValue(); llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false); tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb()); tmp = new llvm::GetElementPtrInst(l->getValue(),tmp,"tmp",p->scopebb()); } else { tmp = llvm::BinaryOperator::createSub(l->getValue(),r->getValue(),"tmp",p->scopebb()); } /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; if (storeVal->getType()->getContainedType(0) != tmp->getType()) { tmp = LLVM_DtoPointedType(storeVal, tmp); }*/ if (l->mem == 0) LLVM_DtoGiveArgumentStorage(l); new llvm::StoreInst(tmp, l->mem, p->scopebb()); delete l; delete r; elem* e = new elem; e->val = tmp; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* MulExp::toElem(IRState* p) { Logger::print("MulExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); llvm::Value* vl = l->getValue(); llvm::Value* vr = r->getValue(); Logger::cout() << "mul: " << *vl << ", " << *vr << '\n'; e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb()); e->type = elem::VAL; delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* MulAssignExp::toElem(IRState* p) { Logger::print("MulAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); llvm::Value* vl = l->getValue(); llvm::Value* vr = r->getValue(); Logger::cout() << "mulassign: " << *vl << ", " << *vr << '\n'; llvm::Value* tmp = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb()); /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; if (storeVal->getType()->getContainedType(0) != tmp->getType()) { tmp = LLVM_DtoPointedType(storeVal, tmp); }*/ if (l->mem == 0) LLVM_DtoGiveArgumentStorage(l); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; elem* e = new elem; e->val = tmp; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* DivExp::toElem(IRState* p) { Logger::print("DivExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(type); if (t->isunsigned()) e->val = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isintegral()) e->val = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isfloating()) e->val = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); e->type = elem::VAL; delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* DivAssignExp::toElem(IRState* p) { Logger::print("DivAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(type); llvm::Value* tmp; if (t->isunsigned()) tmp = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isintegral()) tmp = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isfloating()) tmp = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; if (storeVal->getType()->getContainedType(0) != tmp->getType()) { tmp = LLVM_DtoPointedType(storeVal, tmp); }*/ if (l->mem == 0) LLVM_DtoGiveArgumentStorage(l); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; elem* e = new elem; e->val = tmp; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ModExp::toElem(IRState* p) { Logger::print("ModExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(type); if (t->isunsigned()) e->val = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isintegral()) e->val = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isfloating()) e->val = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); e->type = elem::VAL; delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ModAssignExp::toElem(IRState* p) { Logger::print("ModAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(type); llvm::Value* tmp; if (t->isunsigned()) tmp = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isintegral()) tmp = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else if (t->isfloating()) tmp = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; if (storeVal->getType()->getContainedType(0) != tmp->getType()) { tmp = LLVM_DtoPointedType(storeVal, tmp); }*/ if (l->mem == 0) LLVM_DtoGiveArgumentStorage(l); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; elem* e = new elem; e->val = tmp; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CallExp::toElem(IRState* p) { Logger::print("CallExp::toElem: %s\n", toChars()); LOG_SCOPE; elem* e = new elem; elem* fn = e1->toElem(p); LINK dlink = LINKdefault; bool delegateCall = false; llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty,1,false); // hidden struct return parameter handling bool retinptr = false; TypeFunction* tf = 0; Type* e1type = LLVM_DtoDType(e1->type); // regular functions if (e1type->ty == Tfunction) { tf = (TypeFunction*)e1type; if (tf->llvmRetInPtr) { retinptr = true; } dlink = tf->linkage; } // delegates else if (e1type->ty == Tdelegate) { Logger::println("delegateTy = %s\n", e1type->toChars()); assert(e1type->next->ty == Tfunction); tf = (TypeFunction*)e1type->next; if (tf->llvmRetInPtr) { retinptr = true; } dlink = tf->linkage; delegateCall = true; } // invalid else { assert(tf); } size_t n = arguments->dim; if (fn->arg || delegateCall) n++; if (retinptr) n++; llvm::Value* funcval = fn->getValue(); assert(funcval != 0); std::vector<llvm::Value*> llargs(n, 0); const llvm::FunctionType* llfnty = 0; // normal function call if (llvm::isa<llvm::FunctionType>(funcval->getType())) { llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()); } // pointer to something else if (llvm::isa<llvm::PointerType>(funcval->getType())) { // pointer to function pointer - I think this not really supposed to happen, but does :/ // seems like sometimes we get a func* other times a func** if (llvm::isa<llvm::PointerType>(funcval->getType()->getContainedType(0))) { funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); } // function pointer if (llvm::isa<llvm::FunctionType>(funcval->getType()->getContainedType(0))) { //Logger::cout() << "function pointer type:\n" << *funcval << '\n'; llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()->getContainedType(0)); } // struct pointer - delegate else if (llvm::isa<llvm::StructType>(funcval->getType()->getContainedType(0))) { funcval = LLVM_DtoGEP(funcval,zero,one,"tmp",p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); const llvm::Type* ty = funcval->getType()->getContainedType(0); llfnty = llvm::cast<llvm::FunctionType>(ty); } // unknown else { Logger::cout() << "what kind of pointer are we calling? : " << *funcval->getType() << '\n'; } } else { Logger::cout() << "what are we calling? : " << *funcval << '\n'; } assert(llfnty); //Logger::cout() << "Function LLVM type: " << *llfnty << '\n'; // argument handling llvm::FunctionType::param_iterator argiter = llfnty->param_begin(); int j = 0; Logger::println("hidden struct return"); IRExp* topexp = p->topexp(); // hidden struct return arguments if (retinptr) { if (topexp && topexp->e2 == this) { assert(topexp->v); assert(llvm::isa<llvm::StructType>(topexp->v->getType()->getContainedType(0))); llargs[j] = topexp->v; if (LLVM_DtoIsPassedByRef(tf->next)) { e->inplace = true; } else assert(0); } else { llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint()); } ++j; ++argiter; e->type = elem::VAR; } else { e->type = elem::VAL; } Logger::println("this arguments"); // this arguments if (fn->arg) { Logger::println("This Call"); if (fn->arg->getType() != argiter->get()) { //Logger::cout() << *fn->thisparam << '|' << *argiter->get() << '\n'; llargs[j] = new llvm::BitCastInst(fn->arg, argiter->get(), "tmp", p->scopebb()); } else { llargs[j] = fn->arg; } ++j; ++argiter; } // delegate context arguments else if (delegateCall) { Logger::println("Delegate Call"); llvm::Value* contextptr = LLVM_DtoGEP(fn->mem,zero,zero,"tmp",p->scopebb()); llargs[j] = new llvm::LoadInst(contextptr,"tmp",p->scopebb()); ++j; ++argiter; } Logger::println("regular arguments"); // regular arguments for (int i=0; i<arguments->dim; i++,j++) { Argument* fnarg = Argument::getNth(tf->parameters, i); llargs[j] = LLVM_DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]); } // void returns cannot not be named const char* varname = ""; if (llfnty->getReturnType() != llvm::Type::VoidTy) varname = "tmp"; Logger::println("%d params passed", n); for (int i=0; i<n; ++i) { Logger::cout() << *llargs[i] << '\n'; } //Logger::cout() << "Calling: " << *funcval->getType() << '\n'; // call the function llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb()); if (retinptr) e->mem = llargs[0]; else e->val = call; // set calling convention if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall) call->setCallingConv(LLVM_DtoCallingConv(dlink)); else if (fn->callconv != (unsigned)-1) call->setCallingConv(fn->callconv); delete fn; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CastExp::toElem(IRState* p) { Logger::print("CastExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* u = e1->toElem(p); const llvm::Type* tolltype = LLVM_DtoType(to); Type* fromtype = LLVM_DtoDType(e1->type); Type* totype = LLVM_DtoDType(to); int lsz = fromtype->size(); int rsz = totype->size(); // this makes sure the strange lvalue casts don't screw things up e->mem = u->mem; if (fromtype->isintegral()) { if (totype->isintegral()) { if (lsz < rsz) { Logger::cout() << *tolltype << '\n'; if (fromtype->isunsigned() || fromtype->ty == Tbool) { e->val = new llvm::ZExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else { e->val = new llvm::SExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); } } else if (lsz > rsz) { e->val = new llvm::TruncInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else { e->val = new llvm::BitCastInst(u->getValue(), tolltype, "tmp", p->scopebb()); } } else if (totype->isfloating()) { if (fromtype->isunsigned()) { e->val = new llvm::UIToFPInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else { e->val = new llvm::SIToFPInst(u->getValue(), tolltype, "tmp", p->scopebb()); } } else { assert(0); } //e->storeVal = u->storeVal ? u->storeVal : u->val; e->type = elem::VAL; } else if (fromtype->isfloating()) { if (totype->isfloating()) { if ((fromtype->ty == Tfloat80 || fromtype->ty == Tfloat64) && (totype->ty == Tfloat80 || totype->ty == Tfloat64)) { e->val = u->getValue(); } else if (lsz < rsz) { e->val = new llvm::FPExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else if (lsz > rsz) { e->val = new llvm::FPTruncInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else { assert(0); } } else if (totype->isintegral()) { if (totype->isunsigned()) { e->val = new llvm::FPToUIInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else { e->val = new llvm::FPToSIInst(u->getValue(), tolltype, "tmp", p->scopebb()); } } else { assert(0); } e->type = elem::VAL; } else if (fromtype->ty == Tclass) { //assert(to->ty == Tclass); e->val = new llvm::BitCastInst(u->getValue(), tolltype, "tmp", p->scopebb()); e->type = elem::VAL; } else if (fromtype->ty == Tarray || fromtype->ty == Tsarray) { Logger::cout() << "from array or sarray" << '\n'; if (totype->ty == Tpointer) { Logger::cout() << "to pointer" << '\n'; assert(fromtype->next == totype->next); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); llvm::Value* ptr = LLVM_DtoGEP(u->getValue(),zero,one,"tmp",p->scopebb()); e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb()); e->type = elem::VAL; } else if (totype->ty == Tarray) { Logger::cout() << "to array" << '\n'; const llvm::Type* ptrty = LLVM_DtoType(totype->next); if (ptrty == llvm::Type::VoidTy) ptrty = llvm::Type::Int8Ty; ptrty = llvm::PointerType::get(ptrty); const llvm::Type* ety = LLVM_DtoType(fromtype->next); if (ety == llvm::Type::VoidTy) ety = llvm::Type::Int8Ty; if (u->type == elem::SLICE) { e->mem = new llvm::BitCastInst(u->mem, ptrty, "tmp", p->scopebb()); if (fromtype->next->size() == totype->next->size()) e->arg = u->arg; else e->arg = LLVM_DtoArrayCastLength(u->arg, ety, ptrty->getContainedType(0)); } else { llvm::Value* uval = u->getValue(); if (fromtype->ty == Tsarray) { Logger::cout() << "uvalTy = " << *uval->getType() << '\n'; assert(llvm::isa<llvm::PointerType>(uval->getType())); const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(uval->getType()->getContainedType(0)); e->arg = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false); e->arg = LLVM_DtoArrayCastLength(e->arg, ety, ptrty->getContainedType(0)); e->mem = new llvm::BitCastInst(uval, ptrty, "tmp", p->scopebb()); } else { llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); e->arg = LLVM_DtoGEP(uval,zero,zero,"tmp",p->scopebb()); e->arg = new llvm::LoadInst(e->arg, "tmp", p->scopebb()); e->arg = LLVM_DtoArrayCastLength(e->arg, ety, ptrty->getContainedType(0)); e->mem = LLVM_DtoGEP(uval,zero,one,"tmp",p->scopebb()); e->mem = new llvm::LoadInst(e->mem, "tmp", p->scopebb()); //Logger::cout() << *e->mem->getType() << '|' << *ptrty << '\n'; e->mem = new llvm::BitCastInst(e->mem, ptrty, "tmp", p->scopebb()); } } e->type = elem::SLICE; } else if (totype->ty == Tsarray) { Logger::cout() << "to sarray" << '\n'; assert(0); } else { assert(0); } } else if (fromtype->ty == Tpointer) { if (totype->ty == Tpointer || totype->ty == Tclass) { llvm::Value* src = u->getValue(); //Logger::cout() << *src << '|' << *totype << '\n'; e->val = new llvm::BitCastInst(src, tolltype, "tmp", p->scopebb()); } else if (totype->isintegral()) { e->val = new llvm::PtrToIntInst(u->getValue(), tolltype, "tmp", p->scopebb()); } else assert(0); e->type = elem::VAL; } else { assert(0); } delete u; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* SymOffExp::toElem(IRState* p) { Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = 0; if (VarDeclaration* vd = var->isVarDeclaration()) { Logger::println("VarDeclaration"); if (!vd->llvmTouched && vd->isDataseg()) vd->toObjFile(); if (vd->isTypedefDeclaration()) { e->istypeinfo = true; } assert(vd->llvmValue); Type* t = LLVM_DtoDType(type); Type* vdtype = LLVM_DtoDType(vd->type); llvm::Value* llvalue = vd->nestedref ? LLVM_DtoNestedVariable(vd) : vd->llvmValue; if (vdtype->ty == Tstruct && !(t->ty == Tpointer && t->next == vdtype)) { TypeStruct* vdt = (TypeStruct*)vdtype; e = new elem; std::vector<unsigned> dst(1,0); vdt->sym->offsetToIndex(t->next, offset, dst); llvm::Value* ptr = llvalue; assert(ptr); e->mem = LLVM_DtoGEP(ptr,dst,"tmp",p->scopebb()); e->type = elem::VAL; e->field = true; } else if (vdtype->ty == Tsarray) { /*e = new elem; llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); e->val = new llvm::GetElementPtrInst(vd->llvmValue,idx0,idx0,"tmp",p->scopebb());*/ e = new elem; llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); //llvm::Value* idx1 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); e->mem = LLVM_DtoGEP(llvalue,idx0,idx0,"tmp",p->scopebb()); e->arg = llvalue; e->type = elem::VAL; } else if (offset == 0) { e = new elem; assert(llvalue); e->mem = llvalue; const llvm::Type* llt = LLVM_DtoType(t); if (llvalue->getType() != llt) { Logger::cout() << "llt is:" << *llt << '\n'; //const llvm::PointerType* vpty = llvm::PointerType::get(llvm::Type::Int8Ty); e->mem = p->ir->CreateBitCast(e->mem, llt, "tmp"); } e->type = elem::VAL; } else { assert(0); } } else if (FuncDeclaration* fd = var->isFuncDeclaration()) { Logger::println("FuncDeclaration"); e = new elem; if (fd->llvmValue == 0) fd->toObjFile(); e->val = fd->llvmValue; e->type = elem::FUNC; } assert(e != 0); assert(e->type != elem::NONE); return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* PtrExp::toElem(IRState* p) { Logger::print("PtrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* a = e1->toElem(p); if (a->mem) Logger::cout() << "mem: " << *a->mem << '\n'; if (a->val) Logger::cout() << "val: " << *a->val << '\n'; if (a->field) e->mem = a->mem; else e->mem = a->getValue(); e->type = elem::VAR; delete a; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* DotVarExp::toElem(IRState* p) { Logger::print("DotVarExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); Type* t = LLVM_DtoDType(type); Type* e1type = LLVM_DtoDType(e1->type); Logger::print("e1->type=%s\n", e1type->toChars()); if (VarDeclaration* vd = var->isVarDeclaration()) { std::vector<unsigned> vdoffsets(1,0); llvm::Value* src = 0; if (e1type->ty == Tpointer) { assert(e1type->next->ty == Tstruct); TypeStruct* ts = (TypeStruct*)e1type->next; ts->sym->offsetToIndex(vd->type, vd->offset, vdoffsets); Logger::println("Struct member offset:%d", vd->offset); src = l->val ? l->val : l->mem; } else if (e1->type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1type; Logger::println("Class member offset: %d", vd->offset); tc->sym->offsetToIndex(vd->type, vd->offset, vdoffsets); src = l->getValue(); } assert(vdoffsets.size() != 1); assert(src != 0); Logger::cout() << "src: " << *src << '\n'; llvm::Value* arrptr = LLVM_DtoGEP(src,vdoffsets,"tmp",p->scopebb()); e->mem = arrptr; Logger::cout() << "mem: " << *e->mem << '\n'; e->type = elem::VAR; } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) { if (fdecl->llvmValue == 0) { fdecl->toObjFile(); } llvm::Value* funcval = fdecl->llvmValue; e->arg = l->getValue(); // virtual call if (fdecl->isVirtual()) { assert(fdecl->vtblIndex > 0); assert(e1type->ty == Tclass); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* vtblidx = llvm::ConstantInt::get(llvm::Type::Int32Ty, (size_t)fdecl->vtblIndex, false); funcval = LLVM_DtoGEP(e->arg, zero, zero, "tmp", p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); funcval = LLVM_DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); assert(funcval->getType() == fdecl->llvmValue->getType()); e->callconv = LLVM_DtoCallingConv(fdecl->linkage); } e->val = funcval; e->type = elem::VAL; } else { printf("unknown: %s\n", var->toChars()); assert(0); } delete l; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ThisExp::toElem(IRState* p) { Logger::print("ThisExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; if (VarDeclaration* vd = var->isVarDeclaration()) { llvm::Value* v = p->func().decl->llvmThisVar; if (llvm::isa<llvm::AllocaInst>(v)) v = new llvm::LoadInst(v, "tmp", p->scopebb()); e->mem = v; e->type = elem::VAL; e->isthis = true; } else { assert(0); } return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AddrExp::toElem(IRState* p) { Logger::print("AddrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = e1->toElem(p); e->field = true; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* StructLiteralExp::toElem(IRState* p) { Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; llvm::Value* sptr = 0; // if there is no lval, this is probably a temporary struct literal. correct? 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 if (p->topexp()->e2 == this) { sptr = p->topexp()->v; } else assert(0); assert(sptr); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); unsigned n = elements->dim; for (unsigned i=0; i<n; ++i) { llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false); llvm::Value* arrptr = LLVM_DtoGEP(sptr,zero,offset,"tmp",p->scopebb()); Expression* vx = (Expression*)elements->data[i]; if (vx != 0) { p->exps.push_back(IRExp(NULL,vx,arrptr)); elem* ve = vx->toElem(p); p->exps.pop_back(); if (!ve->inplace) { llvm::Value* val = ve->getValue(); Logger::cout() << *val << " | " << *arrptr << '\n'; Type* vxtype = LLVM_DtoDType(vx->type); LLVM_DtoAssign(vxtype, arrptr, val); } delete ve; } else { assert(0); } } e->inplace = true; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* StructLiteralExp::toConstElem(IRState* p) { Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; unsigned n = elements->dim; std::vector<llvm::Constant*> vals(n, NULL); for (unsigned i=0; i<n; ++i) { Expression* vx = (Expression*)elements->data[i]; vals[i] = vx->toConstElem(p); } assert(LLVM_DtoDType(type)->ty == Tstruct); const llvm::Type* t = LLVM_DtoType(type); const llvm::StructType* st = llvm::cast<llvm::StructType>(t); return llvm::ConstantStruct::get(st,vals); } ////////////////////////////////////////////////////////////////////////////////////////// elem* IndexExp::toElem(IRState* p) { Logger::print("IndexExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); Type* e1type = LLVM_DtoDType(e1->type); p->arrays.push_back(l->mem); // if $ is used it must be an array so this is fine. elem* r = e2->toElem(p); p->arrays.pop_back(); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); llvm::Value* arrptr = 0; if (e1type->ty == Tpointer) { arrptr = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { arrptr = LLVM_DtoGEP(l->getValue(), zero, r->getValue(),"tmp",p->scopebb()); } else if (e1type->ty == Tarray) { arrptr = LLVM_DtoGEP(l->mem,zero,one,"tmp",p->scopebb()); arrptr = new llvm::LoadInst(arrptr,"tmp",p->scopebb()); arrptr = new llvm::GetElementPtrInst(arrptr,r->getValue(),"tmp",p->scopebb()); } assert(arrptr); e->mem = arrptr; e->type = elem::VAR; delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* SliceExp::toElem(IRState* p) { Logger::print("SliceExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; Type* t = LLVM_DtoDType(type); assert(t->ty == Tarray); elem* v = e1->toElem(p); Type* e1type = LLVM_DtoDType(e1->type); elem* e = new elem; assert(v->mem); e->type = elem::SLICE; llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); // partial slice if (lwr) { assert(upr); p->arrays.push_back(v->mem); elem* lo = lwr->toElem(p); bool lwr_is_zero = false; if (lo->type == elem::CONST) { assert(lo->val); assert(llvm::isa<llvm::ConstantInt>(lo->val)); if (e1type->ty == Tpointer) { e->mem = v->getValue(); } else if (e1type->ty == Tarray) { llvm::Value* tmp = LLVM_DtoGEP(v->mem,zero,one,"tmp",p->scopebb()); e->mem = new llvm::LoadInst(tmp,"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { e->mem = LLVM_DtoGEP(v->mem,zero,zero,"tmp",p->scopebb()); } else assert(e->mem); llvm::ConstantInt* c = llvm::cast<llvm::ConstantInt>(lo->val); if (!(lwr_is_zero = c->isZero())) { e->mem = new llvm::GetElementPtrInst(e->mem,lo->val,"tmp",p->scopebb()); } } else { if (e1type->ty == Tarray) { llvm::Value* tmp = LLVM_DtoGEP(v->mem,zero,one,"tmp",p->scopebb()); tmp = new llvm::LoadInst(tmp,"tmp",p->scopebb()); e->mem = new llvm::GetElementPtrInst(tmp,lo->getValue(),"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { e->mem = LLVM_DtoGEP(v->mem,zero,lo->getValue(),"tmp",p->scopebb()); } else assert(0); } elem* up = upr->toElem(p); p->arrays.pop_back(); if (up->type == elem::CONST) { assert(up->val); assert(llvm::isa<llvm::ConstantInt>(up->val)); if (lwr_is_zero) { e->arg = up->val; } else { if (lo->type == elem::CONST) { llvm::Constant* clo = llvm::cast<llvm::Constant>(lo->val); llvm::Constant* cup = llvm::cast<llvm::Constant>(up->val); e->arg = llvm::ConstantExpr::getSub(cup, clo); } else { e->arg = llvm::BinaryOperator::createSub(up->val, lo->getValue(), "tmp", p->scopebb()); } } } else { if (lwr_is_zero) { e->arg = up->getValue(); } else { e->arg = llvm::BinaryOperator::createSub(up->getValue(), lo->getValue(), "tmp", p->scopebb()); } } delete lo; delete up; /* llvm::Value* tmpmem = new llvm::AllocaInst(LLVM_DtoType(t),"tmp",p->topallocapoint()); llvm::Value* ptr = LLVM_DtoGEPi(tmpmem,0,0,"tmp"); p->ir->CreateStore(e->arg, ptr); ptr = LLVM_DtoGEPi(tmpmem,0,1,"tmp"); p->ir->CreateStore(e->mem, ptr); e->arg = NULL; e->mem = tmpmem; */ } // full slice else { e->mem = v->mem; } delete v; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CmpExp::toElem(IRState* p) { Logger::print("CmpExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(e1->type); Type* e2t = LLVM_DtoDType(e2->type); assert(t == e2t); if (t->isintegral()) { llvm::ICmpInst::Predicate cmpop; bool skip = false; switch(op) { case TOKlt: case TOKul: cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULT : llvm::ICmpInst::ICMP_SLT; break; case TOKle: case TOKule: cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULE : llvm::ICmpInst::ICMP_SLE; break; case TOKgt: case TOKug: cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGT : llvm::ICmpInst::ICMP_SGT; break; case TOKge: case TOKuge: cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGE : llvm::ICmpInst::ICMP_SGE; break; case TOKue: cmpop = llvm::ICmpInst::ICMP_EQ; break; case TOKlg: cmpop = llvm::ICmpInst::ICMP_NE; break; case TOKleg: skip = true; e->val = llvm::ConstantInt::getTrue(); break; case TOKunord: skip = true; e->val = llvm::ConstantInt::getFalse(); break; default: assert(0); } if (!skip) { e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); } } else if (t->isfloating()) { llvm::FCmpInst::Predicate cmpop; switch(op) { case TOKlt: cmpop = llvm::FCmpInst::FCMP_OLT;break; case TOKle: cmpop = llvm::FCmpInst::FCMP_OLE;break; case TOKgt: cmpop = llvm::FCmpInst::FCMP_OGT;break; case TOKge: cmpop = llvm::FCmpInst::FCMP_OGE;break; case TOKunord: cmpop = llvm::FCmpInst::FCMP_UNO;break; case TOKule: cmpop = llvm::FCmpInst::FCMP_ULE;break; case TOKul: cmpop = llvm::FCmpInst::FCMP_ULT;break; case TOKuge: cmpop = llvm::FCmpInst::FCMP_UGE;break; case TOKug: cmpop = llvm::FCmpInst::FCMP_UGT;break; case TOKue: cmpop = llvm::FCmpInst::FCMP_UEQ;break; case TOKlg: cmpop = llvm::FCmpInst::FCMP_ONE;break; case TOKleg: cmpop = llvm::FCmpInst::FCMP_ORD;break; default: assert(0); } e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); } else { assert(0 && "Unsupported CmpExp type"); } delete l; delete r; e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* EqualExp::toElem(IRState* p) { Logger::print("EqualExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); elem* r = e2->toElem(p); Type* t = LLVM_DtoDType(e1->type); Type* e2t = LLVM_DtoDType(e2->type); assert(t == e2t); if (t->isintegral() || t->ty == Tpointer) { llvm::ICmpInst::Predicate cmpop; switch(op) { case TOKequal: cmpop = llvm::ICmpInst::ICMP_EQ; break; case TOKnotequal: cmpop = llvm::ICmpInst::ICMP_NE; break; default: assert(0); } e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); } else if (t->isfloating()) { llvm::FCmpInst::Predicate cmpop; switch(op) { case TOKequal: cmpop = llvm::FCmpInst::FCMP_OEQ; break; case TOKnotequal: cmpop = llvm::FCmpInst::FCMP_UNE; break; default: assert(0); } e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); } else if (t->ty == Tsarray) { e->val = LLVM_DtoStaticArrayCompare(op,l->mem,r->mem); } else if (t->ty == Tarray) { e->val = LLVM_DtoDynArrayCompare(op,l->mem,r->mem); } else if (t->ty == Tdelegate) { e->val = LLVM_DtoCompareDelegate(op,l->mem,r->mem); } else { assert(0 && "Unsupported EqualExp type"); } delete l; delete r; e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* PostExp::toElem(IRState* p) { Logger::print("PostExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* l = e1->toElem(p); elem* r = e2->toElem(p); elem* e = new elem; e->mem = l->mem; e->val = l->getValue(); e->type = elem::VAL; llvm::Value* val = e->val; llvm::Value* post = 0; Type* e1type = LLVM_DtoDType(e1->type); Type* e2type = LLVM_DtoDType(e2->type); if (e1type->isintegral()) { assert(e2type->isintegral()); llvm::Value* one = llvm::ConstantInt::get(val->getType(), 1, !e2type->isunsigned()); if (op == TOKplusplus) { post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb()); } else if (op == TOKminusminus) { post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb()); } } else if (e1type->ty == Tpointer) { assert(e2type->isintegral()); llvm::Constant* minusone = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)-1,true); llvm::Constant* plusone = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)1,false); llvm::Constant* whichone = (op == TOKplusplus) ? plusone : minusone; post = new llvm::GetElementPtrInst(val, whichone, "tmp", p->scopebb()); } else if (e1type->isfloating()) { assert(e2type->isfloating()); llvm::Value* one = llvm::ConstantFP::get(val->getType(), 1.0f); if (op == TOKplusplus) { post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb()); } else if (op == TOKminusminus) { post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb()); } } else assert(post); //llvm::Value* tostore = l->storeVal ? l->storeVal : l->val; new llvm::StoreInst(post,l->mem,p->scopebb()); delete l; delete r; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* NewExp::toElem(IRState* p) { Logger::print("NewExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; assert(!thisexp); assert(!newargs); assert(newtype); assert(!allocator); elem* e = new elem; Type* ntype = LLVM_DtoDType(newtype); const llvm::Type* t = LLVM_DtoType(ntype); if (onstack) { assert(ntype->ty == Tclass); e->mem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint()); } else { if (ntype->ty == Tclass) { e->mem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb()); } else if (ntype->ty == Tarray) { assert(arguments); if (arguments->dim == 1) { elem* sz = ((Expression*)arguments->data[0])->toElem(p); llvm::Value* dimval = sz->getValue(); assert(p->topexp() && p->topexp()->e2 == this && p->topexp()->v); LLVM_DtoNewDynArray(p->topexp()->v, dimval, ntype->next); delete sz; } else { assert(0); } } else { e->mem = new llvm::MallocInst(t,"tmp",p->scopebb()); } } if (ntype->ty == Tclass) { // first apply the static initializer assert(e->mem); LLVM_DtoInitClass((TypeClass*)ntype, e->mem); // then call constructor if (arguments) { assert(member); assert(member->llvmValue); llvm::Function* fn = llvm::cast<llvm::Function>(member->llvmValue); TypeFunction* tf = (TypeFunction*)LLVM_DtoDType(member->type); std::vector<llvm::Value*> ctorargs; ctorargs.push_back(e->mem); for (size_t i=0; i<arguments->dim; ++i) { Expression* ex = (Expression*)arguments->data[i]; Argument* fnarg = Argument::getNth(tf->parameters, i); llvm::Value* a = LLVM_DtoArgument(fn->getFunctionType()->getParamType(i+1), fnarg, ex); ctorargs.push_back(a); } e->mem = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb()); } } else if (ntype->ty == Tstruct) { TypeStruct* ts = (TypeStruct*)ntype; if (ts->isZeroInit()) { LLVM_DtoStructZeroInit(e->mem); } else { LLVM_DtoStructCopy(e->mem,ts->llvmInit); } } e->inplace = true; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* DeleteExp::toElem(IRState* p) { Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; //assert(e1->type->ty != Tclass); elem* v = e1->toElem(p); llvm::Value* val = v->getValue(); llvm::Value* ldval = 0; const llvm::Type* t = val->getType(); llvm::Constant* z = llvm::Constant::getNullValue(t); Type* e1type = LLVM_DtoDType(e1->type); if (e1type->ty == Tpointer) { ldval = v->getValue(); new llvm::FreeInst(ldval, p->scopebb()); Logger::cout() << *z << '\n'; Logger::cout() << *val << '\n'; new llvm::StoreInst(z, v->mem, p->scopebb()); } else if (e1type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1type; LLVM_DtoCallClassDtors(tc, val); if (v->vardecl && !v->vardecl->onstack) { new llvm::FreeInst(val, p->scopebb()); } new llvm::StoreInst(z, v->mem, p->scopebb()); } else if (e1type->ty == Tarray) { // must be on the heap (correct?) ldval = v->getValue(); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); llvm::Value* ptr = LLVM_DtoGEP(ldval,zero,one,"tmp",p->scopebb()); ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb()); new llvm::FreeInst(ptr, p->scopebb()); LLVM_DtoNullArray(val); } else { assert(0); } delete v; // this expression produces no useful data return 0; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ArrayLengthExp::toElem(IRState* p) { Logger::print("ArrayLengthExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* u = e1->toElem(p); if (p->topexp() && p->topexp()->e1 == this) { e->mem = u->mem; e->type = elem::ARRAYLEN; } else { llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* ptr = LLVM_DtoGEP(u->mem,zero,zero,"tmp",p->scopebb()); e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb()); e->type = elem::VAL; } delete u; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AssertExp::toElem(IRState* p) { Logger::print("AssertExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* u = e1->toElem(p); elem* m = msg ? msg->toElem(p) : NULL; llvm::Value* loca = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false); LLVM_DtoAssert(u->getValue(), loca, m ? m->val : NULL); delete m; delete u; return new elem; } ////////////////////////////////////////////////////////////////////////////////////////// elem* NotExp::toElem(IRState* p) { Logger::print("NotExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* u = e1->toElem(p); llvm::Value* b = LLVM_DtoBoolean(u->getValue()); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, true); e->val = p->ir->CreateICmpEQ(b,zero); //e->val = new llvm::ICmpInst(llvm::ICmpInst::ICMP_EQ,b,zero,"tmp",p->scopebb()); e->type = elem::VAL; delete u; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* AndAndExp::toElem(IRState* p) { Logger::print("AndAndExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; // allocate a temporary for the final result. failed to come up with a better way :/ llvm::Value* resval = 0; llvm::BasicBlock* entryblock = &p->topfunc()->front(); resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"andandtmp",p->topallocapoint()); elem* e = new elem; elem* u = e1->toElem(p); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* andand = new llvm::BasicBlock("andand", gIR->topfunc(), oldend); llvm::BasicBlock* andandend = new llvm::BasicBlock("andandend", gIR->topfunc(), oldend); llvm::Value* ubool = LLVM_DtoBoolean(u->getValue()); new llvm::StoreInst(ubool,resval,p->scopebb()); new llvm::BranchInst(andand,andandend,ubool,p->scopebb()); p->scope() = IRScope(andand, andandend); elem* v = e2->toElem(p); llvm::Value* vbool = LLVM_DtoBoolean(v->getValue()); llvm::Value* uandvbool = llvm::BinaryOperator::create(llvm::BinaryOperator::And, ubool, vbool,"tmp",p->scopebb()); new llvm::StoreInst(uandvbool,resval,p->scopebb()); new llvm::BranchInst(andandend,p->scopebb()); delete u; delete v; p->scope() = IRScope(andandend, oldend); e->val = new llvm::LoadInst(resval,"tmp",p->scopebb()); e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* OrOrExp::toElem(IRState* p) { Logger::print("OrOrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; // allocate a temporary for the final result. failed to come up with a better way :/ llvm::Value* resval = 0; llvm::BasicBlock* entryblock = &p->topfunc()->front(); resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"orortmp",p->topallocapoint()); elem* e = new elem; elem* u = e1->toElem(p); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* oror = new llvm::BasicBlock("oror", gIR->topfunc(), oldend); llvm::BasicBlock* ororend = new llvm::BasicBlock("ororend", gIR->topfunc(), oldend); llvm::Value* ubool = LLVM_DtoBoolean(u->getValue()); new llvm::StoreInst(ubool,resval,p->scopebb()); new llvm::BranchInst(ororend,oror,ubool,p->scopebb()); p->scope() = IRScope(oror, ororend); elem* v = e2->toElem(p); llvm::Value* vbool = LLVM_DtoBoolean(v->getValue()); new llvm::StoreInst(vbool,resval,p->scopebb()); new llvm::BranchInst(ororend,p->scopebb()); delete u; delete v; p->scope() = IRScope(ororend, oldend); e->val = new llvm::LoadInst(resval,"tmp",p->scopebb()); e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// #define BinBitExp(X,Y) \ elem* X##Exp::toElem(IRState* p) \ { \ Logger::print("%sExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ LOG_SCOPE; \ elem* e = new elem; \ elem* u = e1->toElem(p); \ elem* v = e2->toElem(p); \ e->val = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getValue(), v->getValue(), "tmp", p->scopebb()); \ e->type = elem::VAL; \ delete u; \ delete v; \ return e; \ } \ \ elem* X##AssignExp::toElem(IRState* p) \ { \ Logger::print("%sAssignExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ LOG_SCOPE; \ elem* u = e1->toElem(p); \ elem* v = e2->toElem(p); \ llvm::Value* uval = u->getValue(); \ assert(uval); \ llvm::Value* vval = v->getValue(); \ assert(vval); \ llvm::Value* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, uval, vval, "tmp", p->scopebb()); \ if (u->mem == 0) \ LLVM_DtoGiveArgumentStorage(u); \ Logger::cout() << *tmp << '|' << *u->mem << '\n'; \ new llvm::StoreInst(LLVM_DtoPointedType(u->mem, tmp), u->mem, p->scopebb()); \ delete u; \ delete v; \ elem* e = new elem; \ e->mem = u->mem; \ e->type = elem::VAR; \ return e; \ } BinBitExp(And,And); BinBitExp(Or,Or); BinBitExp(Xor,Xor); BinBitExp(Shl,Shl); BinBitExp(Shr,AShr); BinBitExp(Ushr,LShr); ////////////////////////////////////////////////////////////////////////////////////////// elem* HaltExp::toElem(IRState* p) { Logger::print("HaltExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; llvm::Value* loca = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false); LLVM_DtoAssert(llvm::ConstantInt::getFalse(), loca, NULL); new llvm::UnreachableInst(p->scopebb()); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// elem* DelegateExp::toElem(IRState* p) { Logger::print("DelegateExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; 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); 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; } ////////////////////////////////////////////////////////////////////////////////////////// elem* IdentityExp::toElem(IRState* p) { Logger::print("IdentityExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* u = e1->toElem(p); elem* v = e2->toElem(p); elem* e = new elem; llvm::Value* l = u->getValue(); llvm::Value* r = 0; if (v->type == elem::NUL) r = llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(l->getType())); else r = v->getValue(); 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; delete v; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CommaExp::toElem(IRState* p) { Logger::print("CommaExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* u = e1->toElem(p); elem* v = e2->toElem(p); delete u; return v; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CondExp::toElem(IRState* p) { Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; 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(); llvm::Value* resval = new llvm::AllocaInst(resty,"condtmp",p->topallocapoint()); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* condtrue = new llvm::BasicBlock("condtrue", gIR->topfunc(), oldend); llvm::BasicBlock* condfalse = new llvm::BasicBlock("condfalse", gIR->topfunc(), oldend); llvm::BasicBlock* condend = new llvm::BasicBlock("condend", gIR->topfunc(), oldend); elem* c = econd->toElem(p); llvm::Value* cond_val = LLVM_DtoBoolean(c->getValue()); delete c; new llvm::BranchInst(condtrue,condfalse,cond_val,p->scopebb()); p->scope() = IRScope(condtrue, condfalse); elem* u = e1->toElem(p); LLVM_DtoAssign(dtype, resval, u->getValue()); new llvm::BranchInst(condend,p->scopebb()); delete u; p->scope() = IRScope(condfalse, condend); elem* v = e2->toElem(p); LLVM_DtoAssign(dtype, resval, v->getValue()); new llvm::BranchInst(condend,p->scopebb()); delete v; p->scope() = IRScope(condend, oldend); elem* e = new elem; e->mem = resval; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ComExp::toElem(IRState* p) { Logger::print("ComExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* u = e1->toElem(p); llvm::Value* value = u->getValue(); llvm::Value* minusone = llvm::ConstantInt::get(value->getType(), -1, true); e->val = llvm::BinaryOperator::create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb()); delete u; e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* NegExp::toElem(IRState* p) { Logger::print("NegExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* e = new elem; elem* l = e1->toElem(p); llvm::Value* val = l->getValue(); delete l; Type* t = LLVM_DtoDType(type); llvm::Value* zero = 0; if (t->isintegral()) zero = llvm::ConstantInt::get(val->getType(), 0, true); else if (t->isfloating()) { if (t->ty == Tfloat32) zero = llvm::ConstantFP::get(val->getType(), float(0)); else if (t->ty == Tfloat64 || t->ty == Tfloat80) zero = llvm::ConstantFP::get(val->getType(), double(0)); else assert(0); } else assert(0); e->val = llvm::BinaryOperator::createSub(zero,val,"tmp",p->scopebb()); e->type = elem::VAL; return e; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CatExp::toElem(IRState* p) { Logger::print("CatExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; assert(0 && "array cat is not yet implemented"); elem* lhs = e1->toElem(p); elem* rhs = e2->toElem(p); // determine new size delete lhs; delete rhs; return 0; } ////////////////////////////////////////////////////////////////////////////////////////// elem* CatAssignExp::toElem(IRState* p) { Logger::print("CatAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; elem* l = e1->toElem(p); assert(l->mem); Type* e1type = LLVM_DtoDType(e1->type); Type* elemtype = LLVM_DtoDType(e1type->next); Type* e2type = LLVM_DtoDType(e2->type); if (e2type == elemtype) { LLVM_DtoCatArrayElement(l->mem,e2); } else assert(0 && "only one element at a time right now"); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// elem* ArrayLiteralExp::toElem(IRState* p) { Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; const llvm::Type* t = LLVM_DtoType(type); Logger::cout() << "array literal has llvm type: " << *t << '\n'; llvm::Value* mem = 0; if (!p->topexp() || p->topexp()->e2 != this) { assert(LLVM_DtoDType(type)->ty == Tsarray); mem = new llvm::AllocaInst(t,"tmparrayliteral",p->topallocapoint()); } else if (p->topexp()->e2 == this) { mem = p->topexp()->v; assert(mem); if (!llvm::isa<llvm::PointerType>(mem->getType()) || !llvm::isa<llvm::ArrayType>(mem->getType()->getContainedType(0))) { error("TODO array literals can currently only be used to initialise static arrays"); fatal(); } } else assert(0); for (unsigned i=0; i<elements->dim; ++i) { Expression* expr = (Expression*)elements->data[i]; llvm::Value* elemAddr = LLVM_DtoGEPi(mem,0,i,"tmp",p->scopebb()); elem* e = expr->toElem(p); new llvm::StoreInst(e->getValue(), elemAddr, p->scopebb()); } elem* e = new elem; e->mem = mem; e->type = elem::VAL; e->inplace = true; return e; } ////////////////////////////////////////////////////////////////////////////////////////// llvm::Constant* ArrayLiteralExp::toConstElem(IRState* p) { Logger::print("ArrayLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; const llvm::Type* t = LLVM_DtoType(type); Logger::cout() << "array literal has llvm type: " << *t << '\n'; assert(llvm::isa<llvm::ArrayType>(t)); const llvm::ArrayType* arrtype = llvm::cast<llvm::ArrayType>(t); assert(arrtype->getNumElements() == elements->dim); std::vector<llvm::Constant*> vals(elements->dim, NULL); for (unsigned i=0; i<elements->dim; ++i) { Expression* expr = (Expression*)elements->data[i]; vals[i] = expr->toConstElem(p); } return llvm::ConstantArray::get(arrtype, vals); } ////////////////////////////////////////////////////////////////////////////////////////// elem* FuncExp::toElem(IRState* p) { Logger::print("FuncExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; assert(fd); if (fd->isNested()) Logger::println("nested"); Logger::println("kind = %s\n", fd->kind()); fd->toObjFile(); llvm::Value* lval = 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 if (p->topexp()->e2 == this) { lval = p->topexp()->v; assert(lval); } else assert(0); elem* e = new elem; llvm::Value* context = LLVM_DtoGEPi(lval,0,0,"tmp",p->scopebb()); const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(context->getType()->getContainedType(0)); llvm::Value* llvmNested = p->func().decl->llvmNested; if (llvmNested == NULL) { llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty); p->ir->CreateStore(nullcontext, context); } else { llvm::Value* nestedcontext = p->ir->CreateBitCast(llvmNested, pty, "tmp"); p->ir->CreateStore(nestedcontext, context); } llvm::Value* fptr = LLVM_DtoGEPi(lval,0,1,"tmp",p->scopebb()); assert(fd->llvmValue); llvm::Value* castfptr = new llvm::BitCastInst(fd->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb()); new llvm::StoreInst(castfptr, fptr, p->scopebb()); e->inplace = true; e->mem = lval; e->type = elem::VAR; return e; } ////////////////////////////////////////////////////////////////////////////////////////// #define STUB(x) elem *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } //STUB(IdentityExp); //STUB(CondExp); //STUB(EqualExp); STUB(InExp); //STUB(CmpExp); //STUB(AndAndExp); //STUB(OrOrExp); //STUB(AndExp); //STUB(AndAssignExp); //STUB(OrExp); //STUB(OrAssignExp); //STUB(XorExp); //STUB(XorAssignExp); //STUB(ShrExp); //STUB(ShrAssignExp); //STUB(ShlExp); //STUB(ShlAssignExp); //STUB(UshrExp); //STUB(UshrAssignExp); //STUB(DivExp); //STUB(DivAssignExp); //STUB(MulExp); //STUB(MulAssignExp); //STUB(ModExp); //STUB(ModAssignExp); //STUB(CatExp); //STUB(CatAssignExp); //STUB(AddExp); //STUB(AddAssignExp); STUB(Expression); //STUB(MinExp); //STUB(MinAssignExp); //STUB(PostExp); //STUB(NullExp); //STUB(ThisExp); //STUB(CallExp); STUB(DotTypeExp); STUB(TypeDotIdExp); //STUB(DotVarExp); //STUB(AssertExp); //STUB(FuncExp); //STUB(DelegateExp); //STUB(VarExp); //STUB(DeclarationExp); //STUB(NewExp); //STUB(SymOffExp); STUB(ScopeExp); //STUB(AssignExp); STUB(TypeExp); //STUB(RealExp); STUB(ComplexExp); //STUB(StringExp); //STUB(IntegerExp); STUB(BoolExp); //STUB(NotExp); //STUB(ComExp); //STUB(NegExp); //STUB(PtrExp); //STUB(AddrExp); //STUB(SliceExp); //STUB(CastExp); //STUB(DeleteExp); //STUB(IndexExp); //STUB(CommaExp); //STUB(ArrayLengthExp); //STUB(HaltExp); STUB(RemoveExp); //STUB(ArrayLiteralExp); 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; } CONSTSTUB(Expression); //CONSTSTUB(IntegerExp); //CONSTSTUB(RealExp); //CONSTSTUB(NullExp); //CONSTSTUB(StringExp); //CONSTSTUB(VarExp); //CONSTSTUB(ArrayLiteralExp); CONSTSTUB(AssocArrayLiteralExp); //CONSTSTUB(StructLiteralExp); unsigned Type::totym() { return 0; } type * Type::toCtype() { assert(0); return 0; } type * Type::toCParamtype() { assert(0); return 0; } Symbol * Type::toSymbol() { assert(0); return 0; } type * TypeTypedef::toCtype() { assert(0); return 0; } type * TypeTypedef::toCParamtype() { assert(0); return 0; } void TypedefDeclaration::toDebug() { assert(0); } type * TypeEnum::toCtype() { assert(0); return 0; } type * TypeStruct::toCtype() { assert(0); return 0; } void StructDeclaration::toDebug() { assert(0); } Symbol * TypeClass::toSymbol() { assert(0); return 0; } unsigned TypeFunction::totym() { assert(0); return 0; } type * TypeFunction::toCtype() { assert(0); return 0; } type * TypeSArray::toCtype() { assert(0); return 0; } type *TypeSArray::toCParamtype() { assert(0); return 0; } type * TypeDArray::toCtype() { assert(0); return 0; } type * TypeAArray::toCtype() { assert(0); return 0; } type * TypePointer::toCtype() { assert(0); return 0; } type * TypeDelegate::toCtype() { assert(0); return 0; } type * TypeClass::toCtype() { assert(0); return 0; } void ClassDeclaration::toDebug() { assert(0); } ////////////////////////////////////////////////////////////////////////////// void EnumDeclaration::toDebug() { assert(0); } int Dsymbol::cvMember(unsigned char*) { assert(0); return 0; } int EnumDeclaration::cvMember(unsigned char*) { assert(0); return 0; } int FuncDeclaration::cvMember(unsigned char*) { assert(0); return 0; } int VarDeclaration::cvMember(unsigned char*) { assert(0); return 0; } int TypedefDeclaration::cvMember(unsigned char*) { assert(0); return 0; } void obj_includelib(char*){} AsmStatement::AsmStatement(Loc loc, Token *tokens) : Statement(loc) { assert(0); } Statement *AsmStatement::syntaxCopy() { assert(0); return 0; } Statement *AsmStatement::semantic(Scope *sc) { return Statement::semantic(sc); } void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { Statement::toCBuffer(buf, hgs); } int AsmStatement::comeFrom() { assert(0); return FALSE; } void backend_init() { // now lazily loaded //LLVM_D_InitRuntime(); } void backend_term() { LLVM_D_FreeRuntime(); }