Mercurial > projects > ldc
diff gen/toir.c @ 1:c53b6e3fe49a trunk
[svn r5] Initial commit. Most things are very rough.
author | lindquist |
---|---|
date | Sat, 01 Sep 2007 21:43:27 +0200 |
parents | |
children | e116aa1488e6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/toir.c Sat Sep 01 21:43:27 2007 +0200 @@ -0,0 +1,2910 @@ +// 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 "llvm/Type.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Constants.h" +#include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/CallingConv.h" + +#include "total.h" +#include "init.h" +#include "symbol.h" +#include "mtype.h" +#include "hdrgen.h" +#include "irstate.h" +#include "elem.h" +#include "port.h" +#include "logger.h" + +#include "tollvm.h" +#include "runtime.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"); + + // handle const + // TODO probably not correct + bool isconst = (vd->storage_class & STCconst) != 0; + + // allocate storage on the stack + Logger::println("vdtype = %s", vd->type->toChars()); + 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; + // e->val = really needed?? + + LLVM_DtoInitializer(vd->type, vd->init); + } + // struct declaration + else if (StructDeclaration* s = declaration->isStructDeclaration()) + { + Logger::println("StructDeclaration"); + s->toObjFile(); + } + // unsupported declaration + else + { + error("Only Var/Struct-Declaration is supported for DeclarationExp"); + fatal(); + } + 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 (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) + { + Logger::println("TypeInfoDeclaration"); + } + + // this must be a dollar expression or some other magic value + if (!vd->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()); + e->val = new llvm::LoadInst(tmp,"tmp",p->scopebb()); + e->type = elem::VAL; + } + // magic + else + { + if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) + { + tid->toObjFile(); + e->mem = tid->llvmValue; + e->type = elem::VAR; + } + else + assert(0 && "only magic supported is typeinfo"); + } + return e; + } + + // function parameter + if (vd->storage_class & STCparameter) { + Logger::println("function param"); + if (vd->storage_class & (STCref | STCout)) { + e->mem = vd->llvmValue; + e->type = elem::VAR; + } + else { + if (vd->type->ty == Tstruct || vd->type->ty == Tdelegate || vd->type->ty == Tarray) { + e->mem = vd->llvmValue; + e->type = elem::VAR; + } + else { + e->val = vd->llvmValue; + e->type = elem::VAL; + } + } + } + else { + e->mem = vd->llvmValue; + //e->mem->setName(toChars()); + 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 + Logger::print("Sym: type=%s\n", sdecl->type->toChars()); + assert(sdecl->type->ty == Tstruct); + //assert(sdecl->llvmInitZ); + //e->val = sdecl->llvmInitZ; + TypeStruct* ts = (TypeStruct*)sdecl->type; + e->mem = ts->llvmInit; + assert(e->mem); + e->type = elem::VAR; + } + else + { + assert(0 && "Unimplemented VarExp type"); + } + + assert(e->mem || e->val); + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* IntegerExp::toElem(IRState* p) +{ + Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars()); + LOG_SCOPE; + elem* e = new elem; + 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); + e->val = llvm::ConstantExpr::getIntToPtr(i, t); + } + else if (llvm::isa<llvm::IntegerType>(t)) { + e->val = llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned()); + } + else { + assert(0); + } + e->type = elem::CONST; + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* RealExp::toElem(IRState* p) +{ + Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars()); + LOG_SCOPE; + elem* e = new elem; + e->val = llvm::ConstantFP::get(LLVM_DtoType(type),value); + e->type = elem::CONST; + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* NullExp::toElem(IRState* p) +{ + Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars()); + LOG_SCOPE; + elem* e = new elem; + const llvm::Type* t = LLVM_DtoType(type); + if (llvm::isa<llvm::StructType>(t)) + t = llvm::PointerType::get(t); + Logger::cout() << *t << '\n'; + e->val = llvm::Constant::getNullValue(t); + assert(e->val); + Logger::cout() << *e->val << '\n'; + e->type = elem::NUL; + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* StringExp::toElem(IRState* p) +{ + Logger::print("StringExp::toElem: %s\n", toChars()); + LOG_SCOPE; + + assert(type->next->ty == Tchar && "Only char is supported"); + assert(sz == 1); + + const llvm::Type* ct = LLVM_DtoType(type->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::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* arrptr = new llvm::GetElementPtrInst(gvar,zero,zero,"tmp",p->scopebb()); + + elem* e = new elem; + + if (type->ty == Tarray) { + llvm::Value* arr = p->toplval(); + LLVM_DtoSetArray(arr, llvm::ConstantInt::get(LLVM_DtoSize_t(),len,false), arrptr); + } + else if (type->ty == Tpointer) { + e->mem = arrptr; + } + else { + assert(0); + } + + e->inplace = true; + e->type = elem::VAL; + + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +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->lvals.push_back(l->mem); + elem* r = e2->toElem(p); + p->lvals.pop_back(); + + assert(l->mem); + //e->val = l->store(r->getValue()); + + TY e1ty = e1->type->ty; + TY e2ty = e2->type->ty; + + elem* e = new elem; + + // struct + if (e1ty == Tstruct) { + // struct + struct + if (e2ty == Tstruct) { + // struct literals do the assignment themselvs (in place) + if (!r->inplace) { + TypeStruct* ts = (TypeStruct*)e2->type; + assert(r->mem); + LLVM_DtoStructCopy(ts,l->mem,r->mem); + } + else { + e->inplace = true; + } + } + // struct + const int + else if (e2->type->isintegral()){ + IntegerExp* iexp = (IntegerExp*)e2; + assert(iexp->value == 0 && "Only integral struct initializer allowed is zero"); + TypeStruct* st = (TypeStruct*)e1->type; + LLVM_DtoStructZeroInit(st, l->mem); + } + // :x + else + assert(0 && "struct = unknown"); + } + else if (e1ty == Tsarray) { + assert(0 && "static array = not supported"); + } + else if (e1ty == Tarray) { + if (e2->type->isscalar() || e2->type->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); + } + else if (r->type == elem::SLICE) { + if (l->type == elem::SLICE) + LLVM_DtoArrayCopy(l,r); + else + LLVM_DtoSetArray(l->mem,r->arg,r->mem); + } + else { + // new expressions write directly to the array reference + // so do string literals + if (!r->inplace) { + assert(r->mem); + LLVM_DtoArrayAssign(l->mem, r->mem); + } + else { + e->inplace = true; + } + } + } + else + assert(0); + } + else if (e1ty == Tpointer) { + 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'; + new llvm::StoreInst(tmp, l->mem, p->scopebb()); + } + 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); + } + else + assert(0); + } + else if (r->inplace) { + // do nothing + e->inplace = true; + } + else + assert(0); + } + else + assert(0); + } + // !struct && !array && !pointer && !class + else { + Logger::cout() << *l->mem << '\n'; + new llvm::StoreInst(r->getValue(),l->mem,p->scopebb()); + } + + delete r; + delete l; + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* AddExp::toElem(IRState* p) +{ + Logger::print("AddExp::toElem: %s\n", toChars()); + LOG_SCOPE; + elem* e = new elem; + elem* l = e1->toElem(p); + elem* r = e2->toElem(p); + + if (e1->type != e2->type) { + if (e1->type->ty == Tpointer && e1->type->next->ty == Tstruct) { + assert(l->field); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + assert(r->type == elem::CONST); + llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->val); + + TypeStruct* ts = (TypeStruct*)e1->type->next; + llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, ts->sym->offsetToIndex(cofs->getZExtValue()), false); + + e->mem = new llvm::GetElementPtrInst(l->getValue(), zero, offset, "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); + + elem* e = new elem; + llvm::Value* val = 0; + if (e1->type->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); + }*/ + + 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); + + llvm::Value* tmp = 0; + if (e1->type->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); + }*/ + + 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); + }*/ + + 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); + + if (type->isunsigned()) + e->val = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->isintegral()) + e->val = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->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); + + llvm::Value* tmp; + if (type->isunsigned()) + tmp = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->isintegral()) + tmp = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->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); + }*/ + + 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); + + if (type->isunsigned()) + e->val = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->isintegral()) + e->val = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->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); + + llvm::Value* tmp; + if (type->isunsigned()) + tmp = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->isintegral()) + tmp = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); + else if (type->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); + }*/ + + 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; + + // regular functions + if (e1->type->ty == Tfunction) { + tf = (TypeFunction*)e1->type; + if (tf->llvmRetInPtr) { + retinptr = true; + } + dlink = tf->linkage; + } + + // delegates + else if (e1->type->ty == Tdelegate) { + Logger::println("delegateTy = %s\n", e1->type->toChars()); + assert(e1->type->next->ty == Tfunction); + tf = (TypeFunction*)e1->type->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(); + 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 = new llvm::GetElementPtrInst(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; + + // hidden struct return parameter + if (retinptr) { + if (!p->lvals.empty()) { + assert(llvm::isa<llvm::StructType>(p->toplval()->getType()->getContainedType(0))); + llargs[j] = p->toplval(); + TY Dty = tf->next->ty; + if (Dty == Tstruct || Dty == Tdelegate || Dty == Tarray) { + 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; + } + + // this parameter + 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 parameter + else if (delegateCall) { + Logger::println("Delegate Call"); + llvm::Value* contextptr = new llvm::GetElementPtrInst(fn->mem,zero,zero,"tmp",p->scopebb()); + llargs[j] = new llvm::LoadInst(contextptr,"tmp",p->scopebb()); + ++j; + ++argiter; + } + + // regular parameters + for (int i=0; i<arguments->dim; i++,j++) + { + Expression* argexp = (Expression*)arguments->data[i]; + elem* arg = argexp->toElem(p); + + Argument* fnarg = Argument::getNth(tf->parameters, i); + + TY argty = argexp->type->ty; + if (argty == Tstruct || argty == Tdelegate || argty == Tarray) { + if (!fnarg || !fnarg->llvmCopy) { + llargs[j] = arg->getValue(); + assert(llargs[j] != 0); + } + else { + llvm::Value* allocaInst = 0; + llvm::BasicBlock* entryblock = &p->topfunc()->front(); + const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(arg->mem->getType()); + allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", p->topallocapoint()); + if (argty == Tstruct) { + TypeStruct* ts = (TypeStruct*)argexp->type; + LLVM_DtoStructCopy(ts,allocaInst,arg->mem); + } + else if (argty == Tdelegate) { + LLVM_DtoDelegateCopy(allocaInst,arg->mem); + } + else if (argty == Tarray) { + LLVM_DtoArrayAssign(allocaInst,arg->mem); + } + else + assert(0); + + llargs[j] = allocaInst; + assert(llargs[j] != 0); + } + } + else if (!fnarg || fnarg->llvmCopy) { + llargs[j] = arg->getValue(); + assert(llargs[j] != 0); + } + else { + llargs[j] = arg->mem; + assert(llargs[j] != 0); + } + + delete arg; + } + + // 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()); + e->val = call; + + // set calling convention + if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall) + call->setCallingConv(LLVM_DtoCallingConv(dlink)); + + delete fn; + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +elem* CastExp::toElem(IRState* p) +{ + Logger::print("CastExp::toElem: %s\n", toChars()); + LOG_SCOPE; + elem* e = new elem; + elem* u = e1->toElem(p); + const llvm::Type* totype = LLVM_DtoType(to); + Type* from = e1->type; + int lsz = from->size(); + int rsz = to->size(); + + // this makes sure the strange lvalue casts don't screw things up + e->mem = u->mem; + + if (from->isintegral()) { + if (to->isintegral()) { + if (lsz < rsz) { + Logger::cout() << *totype << '\n'; + if (from->isunsigned() || from->ty == Tbool) { + e->val = new llvm::ZExtInst(u->getValue(), totype, "tmp", p->scopebb()); + } else { + e->val = new llvm::SExtInst(u->getValue(), totype, "tmp", p->scopebb()); + } + } + else if (lsz > rsz) { + e->val = new llvm::TruncInst(u->getValue(), totype, "tmp", p->scopebb()); + } + else { + e->val = new llvm::BitCastInst(u->getValue(), totype, "tmp", p->scopebb()); + } + } + else if (to->isfloating()) { + if (from->isunsigned()) { + e->val = new llvm::UIToFPInst(u->getValue(), totype, "tmp", p->scopebb()); + } + else { + e->val = new llvm::SIToFPInst(u->getValue(), totype, "tmp", p->scopebb()); + } + } + else { + assert(0); + } + //e->storeVal = u->storeVal ? u->storeVal : u->val; + e->type = elem::VAL; + } + else if (from->isfloating()) { + if (to->isfloating()) { + if ((from->ty == Tfloat80 || from->ty == Tfloat64) && (to->ty == Tfloat80 || to->ty == Tfloat64)) { + e->val = u->getValue(); + } + else if (lsz < rsz) { + e->val = new llvm::FPExtInst(u->getValue(), totype, "tmp", p->scopebb()); + } + else if (lsz > rsz) { + e->val = new llvm::FPTruncInst(u->getValue(), totype, "tmp", p->scopebb()); + } + else { + assert(0); + } + } + else if (to->isintegral()) { + if (to->isunsigned()) { + e->val = new llvm::FPToUIInst(u->getValue(), totype, "tmp", p->scopebb()); + } + else { + e->val = new llvm::FPToSIInst(u->getValue(), totype, "tmp", p->scopebb()); + } + } + else { + assert(0); + } + e->type = elem::VAL; + } + else if (from->ty == Tclass) { + //assert(to->ty == Tclass); + e->val = new llvm::BitCastInst(u->getValue(), totype, "tmp", p->scopebb()); + e->type = elem::VAL; + } + else if (from->ty == Tarray || from->ty == Tsarray) { + Logger::cout() << "from array or sarray" << '\n'; + if (to->ty == Tpointer) { + Logger::cout() << "to pointer" << '\n'; + assert(from->next == to->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 = new llvm::GetElementPtrInst(u->getValue(),zero,one,"tmp",p->scopebb()); + e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb()); + e->type = elem::VAL; + } + else if (to->ty == Tarray) { + Logger::cout() << "to array" << '\n'; + assert(from->next->size() == to->next->size()); + const llvm::Type* ptrty = LLVM_DtoType(to->next); + if (ptrty == llvm::Type::VoidTy) + ptrty = llvm::Type::Int8Ty; + ptrty = llvm::PointerType::get(ptrty); + + if (u->type == elem::SLICE) { + e->mem = new llvm::BitCastInst(u->mem, ptrty, "tmp", p->scopebb()); + e->arg = u->arg; + } + else { + llvm::Value* uval = u->getValue(); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); + e->arg = new llvm::GetElementPtrInst(uval,zero,zero,"tmp",p->scopebb()); + e->arg = new llvm::LoadInst(e->arg, "tmp", p->scopebb()); + + e->mem = new llvm::GetElementPtrInst(uval,zero,one,"tmp",p->scopebb()); + e->mem = new llvm::LoadInst(e->mem, "tmp", p->scopebb()); + e->mem = new llvm::BitCastInst(e->mem, ptrty, "tmp", p->scopebb()); + } + e->type = elem::SLICE; + } + else if (to->ty == Tsarray) { + Logger::cout() << "to sarray" << '\n'; + assert(0); + } + else { + assert(0); + } + } + else if (from->ty == Tpointer) { + if (to->ty == Tpointer || to->ty == Tclass) { + llvm::Value* src = u->getValue(); + //Logger::cout() << *src << '|' << *totype << '\n'; + e->val = new llvm::BitCastInst(src, totype, "tmp", p->scopebb()); + } + else if (to->isintegral()) { + e->val = new llvm::PtrToIntInst(u->getValue(), totype, "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->type->ty == Tstruct && !(type->ty == Tpointer && type->next == vd->type)) { + TypeStruct* vdt = (TypeStruct*)vd->type; + e = new elem; + llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* idx1 = llvm::ConstantInt::get(llvm::Type::Int32Ty, (uint64_t)vdt->sym->offsetToIndex(offset), false); + //const llvm::Type* _typ = llvm::GetElementPtrInst::getIndexedType(LLVM_DtoType(type), idx1); + llvm::Value* ptr = vd->llvmValue; + assert(ptr); + e->mem = new llvm::GetElementPtrInst(ptr,idx0,idx1,"tmp",p->scopebb()); + e->type = elem::VAL; + e->field = true; + } + else if (vd->type->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 = new llvm::GetElementPtrInst(vd->llvmValue,idx0,idx0,"tmp",p->scopebb()); + e->type = elem::VAL; + } + else if (offset == 0) { + vd->toObjFile(); + e = new elem; + e->mem = vd->llvmValue; + //e->vardecl = vd; + 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->aspointer = true; + 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); + + Logger::print("e1->type=%s\n", e1->type->toChars()); + + if (VarDeclaration* vd = var->isVarDeclaration()) { + size_t vdoffset = (size_t)-1; + llvm::Value* src = 0; + if (e1->type->ty == Tpointer) { + assert(e1->type->next->ty == Tstruct); + TypeStruct* ts = (TypeStruct*)e1->type->next; + vdoffset = ts->sym->offsetToIndex(vd->offset); + Logger::println("Struct member offset:%d index:%d", vd->offset, vdoffset); + src = l->val; + } + else if (e1->type->ty == Tclass) { + TypeClass* tc = (TypeClass*)e1->type; + Logger::println("Class member offset: %d", vd->offset); + vdoffset = tc->sym->offsetToIndex(vd->offset); + src = l->getValue(); + } + assert(vdoffset != (size_t)-1); + assert(src != 0); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, vdoffset, false); + llvm::Value* arrptr = new llvm::GetElementPtrInst(src,zero,offset,"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(e1->type->ty == Tclass); + + const llvm::Type* vtbltype = llvm::PointerType::get(llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty),0)); + + 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 = new llvm::GetElementPtrInst(e->arg, zero, zero, "tmp", p->scopebb()); + funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); + funcval = new llvm::BitCastInst(funcval, vtbltype, "tmp", p->scopebb()); + funcval = new llvm::GetElementPtrInst(funcval, zero, vtblidx, "tmp", p->scopebb()); + funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); + funcval = new llvm::BitCastInst(funcval, fdecl->llvmValue->getType(), "tmp", p->scopebb()); + } + 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()) { + assert(vd->llvmValue == 0); + + llvm::Function* fn = p->topfunc(); + assert(fn); + + TypeFunction* tf = p->topfunctype(); + assert(tf); + + llvm::Value* v = 0; + if (tf->llvmRetInPtr) + v = ++fn->arg_begin(); + else + v = fn->arg_begin(); + assert(v); + + e->val = v; + e->type = elem::VAL; + } + 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; + + // if there is no lval, this must be a static initializer for a global. correct? + if (p->lvals.empty()) + { + // TODO + assert(0); + } + // otherwise write directly in the lvalue + else + { + llvm::Value* sptr = p->toplval(); + 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 = new llvm::GetElementPtrInst(sptr,zero,offset,"tmp",p->scopebb()); + + Expression* vx = (Expression*)elements->data[i]; + if (vx != 0) { + elem* ve = vx->toElem(p); + //Logger::cout() << *ve->val << " | " << *arrptr << '\n'; + new llvm::StoreInst(ve->getValue(), arrptr, p->scopebb()); + delete ve; + } + else { + assert(0); + } + } + } + + e->inplace = true; + + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +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); + + 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 (e1->type->ty == Tpointer) { + arrptr = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb()); + } + else if (e1->type->ty == Tsarray) { + arrptr = new llvm::GetElementPtrInst(l->mem, zero, r->getValue(),"tmp",p->scopebb()); + } + else if (e1->type->ty == Tarray) { + arrptr = new llvm::GetElementPtrInst(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; + + elem* v = e1->toElem(p); + + 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 (e1->type->ty == Tpointer) { + e->mem = v->getValue(); + } + else if (e1->type->ty == Tarray) { + llvm::Value* tmp = new llvm::GetElementPtrInst(v->mem,zero,one,"tmp",p->scopebb()); + e->mem = new llvm::LoadInst(tmp,"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 + { + llvm::Value* tmp = new llvm::GetElementPtrInst(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()); + } + + 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; + } + // 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); + + assert(e1->type == e2->type); + + Type* t = e1->type; + + if (t->isintegral()) + { + llvm::ICmpInst::Predicate cmpop; + switch(op) + { + case TOKlt: + cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULT : llvm::ICmpInst::ICMP_SLT; + break; + case TOKle: + cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULE : llvm::ICmpInst::ICMP_SLE; + break; + case TOKgt: + cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGT : llvm::ICmpInst::ICMP_SGT; + break; + case TOKge: + cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGE : llvm::ICmpInst::ICMP_SGE; + 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 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); + + assert(e1->type == e2->type); + + Type* t = e1->type; + + 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 == Tarray) + { + // array comparison invokes the typeinfo runtime + assert(0); + } + 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; + + if (e1->type->isintegral()) + { + assert(e2->type->isintegral()); + llvm::Value* one = llvm::ConstantInt::get(val->getType(), 1, !e2->type->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 (e1->type->ty == Tpointer) + { + assert(e2->type->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 (e1->type->isfloating()) + { + assert(e2->type->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(!arguments); + //assert(!member); + assert(!allocator); + + elem* e = new elem; + + const llvm::Type* t = LLVM_DtoType(newtype); + + if (onstack) { + assert(newtype->ty == Tclass); + e->mem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint()); + } + else { + if (newtype->ty == Tclass) { + e->mem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb()); + } + else if (newtype->ty == Tarray) { + t = LLVM_DtoType(newtype->next); + assert(arguments); + if (arguments->dim == 1) { + elem* sz = ((Expression*)arguments->data[0])->toElem(p); + llvm::Value* dimval = sz->getValue(); + llvm::Value* usedimval = dimval; + if (dimval->getType() != llvm::Type::Int32Ty) + usedimval = new llvm::TruncInst(dimval, llvm::Type::Int32Ty,"tmp",p->scopebb()); + e->mem = new llvm::MallocInst(t,usedimval,"tmp",p->scopebb()); + + LLVM_DtoSetArray(p->toplval(), dimval, e->mem); + delete sz; + } + else { + assert(0); + } + } + else { + e->mem = new llvm::MallocInst(t,"tmp",p->scopebb()); + } + } + + if (newtype->ty == Tclass) { + // first apply the static initializer + assert(e->mem); + LLVM_DtoInitClass((TypeClass*)newtype, e->mem); + + // then call constructor + if (arguments) { + 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]; + Logger::println("arg=%s", ex->toChars()); + elem* exe = ex->toElem(p); + assert(exe->getValue()); + ctorargs.push_back(exe->getValue()); + delete exe; + } + assert(member); + assert(member->llvmValue); + new llvm::CallInst(member->llvmValue, ctorargs.begin(), ctorargs.end(), "", p->scopebb()); + } + } + else if (newtype->ty == Tstruct) { + TypeStruct* ts = (TypeStruct*)newtype; + if (ts->isZeroInit()) { + LLVM_DtoStructZeroInit(ts,e->mem); + } + else { + LLVM_DtoStructCopy(ts,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); + + if (e1->type->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 (e1->type->ty == Tclass) { + TypeClass* tc = (TypeClass*)e1->type; + 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 (e1->type->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 = new llvm::GetElementPtrInst(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); + + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* ptr = new llvm::GetElementPtrInst(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* e = new elem; + elem* u = e1->toElem(p); + elem* m = msg ? msg->toElem(p) : 0; + + std::vector<llvm::Value*> llargs; + llargs.resize(3); + llargs[0] = LLVM_DtoBoolean(u->getValue()); + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false); + llargs[2] = m ? m->val : llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)); + + delete m; + delete u; + + //Logger::cout() << *llargs[0] << '|' << *llargs[1] << '\n'; + + llvm::Function* fn = LLVM_D_GetRuntimeFunction(p->module, "_d_assert"); + assert(fn); + llvm::CallInst* call = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", p->scopebb()); + call->setCallingConv(llvm::CallingConv::C); + + return e; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +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 = 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* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getValue(), v->getValue(), "tmp", p->scopebb()); \ + 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; + + std::vector<llvm::Value*> llargs; + llargs.resize(3); + llargs[0] = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, false); + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false); + llargs[2] = llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)); + + //Logger::cout() << *llargs[0] << '|' << *llargs[1] << '\n'; + + llvm::Function* fn = LLVM_D_GetRuntimeFunction(p->module, "_d_assert"); + assert(fn); + llvm::CallInst* call = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", p->scopebb()); + call->setCallingConv(llvm::CallingConv::C); + + //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); + + llvm::Value* lval = p->toplval(); + + llvm::Value* context = new llvm::GetElementPtrInst(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 = new llvm::GetElementPtrInst(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(); + + 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; + + const llvm::Type* resty = LLVM_DtoType(type); + + // 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); + Logger::cout() << *u->val << '|' << *resval << '\n'; \ + new llvm::StoreInst(u->getValue(),resval,p->scopebb()); + 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()); + 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; + 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; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +#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); + +unsigned Type::totym() { return 0; } + +type * +Type::toCtype() { + return 0; +} + +type * Type::toCParamtype() +{ + return 0; +} +Symbol * Type::toSymbol() +{ + return 0; +} + +type * +TypeTypedef::toCtype() +{ + return 0; +} + +type * +TypeTypedef::toCParamtype() +{ + return 0; +} + +void +TypedefDeclaration::toDebug() +{ +} + + +type * +TypeEnum::toCtype() +{ + return 0; +} + +type * +TypeStruct::toCtype() +{ + return 0; +} + +void +StructDeclaration::toDebug() +{ +} + +Symbol * TypeClass::toSymbol() +{ + return 0; +} + +unsigned TypeFunction::totym() +{ + return 0; +} + +type * +TypeFunction::toCtype() +{ + return 0; +} + +type * +TypeSArray::toCtype() +{ + return 0; +} + +type *TypeSArray::toCParamtype() { return 0; } + +type * +TypeDArray::toCtype() +{ + return 0; +} + +type * +TypeAArray::toCtype() +{ + return 0; +} + +type * +TypePointer::toCtype() +{ + return 0; +} + +type * +TypeDelegate::toCtype() +{ + return 0; +} + +type * +TypeClass::toCtype() +{ + return 0; +} + +void +ClassDeclaration::toDebug() +{ +} + +/* --------------------------------------------------------------------------------------- */ + +void CompoundStatement::toIR(IRState* p) +{ + static int csi = 0; + Logger::println("CompoundStatement::toIR(%d):\n<<<\n%s>>>", csi++, toChars()); + LOG_SCOPE; + + /* + const char* labelname; + bool insterm = false; + + if (!p->scopes()) { + labelname = "bb"; + insterm = true; + } + else + labelname = "entry"; + + //if (!llvm::isa<llvm::TerminatorInst>(p->topfunc()->back().back())) + // insterm = true; + + llvm::BasicBlock* bb = new llvm::BasicBlock(labelname, p->topfunc()); + + if (insterm) { + new llvm::BranchInst(bb,p->topbb()); + } + + p->bbs.push(bb); + */ + + size_t n = statements->dim; + for (size_t i=0; i<n; i++) + { + Statement* s = (Statement*)statements->data[i]; + if (s) + s->toIR(p); + else + Logger::println("NULL statement found in CompoundStatement !! :S"); + } + + //p->bbs.pop(); +} + +void ReturnStatement::toIR(IRState* p) +{ + static int rsi = 0; + Logger::println("ReturnStatement::toIR(%d): %s", rsi++, toChars()); + LOG_SCOPE; + + if (exp) + { + TY expty = exp->type->ty; + if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) { + assert(expty == Tstruct || expty == Tdelegate || expty == Tarray); + + TypeFunction* f = p->topfunctype(); + assert(f->llvmRetInPtr && f->llvmRetArg); + + p->lvals.push_back(f->llvmRetArg); + elem* e = exp->toElem(p); + p->lvals.pop_back(); + + // structliterals do this themselves + // also they dont produce any value + if (expty == Tstruct) { + if (!e->inplace) { + TypeStruct* ts = (TypeStruct*)exp->type; + assert(e->mem); + LLVM_DtoStructCopy(ts,f->llvmRetArg,e->mem); + } + } + else if (expty == Tdelegate) { + // do nothing, handled by the DelegateExp + LLVM_DtoDelegateCopy(f->llvmRetArg,e->mem); + } + else if (expty == Tarray) { + if (e->type == elem::SLICE) { + LLVM_DtoSetArray(f->llvmRetArg,e->arg,e->mem); + } + // else the return value is a variable and should already have been assigned by now + } + else + assert(0); + + new llvm::ReturnInst(p->scopebb()); + delete e; + } + else { + elem* e = exp->toElem(p); + llvm::Value* v = e->getValue(); + Logger::cout() << *v << '\n'; + new llvm::ReturnInst(v, p->scopebb()); + delete e; + } + } + else + { + if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) + new llvm::ReturnInst(p->scopebb()); + else + new llvm::UnreachableInst(p->scopebb()); + } + + p->scope().returned = true; +} + +void ExpStatement::toIR(IRState* p) +{ + static int esi = 0; + Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars()); + LOG_SCOPE; + + if (exp != 0) { + elem* e = exp->toElem(p); + delete e; + } + /*elem* e = exp->toElem(p); + p->buf.printf("%s", e->toChars()); + delete e; + p->buf.writenl();*/ +} + +void IfStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("IfStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + elem* cond_e = condition->toElem(p); + llvm::Value* cond_val = cond_e->getValue(); + delete cond_e; + + llvm::BasicBlock* oldend = gIR->scopeend(); + + llvm::BasicBlock* ifbb = new llvm::BasicBlock("if", gIR->topfunc(), oldend); + llvm::BasicBlock* endbb = new llvm::BasicBlock("endif", gIR->topfunc(), oldend); + llvm::BasicBlock* elsebb = 0; + if (elsebody) { + elsebb = new llvm::BasicBlock("else", gIR->topfunc(), endbb); + } + else { + elsebb = endbb; + } + + if (cond_val->getType() != llvm::Type::Int1Ty) { + Logger::cout() << "if conditional: " << *cond_val << '\n'; + cond_val = LLVM_DtoBoolean(cond_val); + } + llvm::Value* ifgoback = new llvm::BranchInst(ifbb, elsebb, cond_val, gIR->scopebegin()); + + // replace current scope + gIR->scope() = IRScope(ifbb,elsebb); + + bool endifUsed = false; + + // do scoped statements + ifbody->toIR(p); + if (!gIR->scopereturned()) { + new llvm::BranchInst(endbb,gIR->scopebegin()); + endifUsed = true; + } + + if (elsebody) { + //assert(0); + gIR->scope() = IRScope(elsebb,endbb); + elsebody->toIR(p); + if (!gIR->scopereturned()) { + new llvm::BranchInst(endbb,gIR->scopebegin()); + endifUsed = true; + } + } + + // rewrite the scope + gIR->scope() = IRScope(endbb,oldend); +} + +void ScopeStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("ScopeStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + llvm::BasicBlock* oldend = gIR->scopeend(); + + IRScope irs; + irs.begin = new llvm::BasicBlock("scope", gIR->topfunc(), oldend); + irs.end = new llvm::BasicBlock("endscope", gIR->topfunc(), oldend); + + // pass the previous BB into this + new llvm::BranchInst(irs.begin, gIR->scopebegin()); + + gIR->scope() = irs; + + statement->toIR(p); + if (!gIR->scopereturned()) { + new llvm::BranchInst(irs.end, gIR->scopebegin()); + } + + // rewrite the scope + gIR->scope() = IRScope(irs.end,oldend); +} + +void WhileStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("WhileStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + // create while blocks + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* whilebb = new llvm::BasicBlock("whilecond", gIR->topfunc(), oldend); + llvm::BasicBlock* endbb = new llvm::BasicBlock("endwhile", gIR->topfunc(), oldend); + + // move into the while block + new llvm::BranchInst(whilebb, gIR->scopebegin()); + + // replace current scope + gIR->scope() = IRScope(whilebb,endbb); + + // create the condition + elem* cond_e = condition->toElem(p); + llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue()); + delete cond_e; + + // while body block + llvm::BasicBlock* whilebodybb = new llvm::BasicBlock("whilebody", gIR->topfunc(), endbb); + + // conditional branch + llvm::Value* ifbreak = new llvm::BranchInst(whilebodybb, endbb, cond_val, whilebb); + + // rewrite scope + gIR->scope() = IRScope(whilebodybb,endbb); + + // do while body code + body->toIR(p); + + // loop + new llvm::BranchInst(whilebb, gIR->scopebegin()); + + // rewrite the scope + gIR->scope() = IRScope(endbb,oldend); +} + +void DoStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("DoStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + // create while blocks + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* dowhilebb = new llvm::BasicBlock("dowhile", gIR->topfunc(), oldend); + llvm::BasicBlock* endbb = new llvm::BasicBlock("enddowhile", gIR->topfunc(), oldend); + + // move into the while block + new llvm::BranchInst(dowhilebb, gIR->scopebegin()); + + // replace current scope + gIR->scope() = IRScope(dowhilebb,endbb); + + // do do-while body code + body->toIR(p); + + // create the condition + elem* cond_e = condition->toElem(p); + llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue()); + delete cond_e; + + // conditional branch + llvm::Value* ifbreak = new llvm::BranchInst(dowhilebb, endbb, cond_val, gIR->scopebegin()); + + // rewrite the scope + gIR->scope() = IRScope(endbb,oldend); +} + +void ForStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("ForStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + // create for blocks + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* forbb = new llvm::BasicBlock("forcond", gIR->topfunc(), oldend); + llvm::BasicBlock* forbodybb = new llvm::BasicBlock("forbody", gIR->topfunc(), oldend); + llvm::BasicBlock* forincbb = new llvm::BasicBlock("forinc", gIR->topfunc(), oldend); + llvm::BasicBlock* endbb = new llvm::BasicBlock("endfor", gIR->topfunc(), oldend); + + // init + if (init != 0) + init->toIR(p); + + // move into the for condition block, ie. start the loop + new llvm::BranchInst(forbb, gIR->scopebegin()); + + IRScope loop; + loop.begin = forincbb; + loop.end = endbb; + p->loopbbs.push_back(loop); + + // replace current scope + gIR->scope() = IRScope(forbb,forbodybb); + + // create the condition + elem* cond_e = condition->toElem(p); + llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue()); + delete cond_e; + + // conditional branch + llvm::Value* ifbreak = new llvm::BranchInst(forbodybb, endbb, cond_val, forbb); + + // rewrite scope + gIR->scope() = IRScope(forbodybb,forincbb); + + // do for body code + body->toIR(p); + + // move into the for increment block + new llvm::BranchInst(forincbb, gIR->scopebegin()); + gIR->scope() = IRScope(forincbb, endbb); + + // increment + if (increment) { + elem* inc = increment->toElem(p); + delete inc; + } + + // loop + new llvm::BranchInst(forbb, gIR->scopebegin()); + + p->loopbbs.pop_back(); + + // rewrite the scope + gIR->scope() = IRScope(endbb,oldend); +} + +void BreakStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("BreakStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + if (ident != 0) { + Logger::println("ident = %s", ident->toChars()); + assert(0); + } + else { + new llvm::BranchInst(gIR->loopbbs.back().end, gIR->scopebegin()); + } +} + +void ContinueStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("ContinueStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + if (ident != 0) { + Logger::println("ident = %s", ident->toChars()); + assert(0); + } + else { + new llvm::BranchInst(gIR->loopbbs.back().begin, gIR->scopebegin()); + } +} + +void OnScopeStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("OnScopeStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + assert(statement); + //statement->toIR(p); // this seems to be redundant +} + +void TryFinallyStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("TryFinallyStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + llvm::BasicBlock* oldend = gIR->scopeend(); + + llvm::BasicBlock* trybb = new llvm::BasicBlock("try", gIR->topfunc(), oldend); + llvm::BasicBlock* finallybb = new llvm::BasicBlock("finally", gIR->topfunc(), oldend); + llvm::BasicBlock* endbb = new llvm::BasicBlock("endtryfinally", gIR->topfunc(), oldend); + + // pass the previous BB into this + new llvm::BranchInst(trybb, gIR->scopebegin()); + + gIR->scope() = IRScope(trybb,finallybb); + + assert(body); + body->toIR(p); + new llvm::BranchInst(finallybb, gIR->scopebegin()); + + // rewrite the scope + gIR->scope() = IRScope(finallybb,endbb); + + assert(finalbody); + finalbody->toIR(p); + new llvm::BranchInst(endbb, gIR->scopebegin()); + + // rewrite the scope + gIR->scope() = IRScope(endbb,oldend); +} + +void TryCatchStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("TryCatchStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + assert(0 && "try-catch is not properly"); + + assert(body); + body->toIR(p); + + assert(catches); + for(size_t i=0; i<catches->dim; ++i) + { + Catch* c = (Catch*)catches->data[i]; + c->handler->toIR(p); + } +} + +void ThrowStatement::toIR(IRState* p) +{ + static int wsi = 0; + Logger::println("ThrowStatement::toIR(%d): %s", wsi++, toChars()); + LOG_SCOPE; + + assert(0 && "throw is not implemented"); + + assert(exp); + elem* e = exp->toElem(p); + delete e; +} + +#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();} +//STUBST(BreakStatement); +//STUBST(ForStatement); +STUBST(WithStatement); +STUBST(SynchronizedStatement); +//STUBST(ReturnStatement); +//STUBST(ContinueStatement); +STUBST(DefaultStatement); +STUBST(CaseStatement); +STUBST(SwitchStatement); +STUBST(SwitchErrorStatement); +STUBST(Statement); +//STUBST(IfStatement); +STUBST(ForeachStatement); +//STUBST(DoStatement); +//STUBST(WhileStatement); +//STUBST(ExpStatement); +//STUBST(CompoundStatement); +//STUBST(ScopeStatement); +STUBST(AsmStatement); +//STUBST(TryCatchStatement); +//STUBST(TryFinallyStatement); +STUBST(VolatileStatement); +STUBST(LabelStatement); +//STUBST(ThrowStatement); +STUBST(GotoCaseStatement); +STUBST(GotoDefaultStatement); +STUBST(GotoStatement); +STUBST(UnrolledLoopStatement); +//STUBST(OnScopeStatement); + + +void +EnumDeclaration::toDebug() +{ + +} + +int +Dsymbol::cvMember(unsigned char*) +{ + return 0; +} +int +EnumDeclaration::cvMember(unsigned char*) +{ + return 0; +} +int +FuncDeclaration::cvMember(unsigned char*) +{ + return 0; +} +int +VarDeclaration::cvMember(unsigned char*) +{ + return 0; +} +int +TypedefDeclaration::cvMember(unsigned char*) +{ + return 0; +} + +void obj_includelib(char*){} + +AsmStatement::AsmStatement(Loc loc, Token *tokens) : + Statement(loc) +{ +} +Statement *AsmStatement::syntaxCopy() { + 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() +{ + return FALSE; +} + +void +backend_init() +{ + //LLVM_D_InitRuntime(); + // lazily loaded +} + +void +backend_term() +{ + LLVM_D_FreeRuntime(); +}