std::vector<llvm::Type *> IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; std::vector<llvm::Type *> types; types.reserve(vtbl_array->dim); auto I = vtbl_array->begin(); // first comes the classinfo for D interfaces if (first) { types.push_back(DtoType(first)); ++I; } // then come the functions for (auto E = vtbl_array->end(); I != E; ++I) { FuncDeclaration *fd = *I; if (fd == nullptr) { // FIXME: This stems from the ancient D1 days – can it still happen? types.push_back(getVoidPtrType()); continue; } IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); // If inferring return type and semantic3 has not been run, do it now. // This pops up in some other places in the frontend as well, however // it is probably a bug that it still occurs that late. if (!fd->type->nextOf() && fd->inferRetType) { Logger::println("Running late semantic3 to infer return type."); TemplateInstance *spec = fd->isSpeculative(); unsigned int olderrs = global.errors; fd->semantic3(fd->_scope); if (spec && global.errors != olderrs) { spec->errors = global.errors - olderrs; } } if (!fd->type->nextOf()) { // Return type of the function has not been inferred. This seems to // happen with virtual functions and is probably a frontend bug. IF_LOG Logger::println("Broken function type, semanticRun: %d", fd->semanticRun); types.push_back(getVoidPtrType()); continue; } types.push_back(getPtrToType(DtoFunctionType(fd))); } return types; }
IrTypeFunction* IrTypeFunction::get(Type* dt, Type* nestedContextOverride) { assert(!dt->irtype); assert(dt->ty == Tfunction); TypeFunction* tf = static_cast<TypeFunction*>(dt); llvm::Type* lt = DtoFunctionType(tf, tf->irFty, NULL, nestedContextOverride); if (!dt->irtype) dt->irtype = new IrTypeFunction(dt, lt); return dt->irtype->isFunction(); }
IrTypeDelegate* IrTypeDelegate::get(Type* t) { assert(!t->irtype); assert(t->ty == Tdelegate); assert(t->nextOf()->ty == Tfunction); TypeDelegate *dt = (TypeDelegate*)t; if (!dt->irtype) { TypeFunction* tf = static_cast<TypeFunction*>(dt->nextOf()); llvm::Type* ltf = DtoFunctionType(tf, dt->irFty, NULL, Type::tvoid->pointerTo()); llvm::Type *types[] = { getVoidPtrType(), getPtrToType(ltf) }; LLStructType* lt = LLStructType::get(gIR->context(), types, false); dt->irtype = new IrTypeDelegate(dt, lt); } return dt->irtype->isDelegate(); }
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; }
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"); } } } }
void DtoResolveFunction(FuncDeclaration* fdecl) { if ((!global.params.useUnitTests || !fdecl->type) && fdecl->isUnitTestDeclaration()) { IF_LOG Logger::println("Ignoring unittest %s", fdecl->toPrettyChars()); return; // ignore declaration completely } if (fdecl->ir.isResolved()) return; fdecl->ir.setResolved(); Type *type = fdecl->type; // If errors occurred compiling it, such as bugzilla 6118 if (type && type->ty == Tfunction) { Type *next = static_cast<TypeFunction *>(type)->next; if (!next || next->ty == Terror) return; } //printf("resolve function: %s\n", fdecl->toPrettyChars()); if (fdecl->parent) if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance()) { if (TemplateDeclaration* tempdecl = tinst->tempdecl->isTemplateDeclaration()) { if (tempdecl->llvmInternal == LLVMva_arg) { Logger::println("magic va_arg found"); fdecl->llvmInternal = LLVMva_arg; fdecl->ir.setDefined(); return; // this gets mapped to an instruction so a declaration makes no sence } else if (tempdecl->llvmInternal == LLVMva_start) { Logger::println("magic va_start found"); fdecl->llvmInternal = LLVMva_start; } else if (tempdecl->llvmInternal == LLVMintrinsic) { Logger::println("overloaded intrinsic found"); assert(fdecl->llvmInternal == LLVMintrinsic); assert(fdecl->mangleOverride); } else if (tempdecl->llvmInternal == LLVMinline_asm) { Logger::println("magic inline asm found"); TypeFunction* tf = static_cast<TypeFunction*>(fdecl->type); if (tf->varargs != 1 || (fdecl->parameters && fdecl->parameters->dim != 0)) { tempdecl->error("invalid __asm declaration, must be a D style variadic with no explicit parameters"); fatal(); } fdecl->llvmInternal = LLVMinline_asm; fdecl->ir.setDefined(); return; // this gets mapped to a special inline asm call, no point in going on. } else if (tempdecl->llvmInternal == LLVMinline_ir) { Logger::println("magic inline ir found"); fdecl->llvmInternal = LLVMinline_ir; fdecl->linkage = LINKc; Type* type = fdecl->type; assert(type->ty == Tfunction); static_cast<TypeFunction*>(type)->linkage = LINKc; DtoFunctionType(fdecl); DtoDeclareFunction(fdecl); fdecl->ir.setDefined(); return; } } } DtoFunctionType(fdecl); IF_LOG Logger::println("DtoResolveFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars()); LOG_SCOPE; // queue declaration unless the function is abstract without body if (!fdecl->isAbstract() || fdecl->fbody) { DtoDeclareFunction(fdecl); } }