bool alreadyOrWillBeDefined(FuncDeclaration &fdecl) { for (FuncDeclaration *f = &fdecl; f;) { if (!f->isInstantiated() && f->inNonRoot()) { return false; } if (f->isNested()) { f = f->toParent2()->isFuncDeclaration(); } else { break; } } return true; }
void DtoDefineFunction(FuncDeclaration* fd) { IF_LOG Logger::println("DtoDefineFunction(%s): %s", fd->toPrettyChars(), fd->loc.toChars()); LOG_SCOPE; if (fd->ir.isDefined()) return; if ((fd->type && fd->type->ty == Terror) || (fd->type && fd->type->ty == Tfunction && static_cast<TypeFunction *>(fd->type)->next == NULL) || (fd->type && fd->type->ty == Tfunction && static_cast<TypeFunction *>(fd->type)->next->ty == Terror)) { IF_LOG Logger::println("Ignoring; has error type, no return type or returns error type"); fd->ir.setDefined(); return; } if (fd->semanticRun == PASSsemanticdone) { /* What happened is this function failed semantic3() with errors, * but the errors were gagged. * Try to reproduce those errors, and then fail. */ error(fd->loc, "errors compiling function %s", fd->toPrettyChars()); fd->ir.setDefined(); return; } DtoResolveFunction(fd); if (fd->isUnitTestDeclaration() && !global.params.useUnitTests) { IF_LOG Logger::println("No code generation for unit test declaration %s", fd->toChars()); fd->ir.setDefined(); return; } // Skip array ops implemented in druntime if (fd->isArrayOp && isDruntimeArrayOp(fd)) { IF_LOG Logger::println("No code generation for array op %s implemented in druntime", fd->toChars()); fd->ir.setDefined(); return; } // Check whether the frontend knows that the function is already defined // in some other module (see DMD's FuncDeclaration::toObjFile). for (FuncDeclaration *f = fd; f; ) { if (!f->isInstantiated() && f->inNonRoot()) { IF_LOG Logger::println("Skipping '%s'.", fd->toPrettyChars()); // TODO: Emit as available_externally for inlining purposes instead // (see #673). fd->ir.setDefined(); return; } if (f->isNested()) f = f->toParent2()->isFuncDeclaration(); else break; } DtoDeclareFunction(fd); assert(fd->ir.isDeclared()); // DtoResolveFunction might also set the defined flag for functions we // should not touch. if (fd->ir.isDefined()) return; fd->ir.setDefined(); // We cannot emit nested functions with parents that have not gone through // semantic analysis. This can happen as DMD leaks some template instances // from constraints into the module member list. DMD gets away with being // sloppy as functions in template contraints obviously never need to access // data from the template function itself, but it would still mess up our // nested context creation code. FuncDeclaration* parent = fd; while ((parent = getParentFunc(parent, true))) { if (parent->semanticRun != PASSsemantic3done || parent->semantic3Errors) { IF_LOG Logger::println("Ignoring nested function with unanalyzed parent."); return; } } assert(fd->semanticRun == PASSsemantic3done); assert(fd->ident != Id::empty); if (fd->isUnitTestDeclaration()) { gIR->unitTests.push_back(fd); } else if (fd->isSharedStaticCtorDeclaration()) { gIR->sharedCtors.push_back(fd); } else if (StaticDtorDeclaration *dtorDecl = fd->isSharedStaticDtorDeclaration()) { gIR->sharedDtors.push_front(fd); if (dtorDecl->vgate) gIR->sharedGates.push_front(dtorDecl->vgate); } else if (fd->isStaticCtorDeclaration()) { gIR->ctors.push_back(fd); } else if (StaticDtorDeclaration *dtorDecl = fd->isStaticDtorDeclaration()) { gIR->dtors.push_front(fd); if (dtorDecl->vgate) gIR->gates.push_front(dtorDecl->vgate); } // if this function is naked, we take over right away! no standard processing! if (fd->naked) { DtoDefineNakedFunction(fd); return; } IrFunction *irFunc = getIrFunc(fd); IrFuncTy &irFty = irFunc->irFty; // debug info irFunc->diSubprogram = gIR->DBuilder.EmitSubProgram(fd); Type* t = fd->type->toBasetype(); TypeFunction* f = static_cast<TypeFunction*>(t); // assert(f->ctype); llvm::Function* func = irFunc->func; // is there a body? if (fd->fbody == NULL) return; IF_LOG Logger::println("Doing function body for: %s", fd->toChars()); gIR->functions.push_back(irFunc); if (fd->isMain()) gIR->emitMain = true; func->setLinkage(lowerFuncLinkage(fd)); // On x86_64, always set 'uwtable' for System V ABI compatibility. // TODO: Find a better place for this. // TODO: Is this required for Win64 as well? if (global.params.targetTriple.getArch() == llvm::Triple::x86_64) { func->addFnAttr(LDC_ATTRIBUTE(UWTable)); } #if LDC_LLVM_VER >= 303 if (opts::sanitize != opts::None) { // Set the required sanitizer attribute. if (opts::sanitize == opts::AddressSanitizer) { func->addFnAttr(LDC_ATTRIBUTE(SanitizeAddress)); } if (opts::sanitize == opts::MemorySanitizer) { func->addFnAttr(LDC_ATTRIBUTE(SanitizeMemory)); } if (opts::sanitize == opts::ThreadSanitizer) { func->addFnAttr(LDC_ATTRIBUTE(SanitizeThread)); } } #endif llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "", func); llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", func); //assert(gIR->scopes.empty()); gIR->scopes.push_back(IRScope(beginbb, endbb)); // create alloca point // this gets erased when the function is complete, so alignment etc does not matter at all llvm::Instruction* allocaPoint = new llvm::AllocaInst(LLType::getInt32Ty(gIR->context()), "alloca point", beginbb); irFunc->allocapoint = allocaPoint; // debug info - after all allocas, but before any llvm.dbg.declare etc gIR->DBuilder.EmitFuncStart(fd); // this hack makes sure the frame pointer elimination optimization is disabled. // this this eliminates a bunch of inline asm related issues. if (fd->hasReturnExp & 8) // has inline asm { // emit a call to llvm_eh_unwind_init LLFunction* hack = GET_INTRINSIC_DECL(eh_unwind_init); gIR->ir->CreateCall(hack, ""); } // give the 'this' argument storage and debug info if (irFty.arg_this) { LLValue* thisvar = irFunc->thisArg; assert(thisvar); LLValue* thismem = thisvar; if (!irFty.arg_this->byref) { thismem = DtoRawAlloca(thisvar->getType(), 0, "this"); // FIXME: align? DtoStore(thisvar, thismem); irFunc->thisArg = thismem; } assert(getIrParameter(fd->vthis)->value == thisvar); getIrParameter(fd->vthis)->value = thismem; gIR->DBuilder.EmitLocalVariable(thismem, fd->vthis); } // give the 'nestArg' storage if (irFty.arg_nest) { LLValue *nestArg = irFunc->nestArg; LLValue *val = DtoRawAlloca(nestArg->getType(), 0, "nestedFrame"); DtoStore(nestArg, val); irFunc->nestArg = val; } // give arguments storage // and debug info if (fd->parameters) { size_t n = irFty.args.size(); assert(n == fd->parameters->dim); for (size_t i=0; i < n; ++i) { Dsymbol* argsym = static_cast<Dsymbol*>(fd->parameters->data[i]); VarDeclaration* vd = argsym->isVarDeclaration(); assert(vd); IrParameter* irparam = getIrParameter(vd); assert(irparam); bool refout = vd->storage_class & (STCref | STCout); bool lazy = vd->storage_class & STClazy; if (!refout && (!irparam->arg->byref || lazy)) { // alloca a stack slot for this first class value arg LLValue* mem = DtoAlloca(irparam->arg->type, vd->ident->toChars()); // let the abi transform the argument back first DImValue arg_dval(vd->type, irparam->value); irFty.getParam(vd->type, i, &arg_dval, mem); // set the arg var value to the alloca irparam->value = mem; } if (global.params.symdebug && !(isaArgument(irparam->value) && isaArgument(irparam->value)->hasByValAttr()) && !refout) gIR->DBuilder.EmitLocalVariable(irparam->value, vd); } } FuncGen fg; irFunc->gen = &fg; DtoCreateNestedContext(fd); if (fd->vresult && ! fd->vresult->nestedrefs.dim // FIXME: not sure here :/ ) { DtoVarDeclaration(fd->vresult); } // D varargs: prepare _argptr and _arguments if (f->linkage == LINKd && f->varargs == 1) { // allocate _argptr (of type core.stdc.stdarg.va_list) LLValue* argptrmem = DtoAlloca(Type::tvalist, "_argptr_mem"); irFunc->_argptr = argptrmem; // initialize _argptr with a call to the va_start intrinsic LLValue* vaStartArg = gABI->prepareVaStart(argptrmem); llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), vaStartArg, "", gIR->scopebb()); // copy _arguments to a memory location LLType* argumentsType = irFunc->_arguments->getType(); LLValue* argumentsmem = DtoRawAlloca(argumentsType, 0, "_arguments_mem"); new llvm::StoreInst(irFunc->_arguments, argumentsmem, gIR->scopebb()); irFunc->_arguments = argumentsmem; } // output function body codegenFunction(fd->fbody, gIR); irFunc->gen = 0; llvm::BasicBlock* bb = gIR->scopebb(); if (pred_begin(bb) == pred_end(bb) && bb != &bb->getParent()->getEntryBlock()) { // This block is trivially unreachable, so just delete it. // (This is a common case because it happens when 'return' // is the last statement in a function) bb->eraseFromParent(); } else if (!gIR->scopereturned()) { // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement // in automatically, so we do it here. // pass the previous block into this block gIR->DBuilder.EmitFuncEnd(fd); if (func->getReturnType() == LLType::getVoidTy(gIR->context())) { llvm::ReturnInst::Create(gIR->context(), gIR->scopebb()); } else if (!fd->isMain()) { AsmBlockStatement* asmb = fd->fbody->endsWithAsm(); if (asmb) { assert(asmb->abiret); llvm::ReturnInst::Create(gIR->context(), asmb->abiret, bb); } else { llvm::ReturnInst::Create(gIR->context(), llvm::UndefValue::get(func->getReturnType()), bb); } } else llvm::ReturnInst::Create(gIR->context(), LLConstant::getNullValue(func->getReturnType()), bb); } // erase alloca point if (allocaPoint->getParent()) allocaPoint->eraseFromParent(); allocaPoint = 0; gIR->func()->allocapoint = 0; gIR->scopes.pop_back(); // get rid of the endentry block, it's never used assert(!func->getBasicBlockList().empty()); func->getBasicBlockList().pop_back(); gIR->functions.pop_back(); }