Mercurial > projects > ldc
diff gen/tollvm.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/tollvm.c Sat Sep 01 21:43:27 2007 +0200 @@ -0,0 +1,1089 @@ +#include <iostream> + +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalValue.h" +#include "llvm/Instructions.h" +#include "llvm/CallingConv.h" + +#include "mtype.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "declaration.h" +#include "init.h" + +#include "tollvm.h" +#include "irstate.h" +#include "logger.h" +#include "runtime.h" +#include "elem.h" + +const llvm::Type* LLVM_DtoType(Type* t) +{ + assert(t); + switch (t->ty) + { + // integers + case Tint8: + case Tuns8: + case Tchar: + return (const llvm::Type*)llvm::Type::Int8Ty; + case Tint16: + case Tuns16: + case Twchar: + return (const llvm::Type*)llvm::Type::Int16Ty; + case Tint32: + case Tuns32: + case Tdchar: + return (const llvm::Type*)llvm::Type::Int32Ty; + case Tint64: + case Tuns64: + return (const llvm::Type*)llvm::Type::Int64Ty; + + case Tbool: + return (const llvm::Type*)llvm::ConstantInt::getTrue()->getType(); + + // floats + case Tfloat32: + return llvm::Type::FloatTy; + case Tfloat64: + case Tfloat80: + return llvm::Type::DoubleTy; + + // pointers + case Tpointer: { + assert(t->next); + if (t->next->ty == Tvoid) + return (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty); + else + return (const llvm::Type*)llvm::PointerType::get(LLVM_DtoType(t->next)); + } + + // arrays + case Tarray: + return LLVM_DtoArrayType(t); + case Tsarray: + return LLVM_DtoStaticArrayType(t); + + // void + case Tvoid: + return llvm::Type::VoidTy; + + // aggregates + case Tstruct: { + if (t->llvmType == 0) + { + // recursive or cyclic declaration + if (!gIR->structs.empty()) + { + IRStruct* found = 0; + for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i) + { + if (t == i->type) + { + return i->recty.get(); + } + } + } + + // forward declaration + TypeStruct* ts = (TypeStruct*)t; + assert(ts->sym); + ts->sym->toObjFile(); + } + return t->llvmType; + } + + case Tclass: { + if (t->llvmType == 0) + { + TypeClass* tc = (TypeClass*)t; + assert(tc->sym); + if (!tc->sym->llvmInProgress) { + tc->sym->toObjFile(); + } + else { + //assert(0 && "circular class referencing"); + return llvm::OpaqueType::get(); + } + } + return llvm::PointerType::get(t->llvmType); + } + + // functions + case Tfunction: + { + if (t->llvmType == 0) { + return LLVM_DtoFunctionType(t); + } + else { + return t->llvmType; + } + } + + // delegates + case Tdelegate: + { + if (t->llvmType == 0) { + return LLVM_DtoDelegateType(t); + } + else { + return t->llvmType; + } + } + + // typedefs + case Ttypedef: + { + Type* bt = t->toBasetype(); + assert(bt); + return LLVM_DtoType(bt); + } + + default: + printf("trying to convert unknown type with value %d\n", t->ty); + assert(0); + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam) +{ + TypeFunction* f = (TypeFunction*)t; + + // parameter types + const llvm::Type* rettype; + std::vector<const llvm::Type*> paramvec; + + TY retty = f->next->ty; + + if (retty == Tstruct || retty == Tdelegate || retty == Tarray) { + rettype = llvm::PointerType::get(LLVM_DtoType(f->next)); + paramvec.push_back(rettype); + rettype = llvm::Type::VoidTy; + } + else { + Type* rt = f->next; + if (rt) + rettype = LLVM_DtoType(rt); + else + assert(0); + } + + if (thisparam) { + paramvec.push_back(thisparam); + } + + size_t n = Argument::dim(f->parameters); + for (int i=0; i < n; ++i) { + Argument* arg = Argument::getNth(f->parameters, i); + // ensure scalar + Type* argT = arg->type; + assert(argT); + paramvec.push_back(LLVM_DtoType(argT)); + } + + Logger::cout() << "Return type: " << *rettype << '\n'; + + llvm::FunctionType* functype = llvm::FunctionType::get(rettype, paramvec, f->varargs); + return functype; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl) +{ + TypeFunction* f = (TypeFunction*)fdecl->type; + assert(f != 0); + + // has already been pulled in by a reference to ( + if (f->llvmType != 0) { + return llvm::cast<llvm::FunctionType>(f->llvmType); + } + + // return value type + const llvm::Type* rettype; + const llvm::Type* actualRettype; + Type* rt = f->next; + bool retinptr = false; + bool usesthis = false; + + if (fdecl->isMain()) { + rettype = llvm::Type::Int32Ty; + actualRettype = rettype; + } + else if (rt) { + if (rt->ty == Tstruct || rt->ty == Tdelegate || rt->ty == Tarray) { + rettype = llvm::PointerType::get(LLVM_DtoType(rt)); + actualRettype = llvm::Type::VoidTy; + f->llvmRetInPtr = retinptr = true; + } + else { + rettype = LLVM_DtoType(rt); + actualRettype = rettype; + } + } + else { + assert(0); + } + + // parameter types + std::vector<const llvm::Type*> paramvec; + + if (retinptr) { + Logger::print("returning through pointer parameter\n"); + paramvec.push_back(rettype); + } + + if (fdecl->needThis() && fdecl->vthis) { + Logger::print("this is: %s\n", fdecl->vthis->type->toChars()); + paramvec.push_back(LLVM_DtoType(fdecl->vthis->type)); + usesthis = true; + } + + size_t n = Argument::dim(f->parameters); + for (int i=0; i < n; ++i) { + Argument* arg = Argument::getNth(f->parameters, i); + // ensure scalar + Type* argT = arg->type; + assert(argT); + + if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) { + //assert(arg->vardecl); + //arg->vardecl->refparam = true; + } + else + arg->llvmCopy = true; + + const llvm::Type* at = LLVM_DtoType(argT); + if (llvm::isa<llvm::StructType>(at)) { + Logger::println("struct param"); + paramvec.push_back(llvm::PointerType::get(at)); + } + else if (llvm::isa<llvm::ArrayType>(at)) { + Logger::println("sarray param"); + assert(argT->ty == Tsarray); + //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0))); + paramvec.push_back(llvm::PointerType::get(at)); + } + else { + if (!arg->llvmCopy) { + Logger::println("ref param"); + at = llvm::PointerType::get(at); + } + else { + Logger::println("in param"); + } + paramvec.push_back(at); + } + } + + // construct function type + bool isvararg = f->varargs; + llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); + + f->llvmType = functype; + return functype; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::StructType* LLVM_DtoDelegateType(Type* t) +{ + const llvm::Type* i8ptr = llvm::PointerType::get(llvm::Type::Int8Ty); + const llvm::Type* func = LLVM_DtoFunctionType(t->next, i8ptr); + const llvm::Type* funcptr = llvm::PointerType::get(func); + + std::vector<const llvm::Type*> types; + types.push_back(i8ptr); + types.push_back(funcptr); + return llvm::StructType::get(types); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Type* LLVM_DtoStructType(Type* t) +{ + assert(0); + std::vector<const llvm::Type*> types; + return llvm::StructType::get(types); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::StructType* LLVM_DtoArrayType(Type* t) +{ + assert(t->next); + const llvm::Type* at = LLVM_DtoType(t->next); + const llvm::Type* arrty; + + /*if (t->ty == Tsarray) { + TypeSArray* tsa = (TypeSArray*)t; + assert(tsa->dim->type->isintegral()); + arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger()); + } + else { + arrty = llvm::ArrayType::get(at,0); + }*/ + if (at == llvm::Type::VoidTy) { + at = llvm::Type::Int8Ty; + } + arrty = llvm::PointerType::get(at); + + std::vector<const llvm::Type*> members; + if (global.params.is64bit) + members.push_back(llvm::Type::Int64Ty); + else + members.push_back(llvm::Type::Int32Ty); + + members.push_back(arrty); + + return llvm::StructType::get(members); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t) +{ + if (t->llvmType) + return llvm::cast<llvm::ArrayType>(t->llvmType); + + assert(t->ty == Tsarray); + assert(t->next); + + const llvm::Type* at = LLVM_DtoType(t->next); + + TypeSArray* tsa = (TypeSArray*)t; + assert(tsa->dim->type->isintegral()); + llvm::ArrayType* arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger()); + + tsa->llvmType = arrty; + return arrty; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false) +{ + assert(bits == 32 || bits == 64); + const llvm::Type* int8ty = (const llvm::Type*)llvm::Type::Int8Ty; + const llvm::Type* int32ty = (const llvm::Type*)llvm::Type::Int32Ty; + const llvm::Type* int64ty = (const llvm::Type*)llvm::Type::Int64Ty; + const llvm::Type* int8ptrty = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty); + const llvm::Type* voidty = (const llvm::Type*)llvm::Type::VoidTy; + + assert(gIR); + assert(gIR->module); + + // parameter types + std::vector<const llvm::Type*> pvec; + pvec.push_back(int8ptrty); + pvec.push_back(set?int8ty:int8ptrty); + pvec.push_back(bits==32?int32ty:int64ty); + pvec.push_back(int32ty); + llvm::FunctionType* functype = llvm::FunctionType::get(voidty, pvec, false); + return new llvm::Function(functype, llvm::GlobalValue::ExternalLinkage, name, gIR->module); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// llvm.memset.i32 +static llvm::Function* LLVM_DeclareMemSet32() +{ + static llvm::Function* _func = 0; + if (_func == 0) { + _func = LLVM_DeclareMemIntrinsic("llvm.memset.i32", 32, true); + } + return _func; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +static llvm::Function* LLVM_DeclareMemSet64() +{ + static llvm::Function* _func = 0; + if (_func == 0) { + _func = LLVM_DeclareMemIntrinsic("llvm.memset.i64", 64, true); + } + return _func; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// llvm.memcpy.i32 +static llvm::Function* LLVM_DeclareMemCpy32() +{ + static llvm::Function* _func = 0; + if (_func == 0) { + _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i32", 32); + } + return _func; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// llvm.memcpy.i64 +static llvm::Function* LLVM_DeclareMemCpy64() +{ + static llvm::Function* _func = 0; + if (_func == 0) { + _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i64", 64); + } + return _func; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoStructZeroInit(TypeStruct* t, llvm::Value* v) +{ + assert(gIR); + uint64_t n = gTargetData->getTypeSize(t->llvmType); + //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); + llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemSet32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = sarr; + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false); + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoStructCopy(TypeStruct* t, llvm::Value* dst, llvm::Value* src) +{ + assert(dst->getType() == src->getType()); + assert(gIR); + + uint64_t n = gTargetData->getTypeSize(t->llvmType); + //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n)); + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Constant* LLVM_DtoStructInitializer(StructInitializer* si) +{ + llvm::StructType* structtype = llvm::cast<llvm::StructType>(si->ad->llvmType); + size_t n = structtype->getNumElements(); + + assert(si->value.dim == si->vars.dim); + + std::vector<llvm::Constant*> inits; + inits.resize(n, NULL); + for (int i = 0; i < si->value.dim; ++i) + { + Initializer* ini = (Initializer*)si->value.data[i]; + assert(ini); + + VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; + assert(vd); + Logger::println("vars[%d] = %s", i, vd->toChars()); + unsigned idx = si->ad->offsetToIndex(vd->offset); + + llvm::Constant* v = 0; + + if (ExpInitializer* ex = ini->isExpInitializer()) + { + elem* e = ex->exp->toElem(gIR); + v = llvm::cast<llvm::Constant>(e->val); + delete e; + } + else if (StructInitializer* si = ini->isStructInitializer()) + { + v = LLVM_DtoStructInitializer(si); + } + else if (ArrayInitializer* ai = ini->isArrayInitializer()) + { + v = LLVM_DtoArrayInitializer(ai); + } + else if (ini->isVoidInitializer()) + { + v = llvm::UndefValue::get(structtype->getElementType(idx)); + } + else + assert(v); + + inits[idx] = v; + } + + // fill out nulls + assert(si->ad->llvmInitZ); + if (si->ad->llvmInitZ->isNullValue()) + { + for (int i = 0; i < n; ++i) + { + if (inits[i] == 0) + { + inits[i] = llvm::Constant::getNullValue(structtype->getElementType(i)); + } + } + } + else + { + for (int i = 0; i < n; ++i) + { + if (inits[i] == 0) + { + inits[i] = si->ad->llvmInitZ->getOperand(i); + } + } + } + + return llvm::ConstantStruct::get(structtype, inits); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoNullArray(llvm::Value* v) +{ + assert(gIR); + d_uns64 n = (global.params.is64bit) ? 16 : 8; + + llvm::Type* i8p_ty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* arr = new llvm::BitCastInst(v,i8p_ty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemSet32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = arr; + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false); + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + //Logger::cout() << *fn << '|' << *fn->getType() << '\n'; + //Logger::cout() << "to null array call: " << *llargs[0] << '|' << *llargs[1] << '|' << *llargs[2] << '|' << *llargs[3] << '\n'; + + llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoNullDelegate(llvm::Value* v) +{ + assert(gIR); + d_uns64 n = (global.params.is64bit) ? 16 : 8; + + llvm::Type* i8p_ty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* arr = new llvm::BitCastInst(v,i8p_ty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemSet32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = arr; + llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false); + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoDelegateCopy(llvm::Value* dst, llvm::Value* src) +{ + assert(dst->getType() == src->getType()); + assert(gIR); + + d_uns64 n = (global.params.is64bit) ? 16 : 8; + + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoArrayAssign(llvm::Value* dst, llvm::Value* src) +{ + assert(gIR); + if (dst->getType() == src->getType()) + { + d_uns64 n = (global.params.is64bit) ? 16 : 8; + + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + } + else + { + if (!llvm::isa<llvm::ArrayType>(src->getType()->getContainedType(0))) + { + Logger::cout() << "invalid: " << *src << '\n'; + assert(0); + } + const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(src->getType()->getContainedType(0)); + llvm::Type* dstty = llvm::PointerType::get(arrty->getElementType()); + + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); + + llvm::Value* dstlen = new llvm::GetElementPtrInst(dst,zero,zero,"tmp",gIR->scopebb()); + llvm::Value* srclen = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false); + new llvm::StoreInst(srclen, dstlen, gIR->scopebb()); + + llvm::Value* dstptr = new llvm::GetElementPtrInst(dst,zero,one,"tmp",gIR->scopebb()); + llvm::Value* srcptr = new llvm::BitCastInst(src,dstty,"tmp",gIR->scopebb()); + new llvm::StoreInst(srcptr, dstptr, gIR->scopebb()); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void LLVM_DtoArrayInit(llvm::Value* l, llvm::Value* r) +{ + const llvm::PointerType* ptrty = llvm::cast<llvm::PointerType>(l->getType()); + if (llvm::isa<llvm::ArrayType>(ptrty->getContainedType(0))) + { + const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(ptrty->getContainedType(0)); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + std::vector<llvm::Value*> args; + args.resize(3); + args[0] = new llvm::GetElementPtrInst(l,zero,zero,"tmp",gIR->scopebb()); + args[1] = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false); + args[2] = r; + + const char* funcname = NULL; + + if (llvm::isa<llvm::PointerType>(arrty->getElementType())) { + funcname = "_d_array_init_pointer"; + + const llvm::Type* dstty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); + if (args[0]->getType() != dstty) + args[0] = new llvm::BitCastInst(args[0],dstty,"tmp",gIR->scopebb()); + + const llvm::Type* valty = llvm::PointerType::get(llvm::Type::Int8Ty); + if (args[2]->getType() != valty) + args[2] = new llvm::BitCastInst(args[2],valty,"tmp",gIR->scopebb()); + } + else if (r->getType() == llvm::Type::Int1Ty) { + funcname = "_d_array_init_i1"; + } + else if (r->getType() == llvm::Type::Int8Ty) { + funcname = "_d_array_init_i8"; + } + else if (r->getType() == llvm::Type::Int16Ty) { + funcname = "_d_array_init_i16"; + } + else if (r->getType() == llvm::Type::Int32Ty) { + funcname = "_d_array_init_i32"; + } + else if (r->getType() == llvm::Type::Int64Ty) { + funcname = "_d_array_init_i64"; + } + else if (r->getType() == llvm::Type::FloatTy) { + funcname = "_d_array_init_float"; + } + else if (r->getType() == llvm::Type::DoubleTy) { + funcname = "_d_array_init_double"; + } + else { + assert(0); + } + + Logger::cout() << *args[0] << '|' << *args[2] << '\n'; + + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, funcname); + assert(fn); + llvm::CallInst* call = new llvm::CallInst(fn, args.begin(), args.end(), "", gIR->scopebb()); + call->setCallingConv(llvm::CallingConv::C); + + Logger::println("array init call ok"); + } + else if (llvm::isa<llvm::StructType>(ptrty->getContainedType(0))) + { + assert(0 && "Only static arrays support initialisers atm"); + } + else + assert(0); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void LLVM_DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr) +{ + const llvm::StructType* st = llvm::cast<llvm::StructType>(arr->getType()->getContainedType(0)); + //const llvm::PointerType* pt = llvm::cast<llvm::PointerType>(r->getType()); + + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); + + llvm::Value* arrdim = new llvm::GetElementPtrInst(arr,zero,zero,"tmp",gIR->scopebb()); + new llvm::StoreInst(dim, arrdim, gIR->scopebb()); + + llvm::Value* arrptr = new llvm::GetElementPtrInst(arr,zero,one,"tmp",gIR->scopebb()); + new llvm::StoreInst(ptr, arrptr, gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Constant* LLVM_DtoArrayInitializer(ArrayInitializer* arrinit) +{ + Logger::println("arr init begin"); + assert(arrinit->type->ty == Tsarray); + TypeSArray* t = (TypeSArray*)arrinit->type; + integer_t tdim = t->dim->toInteger(); + + std::vector<llvm::Constant*> inits(tdim, 0); + + const llvm::Type* elemty = LLVM_DtoType(arrinit->type->next); + + assert(arrinit->index.dim == arrinit->value.dim); + for (int i=0,j=0; i < tdim; ++i) + { + Initializer* init = 0; + Expression* idx = (Expression*)arrinit->index.data[j]; + + if (idx) + { + integer_t k = idx->toInteger(); + if (i == k) + { + init = (Initializer*)arrinit->value.data[j]; + assert(init); + ++j; + } + } + else + { + init = (Initializer*)arrinit->value.data[j]; + ++j; + } + + llvm::Constant* v = 0; + + if (!init) + { + elem* e = t->next->defaultInit()->toElem(gIR); + v = llvm::cast<llvm::Constant>(e->val); + delete e; + } + else if (ExpInitializer* ex = init->isExpInitializer()) + { + elem* e = ex->exp->toElem(gIR); + v = llvm::cast<llvm::Constant>(e->val); + delete e; + } + else if (StructInitializer* si = init->isStructInitializer()) + { + v = LLVM_DtoStructInitializer(si); + } + else if (ArrayInitializer* ai = init->isArrayInitializer()) + { + v = LLVM_DtoArrayInitializer(ai); + } + else if (init->isVoidInitializer()) + { + v = llvm::UndefValue::get(elemty); + } + else + assert(v); + + inits[i] = v; + } + + llvm::ArrayType* arrty = LLVM_DtoStaticArrayType(t); + return llvm::ConstantArray::get(arrty, inits); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLVM_DtoArrayCopy(elem* dst, elem* src) +{ + assert(0); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::GlobalValue::LinkageTypes LLVM_DtoLinkage(PROT prot, uint stc) +{ + switch(prot) + { + case PROTprivate: + return llvm::GlobalValue::InternalLinkage; + + case PROTpublic: + case PROTpackage: + case PROTprotected: + case PROTexport: + return llvm::GlobalValue::ExternalLinkage; + + case PROTundefined: + case PROTnone: + assert(0 && "Unsupported linkage type"); + } + return llvm::GlobalValue::ExternalLinkage; + +/* ExternalLinkage = 0, LinkOnceLinkage, WeakLinkage, AppendingLinkage, + InternalLinkage, DLLImportLinkage, DLLExportLinkage, ExternalWeakLinkage, + GhostLinkage */ +} + +////////////////////////////////////////////////////////////////////////////////////////// + +unsigned LLVM_DtoCallingConv(LINK l) +{ + if (l == LINKc) + return llvm::CallingConv::C; + else if (l == LINKd || l == LINKdefault) + return llvm::CallingConv::Fast; + else if (l == LINKwindows) + return llvm::CallingConv::X86_StdCall; + else + assert(0 && "Unsupported calling convention"); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoPointedType(llvm::Value* ptr, llvm::Value* val) +{ + const llvm::Type* ptrTy = ptr->getType()->getContainedType(0); + const llvm::Type* valTy = val->getType(); + // ptr points to val's type + if (ptrTy == valTy) + { + return val; + } + // ptr is integer pointer + else if (ptrTy->isInteger()) + { + // val is integer + assert(valTy->isInteger()); + const llvm::IntegerType* pt = llvm::cast<const llvm::IntegerType>(ptrTy); + const llvm::IntegerType* vt = llvm::cast<const llvm::IntegerType>(valTy); + if (pt->getBitWidth() < vt->getBitWidth()) { + return new llvm::TruncInst(val, pt, "tmp", gIR->scopebb()); + } + else + assert(0); + } + // something else unsupported + else + { + Logger::cout() << *ptrTy << '|' << *valTy << '\n'; + assert(0); + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoBoolean(llvm::Value* val) +{ + const llvm::Type* t = val->getType(); + if (t->isInteger()) + { + if (t == llvm::Type::Int1Ty) + return val; + else { + llvm::Value* zero = llvm::ConstantInt::get(t, 0, false); + return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, val, zero, "tmp", gIR->scopebb()); + } + } + else if (llvm::isa<llvm::PointerType>(t)) { + const llvm::Type* st = LLVM_DtoSize_t(); + llvm::Value* ptrasint = new llvm::PtrToIntInst(val,st,"tmp",gIR->scopebb()); + llvm::Value* zero = llvm::ConstantInt::get(st, 0, false); + return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, ptrasint, zero, "tmp", gIR->scopebb()); + } + else + { + Logger::cout() << *t << '\n'; + } + assert(0); + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* LLVM_DtoSize_t() +{ + if (global.params.is64bit) + return llvm::Type::Int64Ty; + else + return llvm::Type::Int32Ty; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void LLVM_DtoMain() +{ + // emit main function llvm style + // int main(int argc, char**argv, char**env); + + assert(gIR != 0); + IRState& ir = *gIR; + + assert(ir.emitMain && ir.mainFunc); + + // parameter types + std::vector<const llvm::Type*> pvec; + pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty); + const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty); + pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType)); + pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType)); + const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty; + + llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false); + llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module); + + llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func); + + // call static ctors + llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors"); + new llvm::CallInst(fn,"",bb); + + // call user main function + llvm::CallInst* call = new llvm::CallInst(ir.mainFunc,"ret",bb); + call->setCallingConv(ir.mainFunc->getCallingConv()); + + // call static dtors + fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors"); + new llvm::CallInst(fn,"",bb); + + // return + new llvm::ReturnInst(call,bb); + + /* + // return value type + const llvm::Type* rettype; + Type* rt = f->next; + if (rt) { + rettype = LLVM_DtoType(rt); + } + else { + assert(0); + } + + llvm::FunctionType* functype = llvm::FunctionType::get(rettype, paramvec, false); + */ +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void LLVM_DtoCallClassDtors(TypeClass* tc, llvm::Value* instance) +{ + Array* arr = &tc->sym->dtors; + for (size_t i=0; i<arr->dim; i++) + { + FuncDeclaration* fd = (FuncDeclaration*)arr->data[i]; + assert(fd->llvmValue); + new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb()); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void LLVM_DtoInitClass(TypeClass* tc, llvm::Value* dst) +{ + assert(tc->llvmInit); + assert(dst->getType() == tc->llvmInit->getType()); + assert(gIR); + + assert(tc->llvmType); + uint64_t n = gTargetData->getTypeSize(tc->llvmType); + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb()); + + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Constant* LLVM_DtoInitializer(Type* type, Initializer* init) +{ + llvm::Constant* _init = 0; + if (!init) + { + elem* e = type->defaultInit()->toElem(gIR); + if (!e->inplace && !e->isNull()) { + _init = llvm::cast<llvm::Constant>(e->getValue()); + } + delete e; + } + else if (ExpInitializer* ex = init->isExpInitializer()) + { + elem* e = ex->exp->toElem(gIR); + if (!e->inplace && !e->isNull()) { + _init = llvm::cast<llvm::Constant>(e->getValue()); + } + delete e; + } + else if (StructInitializer* si = init->isStructInitializer()) + { + _init = LLVM_DtoStructInitializer(si); + } + else if (ArrayInitializer* ai = init->isArrayInitializer()) + { + _init = LLVM_DtoArrayInitializer(ai); + } + else if (init->isVoidInitializer()) + { + const llvm::Type* ty = LLVM_DtoType(type); + _init = llvm::Constant::getNullValue(ty); + } + else { + Logger::println("unsupported initializer: %s", init->toChars()); + } + return _init; +}