llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) { // handle for C vararg intrinsics if (DtoIsVaIntrinsic(fdecl)) return DtoVaFunctionType(fdecl); Type *dthis=0, *dnest=0; if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) { FuncDeclaration *p = fdecl->parent->isFuncDeclaration(); assert(p); AggregateDeclaration *ad = p->isMember2(); assert(ad); dnest = Type::tvoid->pointerTo(); } else if (fdecl->needThis()) { if (AggregateDeclaration* ad = fdecl->isMember2()) { IF_LOG Logger::println("isMember = this is: %s", ad->type->toChars()); dthis = ad->type; LLType* thisty = DtoType(dthis); //Logger::cout() << "this llvm type: " << *thisty << '\n'; if (ad->isStructDeclaration()) thisty = getPtrToType(thisty); } else { IF_LOG Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind()); llvm_unreachable("needThis, but invalid parent declaration."); } } else if (fdecl->isNested()) { dnest = Type::tvoid->pointerTo(); } LLFunctionType* functype = DtoFunctionType(fdecl->type, getIrFunc(fdecl, true)->irFty, dthis, dnest, fdecl->isMain(), fdecl->isCtorDeclaration(), fdecl->llvmInternal == LLVMintrinsic); return functype; }
bool DtoIsIntrinsic(FuncDeclaration *fd) { return (fd->llvmInternal == LLVMintrinsic || DtoIsVaIntrinsic(fd)); }
void DtoDeclareFunction(FuncDeclaration* fdecl) { DtoResolveFunction(fdecl); if (fdecl->ir.isDeclared()) return; fdecl->ir.setDeclared(); IF_LOG Logger::println("DtoDeclareFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars()); LOG_SCOPE; if (fdecl->isUnitTestDeclaration() && !global.params.useUnitTests) { Logger::println("unit tests not enabled"); return; } //printf("declare function: %s\n", fdecl->toPrettyChars()); // intrinsic sanity check if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) { error(fdecl->loc, "intrinsics cannot have function bodies"); fatal(); } // get TypeFunction* Type* t = fdecl->type->toBasetype(); TypeFunction* f = static_cast<TypeFunction*>(t); // create IrFunction IrFunction *irFunc = getIrFunc(fdecl, true); LLFunction* vafunc = 0; if (DtoIsVaIntrinsic(fdecl)) vafunc = DtoDeclareVaFunction(fdecl); // calling convention LINK link = f->linkage; if (vafunc || fdecl->llvmInternal == LLVMintrinsic // DMD treats _Dmain as having C calling convention and this has been // hardcoded into druntime, even if the frontend type has D linkage. // See Bugzilla issue 9028. || fdecl->isMain() ) { link = LINKc; } // mangled name std::string mangledName(mangleExact(fdecl)); mangledName = gABI->mangleForLLVM(mangledName, link); // construct function LLFunctionType* functype = DtoFunctionType(fdecl); LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName); if (!func) { if(fdecl->llvmInternal == LLVMinline_ir) { func = DtoInlineIRFunction(fdecl); } else { // All function declarations are "external" - any other linkage type // is set when actually defining the function. func = LLFunction::Create(functype, llvm::GlobalValue::ExternalLinkage, mangledName, gIR->module); } } else if (func->getFunctionType() != functype) { error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", mangleExact(fdecl)); fatal(); } func->setCallingConv(gABI->callingConv(link)); IF_LOG Logger::cout() << "func = " << *func << std::endl; // add func to IRFunc irFunc->func = func; // parameter attributes if (!DtoIsIntrinsic(fdecl)) { set_param_attrs(f, func, fdecl); if (global.params.disableRedZone) { func->addFnAttr(LDC_ATTRIBUTE(NoRedZone)); } } // main if (fdecl->isMain()) { // Detect multiple main functions, which is disallowed. DMD checks this // in the glue code, so we need to do it here as well. if (gIR->mainFunc) { error(fdecl->loc, "only one main function allowed"); } gIR->mainFunc = func; } if (fdecl->neverInline) { irFunc->setNeverInline(); } if (fdecl->llvmInternal == LLVMglobal_crt_ctor || fdecl->llvmInternal == LLVMglobal_crt_dtor) { AppendFunctionToLLVMGlobalCtorsDtors(func, fdecl->priority, fdecl->llvmInternal == LLVMglobal_crt_ctor); } IrFuncTy &irFty = irFunc->irFty; // if (!declareOnly) { // name parameters llvm::Function::arg_iterator iarg = func->arg_begin(); if (irFty.arg_sret) { iarg->setName(".sret_arg"); irFunc->retArg = iarg; ++iarg; } if (irFty.arg_this) { iarg->setName(".this_arg"); irFunc->thisArg = iarg; VarDeclaration* v = fdecl->vthis; if (v) { // We already build the this argument here if we will need it // later for codegen'ing the function, just as normal // parameters below, because it can be referred to in nested // context types. Will be given storage in DtoDefineFunction. assert(!isIrParameterCreated(v)); IrParameter *irParam = getIrParameter(v, true); irParam->value = iarg; irParam->arg = irFty.arg_this; irParam->isVthis = true; } ++iarg; } else if (irFty.arg_nest) { iarg->setName(".nest_arg"); irFunc->nestArg = iarg; assert(irFunc->nestArg); ++iarg; } if (irFty.arg_arguments) { iarg->setName("._arguments"); irFunc->_arguments = iarg; ++iarg; } // we never reference parameters of function prototypes unsigned int k = 0; for (; iarg != func->arg_end(); ++iarg) { if (fdecl->parameters && fdecl->parameters->dim > k) { int paramIndex = irFty.reverseParams ? fdecl->parameters->dim-k-1 : k; Dsymbol* argsym = static_cast<Dsymbol*>(fdecl->parameters->data[paramIndex]); VarDeclaration* argvd = argsym->isVarDeclaration(); assert(argvd); assert(!isIrLocalCreated(argvd)); std::string str(argvd->ident->toChars()); str.append("_arg"); iarg->setName(str); IrParameter *irParam = getIrParameter(argvd, true); irParam->value = iarg; irParam->arg = irFty.args[paramIndex]; k++; } else { iarg->setName("unnamed"); } } } }