Mercurial > projects > ldc
diff gen/toir.cpp @ 414:ac1fcc138e42
Fixed issue with internal real representation, incorrect for non x86-32 architectures.
Cleaned up CallExp::toElem, moved implementation to tocall.cpp providing a single procedure to call arbitrary D functions fairly easily.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 28 Jul 2008 02:11:34 +0200 |
parents | 0e6b4d65d3f8 |
children | fa91b03d9cd7 |
line wrap: on
line diff
--- a/gen/toir.cpp Sun Jul 27 18:52:40 2008 +0200 +++ b/gen/toir.cpp Mon Jul 28 02:11:34 2008 +0200 @@ -851,353 +851,42 @@ ////////////////////////////////////////////////////////////////////////////////////////// -// TODO: the method below could really use a cleanup/splitup - DValue* CallExp::toElem(IRState* p) { Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - DValue* fn = e1->toElem(p); - - TypeFunction* tf = 0; - Type* e1type = DtoDType(e1->type); - - bool delegateCall = false; - LINK dlink = LINKd; - - // hidden struct return parameter handling - bool retinptr = false; - - // regular functions - if (e1type->ty == Tfunction) { - tf = (TypeFunction*)e1type; - if (tf->llvmRetInPtr) { - retinptr = true; - } - dlink = tf->linkage; - } - - // delegates - else if (e1type->ty == Tdelegate) { - Logger::println("delegateTy = %s\n", e1type->toChars()); - assert(e1type->next->ty == Tfunction); - tf = (TypeFunction*)e1type->next; - if (tf->llvmRetInPtr) { - retinptr = true; - } - dlink = tf->linkage; - delegateCall = true; - } - - // invalid - else { - assert(tf); - } - - // handling of special intrinsics - bool va_magic = false; + // get the callee value + DValue* fnval = e1->toElem(p); + + // get func value if any + DFuncValue* dfnval = fnval->isFunc(); + + // handle magic intrinsics (mapping to instructions) bool va_intrinsic = false; - DFuncValue* dfv = fn->isFunc(); - if (dfv && dfv->func) { - FuncDeclaration* fndecl = dfv->func; - // vararg intrinsic - if (fndecl->llvmInternal == LLVMva_intrinsic) { - va_magic = true; - va_intrinsic = true; - } + if (dfnval && dfnval->func) + { + FuncDeclaration* fndecl = dfnval->func; // va_start instruction - else if (fndecl->llvmInternal == LLVMva_start) { - va_magic = true; + if (fndecl->llvmInternal == LLVMva_start) { + // TODO + assert(0 && "va_start not yet implemented"); } // va_arg instruction else if (fndecl->llvmInternal == LLVMva_arg) { - //Argument* fnarg = Argument::getNth(tf->parameters, 0); - Expression* exp = (Expression*)arguments->data[0]; - DValue* expelem = exp->toElem(p); - Type* t = DtoDType(type); - const LLType* llt = DtoType(type); - if (DtoIsPassedByRef(t)) - llt = getPtrToType(llt); - // TODO - // issue a warning for broken va_arg instruction. - if (strcmp(global.params.llvmArch, "x86") != 0) { - warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars()); - } - // done - return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp")); + return DtoVaArg(loc, type, (Expression*)arguments->data[0]); } - // alloca + // C alloca else if (fndecl->llvmInternal == LLVMalloca) { - //Argument* fnarg = Argument::getNth(tf->parameters, 0); Expression* exp = (Expression*)arguments->data[0]; DValue* expv = exp->toElem(p); if (expv->getType()->toBasetype()->ty != Tint32) expv = DtoCast(loc, expv, Type::tint32); - LLValue* alloc = new llvm::AllocaInst(LLType::Int8Ty, expv->getRVal(), "alloca", p->scopebb()); - // done - return new DImValue(type, alloc); - } - } - - // args - size_t n = arguments->dim; - DFuncValue* dfn = fn->isFunc(); - if (dfn && dfn->func && dfn->func->llvmInternal == LLVMva_start) - n = 1; - if (delegateCall || (dfn && dfn->vthis)) n++; - if (retinptr) n++; - if (tf->linkage == LINKd && tf->varargs == 1) n+=2; - if (dfn && dfn->func && dfn->func->isNested()) n++; - - LLValue* funcval = fn->getRVal(); - assert(funcval != 0); - std::vector<LLValue*> llargs(n, 0); - - const LLFunctionType* llfnty = 0; - - // TODO: review the stuff below, using the llvm type to choose seem like a bad idea. the D type should be used. - // - // normal function call - if (llvm::isa<LLFunctionType>(funcval->getType())) { - llfnty = llvm::cast<LLFunctionType>(funcval->getType()); - } - // pointer to something - else if (isaPointer(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 (isaPointer(funcval->getType()->getContainedType(0))) { - funcval = DtoLoad(funcval); - } - // function pointer - if (llvm::isa<LLFunctionType>(funcval->getType()->getContainedType(0))) { - //Logger::cout() << "function pointer type:\n" << *funcval << '\n'; - llfnty = llvm::cast<LLFunctionType>(funcval->getType()->getContainedType(0)); - } - // struct pointer - delegate - else if (isaStruct(funcval->getType()->getContainedType(0))) { - funcval = DtoGEPi(funcval,0,1); - funcval = DtoLoad(funcval); - const LLType* ty = funcval->getType()->getContainedType(0); - llfnty = llvm::cast<LLFunctionType>(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 - LLFunctionType::param_iterator argiter = llfnty->param_begin(); - int j = 0; - - // attrs - llvm::PAListPtr palist; - - // hidden struct return arguments - // TODO: use sret param attr - if (retinptr) { - llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint()); - ++j; - ++argiter; - } - - // this arguments - if (dfn && dfn->vthis) { - Logger::cout() << "This Call" << '\n';// func val:" << *funcval << '\n'; - if (dfn->vthis->getType() != argiter->get()) { - //Logger::cout() << "value: " << *dfn->vthis << " totype: " << *argiter->get() << '\n'; - llargs[j] = DtoBitCast(dfn->vthis, argiter->get()); - } - else { - llargs[j] = dfn->vthis; - } - ++j; - ++argiter; - } - // delegate context arguments - else if (delegateCall) { - Logger::println("Delegate Call"); - LLValue* contextptr = DtoGEPi(fn->getRVal(),0,0); - llargs[j] = DtoLoad(contextptr); - ++j; - ++argiter; - } - // nested call - else if (dfn && dfn->func && dfn->func->isNested()) { - Logger::println("Nested Call"); - LLValue* contextptr = DtoNestedContext(dfn->func->toParent2()->isFuncDeclaration()); - if (!contextptr) - contextptr = llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)); - llargs[j] = DtoBitCast(contextptr, getPtrToType(LLType::Int8Ty)); - ++j; - ++argiter; - } - - // va arg function special argument passing - if (va_magic) - { - size_t n = va_intrinsic ? arguments->dim : 1; - for (int i=0; i<n; i++,j++) - { - Argument* fnarg = Argument::getNth(tf->parameters, i); - Expression* exp = (Expression*)arguments->data[i]; - DValue* expelem = exp->toElem(p); - llargs[j] = DtoBitCast(expelem->getLVal(), getPtrToType(LLType::Int8Ty)); + return new DImValue(type, gIR->ir->CreateAlloca(LLType::Int8Ty, expv->getRVal(), ".alloca")); } } - // d variadic function - else if (tf->linkage == LINKd && tf->varargs == 1) - { - Logger::println("doing d-style variadic arguments"); - - size_t nimplicit = j; - - std::vector<const LLType*> vtypes; - - // number of non variadic args - int begin = tf->parameters->dim; - Logger::println("num non vararg params = %d", begin); - - // build struct with argument types - for (int i=begin; i<arguments->dim; i++) - { - Argument* argu = Argument::getNth(tf->parameters, i); - Expression* argexp = (Expression*)arguments->data[i]; - vtypes.push_back(DtoType(argexp->type)); - size_t sz = getABITypeSize(vtypes.back()); - if (sz < PTRSIZE) - vtypes.back() = DtoSize_t(); - } - const LLStructType* vtype = LLStructType::get(vtypes); - Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n'; - LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint()); - - // store arguments in the struct - for (int i=begin,k=0; i<arguments->dim; i++,k++) - { - Expression* argexp = (Expression*)arguments->data[i]; - if (global.params.llvmAnnotate) - DtoAnnotation(argexp->toChars()); - LLValue* argdst = DtoGEPi(mem,0,k); - argdst = DtoBitCast(argdst, getPtrToType(DtoType(argexp->type))); - DtoVariadicArgument(argexp, argdst); - } - - // build type info array - assert(Type::typeinfo->ir.irStruct->constInit); - const LLType* typeinfotype = DtoType(Type::typeinfo->type); - const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements()); - - llvm::GlobalVariable* typeinfomem = - new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module); - Logger::cout() << "_arguments storage: " << *typeinfomem << '\n'; - - std::vector<LLConstant*> vtypeinfos; - for (int i=begin,k=0; i<arguments->dim; i++,k++) - { - Expression* argexp = (Expression*)arguments->data[i]; - vtypeinfos.push_back(DtoTypeInfoOf(argexp->type)); - } - - // apply initializer - LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos); - typeinfomem->setInitializer(tiinits); - - // put data in d-array - std::vector<LLConstant*> pinits; - pinits.push_back(DtoConstSize_t(vtype->getNumElements())); - pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype))); - const LLType* tiarrty = llfnty->getParamType(j)->getContainedType(0); - tiinits = llvm::ConstantStruct::get(pinits); - LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty, - true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module); - - // specify arguments - llargs[j] = typeinfoarrayparam;; - j++; - llargs[j] = p->ir->CreateBitCast(mem, getPtrToType(LLType::Int8Ty), "tmp"); - j++; - - // pass non variadic args - for (int i=0; i<begin; i++) - { - Argument* fnarg = Argument::getNth(tf->parameters, i); - DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); - llargs[j] = argval->getRVal(); - - if (fnarg->llvmByVal) - palist = palist.addAttr(j, llvm::ParamAttr::ByVal); - - j++; - } - - // make sure arg vector has the right size - llargs.resize(nimplicit+begin+2); - } - // normal function call - else - { - Logger::println("doing normal arguments"); - for (int i=0; i<arguments->dim; i++,j++) { - Argument* fnarg = Argument::getNth(tf->parameters, i); - if (global.params.llvmAnnotate) - DtoAnnotation(((Expression*)arguments->data[i])->toChars()); - DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); - llargs[j] = argval->getRVal(); - if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) { - llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); - } - - if (fnarg && fnarg->llvmByVal) - palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal); - } - } - - #if 0 - Logger::println("%d params passed", n); - for (int i=0; i<llargs.size(); ++i) { - assert(llargs[i]); - Logger::cout() << "arg["<<i<<"] = " << *llargs[i] << '\n'; - } - #endif - - // void returns cannot not be named - const char* varname = ""; - if (llfnty->getReturnType() != LLType::VoidTy) - varname = "tmp"; - - //Logger::cout() << "Calling: " << *funcval << '\n'; - - // call the function - CallOrInvoke* call = gIR->CreateCallOrInvoke(funcval, llargs.begin(), llargs.end(), varname); - - LLValue* retllval = (retinptr) ? llargs[0] : call->get(); - - // if the type of retllval is abstract, refine to concrete - if(retllval->getType()->isAbstract()) - retllval = DtoBitCast(retllval, getPtrToType(DtoType(type)), "retval"); - - // set calling convention - if (dfn && dfn->func) { - int li = dfn->func->llvmInternal; - if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { - call->setCallingConv(DtoCallingConv(dlink)); - } - } - else { - call->setCallingConv(DtoCallingConv(dlink)); - } - - // param attrs - call->setParamAttrs(palist); - - return new DImValue(type, retllval, false); + + return DtoCallFunction(type, fnval, arguments); } //////////////////////////////////////////////////////////////////////////////////////////