Expression *CallExp::inlineScan(InlineScanState *iss, Expression *eret) { Expression *e = this; //printf("CallExp::inlineScan()\n"); e1 = e1->inlineScan(iss); arrayInlineScan(iss, arguments); if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; FuncDeclaration *fd = ve->var->isFuncDeclaration(); if (fd && fd != iss->fd && fd->canInline(0, 0, 0)) { Expression *ex = fd->expandInline(iss, eret, NULL, arguments, NULL); if (ex) e = ex; } } else if (e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e1; FuncDeclaration *fd = dve->var->isFuncDeclaration(); if (fd && fd != iss->fd && fd->canInline(1, 0, 0)) { if (dve->e1->op == TOKcall && dve->e1->type->toBasetype()->ty == Tstruct) { /* To create ethis, we'll need to take the address * of dve->e1, but this won't work if dve->e1 is * a function call. */ ; } else { Expression *ex = fd->expandInline(iss, eret, dve->e1, arguments, NULL); if (ex) e = ex; } } } if (e && type->ty != Tvoid && !type->equals(e->type) && e->type->hasWild() && !type->hasWild()) { e = e->copy(); e->type = type; } return e; }
Statement *ExpStatement::inlineScan(InlineScanState *iss) { #if LOG printf("ExpStatement::inlineScan(%s)\n", toChars()); #endif if (exp) { exp = exp->inlineScan(iss); /* See if we can inline as a statement rather than as * an Expression. */ if (exp && exp->op == TOKcall) { CallExp *ce = (CallExp *)exp; if (ce->e1->op == TOKvar) { VarExp *ve = (VarExp *)ce->e1; FuncDeclaration *fd = ve->var->isFuncDeclaration(); if (fd && fd != iss->fd && fd->canInline(0, 0, 1)) { Statement *s; fd->expandInline(iss, NULL, NULL, ce->arguments, &s); return s; } } } } return this; }
Expression *CallExp::inlineScan(InlineScanState *iss) { Expression *e = this; //printf("CallExp::inlineScan()\n"); e1 = e1->inlineScan(iss); arrayInlineScan(iss, arguments); if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; FuncDeclaration *fd = ve->var->isFuncDeclaration(); if (fd && fd != iss->fd && fd->canInline(0)) { e = fd->doInline(iss, NULL, arguments); } } else if (e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e1; FuncDeclaration *fd = dve->var->isFuncDeclaration(); if (fd && fd != iss->fd && fd->canInline(1)) { if (dve->e1->op == TOKcall && dve->e1->type->toBasetype()->ty == Tstruct) { /* To create ethis, we'll need to take the address * of dve->e1, but this won't work if dve->e1 is * a function call. */ ; } else e = fd->doInline(iss, dve->e1, arguments); } } return e; }
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { // global/static variable if (VarDeclaration* vd = sym->isVarDeclaration()) { IF_LOG Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); // generated by inlining semantics run if (vd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (DtoIsTemplateInstance(sym)) return templateLinkage; // Currently, we have to consider all variables, even function-local // statics, to be external, as CTFE might cause template functions // instances to be semantic3'd that occur within the body of a function // from an imported module. Consequently, a copy of them is codegen'd // in the importing module, even if they might reference a static in a // function in the imported module (e.g. via an alias parameter). // // A fix for this would be to track instantiations/semantic3 runs made // solely for CTFE purposes in a way similar to how the extra inlining // semantic runs are handled. // // LDC_FIXME: Can this also occur for functions? Find a better solution. if (true || vd->storage_class & STCextern) return llvm::GlobalValue::ExternalLinkage; } else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { IF_LOG Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type); // intrinsics are always external if (fdecl->llvmInternal == LLVMintrinsic) return llvm::GlobalValue::ExternalLinkage; // Mark functions generated by an inlining semantic run as // available_externally. Naked functions are turned into module-level // inline asm and are thus declaration-only as far as the LLVM IR level // is concerned. if (fdecl->availableExternally && !fdecl->naked) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage if (fdecl->isArrayOp == 1) return templateLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external if (DtoIsTemplateInstance(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external if (ft->linkage == LINKc) return llvm::GlobalValue::ExternalLinkage; // If a function without a body is nested in another // function, we cannot use internal linkage for that // function (see below about nested functions) // FIXME: maybe there is a better way without emission // of needless symbols? if (!fdecl->fbody) return llvm::GlobalValue::ExternalLinkage; } // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { IF_LOG Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); // generated by inlining semantics run if (cd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (DtoIsTemplateInstance(cd)) return templateLinkage; } else { llvm_unreachable("not global/function"); } // The logic here should be sound in theory, but as long as the frontend // keeps inserting templates into wrong modules, this yields to linking // errors (see e.g. GitHub issue #558). #if 0 // Check if sym is a nested function and we can declare it as internal. // // Nested naked functions and the implicitly generated __require/__ensure // functions for in/out contracts cannot be internalized. The reason // for the latter is that contract functions, despite being nested, can be // referenced from other D modules e.g. in the case of contracts on // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). FuncDeclaration* fd = sym->isFuncDeclaration(); if (!fd || (!fd->naked && fd->ident != Id::require && fd->ident != Id::ensure)) { // Any symbol nested in a function that cannot be inlined can't be // referenced directly from outside that function, so we can give // such symbols internal linkage. This holds even if nested indirectly, // such as member functions of aggregates nested in functions. // // Note: This must be checked after things like template member-ness or // symbols nested in templates would get duplicated for each module, // breaking things like // --- // int counter(T)() { static int i; return i++; }" // --- // if instances get emitted in multiple object files because they'd use // different instances of 'i'. // TODO: Check if we are giving away too much inlining potential due to // canInline being overly conservative here. for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { FuncDeclaration *parentFd = parent->isFuncDeclaration(); if (parentFd && !parentFd->canInline(parentFd->needThis(), false, false)) { // We also cannot internalize nested functions which are // leaked to the outside via a templated return type, because // that type will also be codegen'd in any caller modules (see // GitHub issue #131). // Since we can't easily determine if this is really the case // here, just don't internalize it if the parent returns a // template at all, to be safe. TypeFunction* tf = static_cast<TypeFunction*>(parentFd->type); if (!DtoIsTemplateInstance(tf->next->toDsymbol(parentFd->scope))) return llvm::GlobalValue::InternalLinkage; } } } #endif // default to external linkage return llvm::GlobalValue::ExternalLinkage; }
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { const bool mustDefine = mustDefineSymbol(sym); // global variable if (VarDeclaration* vd = sym->isVarDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (vd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(sym)) return templateLinkage; // never use InternalLinkage for variables marked as "extern" if (vd->storage_class & STCextern) return llvm::GlobalValue::ExternalLinkage; } // function else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); } assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type); // intrinsics are always external if (fdecl->llvmInternal == LLVMintrinsic) return llvm::GlobalValue::ExternalLinkage; // generated by inlining semantics run if (fdecl->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage if (fdecl->isArrayOp == 1) return templateLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external else if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external else if (ft->linkage == LINKc) return llvm::GlobalValue::ExternalLinkage; // If a function without a body is nested in another // function, we cannot use internal linkage for that // function (see below about nested functions) // FIXME: maybe there is a better way without emission // of needless symbols? if (!fdecl->fbody) return llvm::GlobalValue::ExternalLinkage; } // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { if (mustDefine) { IF_LOG Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); } // generated by inlining semantics run if (cd->availableExternally && mustDefine) return llvm::GlobalValue::AvailableExternallyLinkage; // template if (needsTemplateLinkage(cd)) return templateLinkage; } else { assert(0 && "not global/function"); } // If the function needs to be defined in the current module, check if it // is a nested function and we can declare it as internal. bool canInternalize = mustDefine; // Nested naked functions and the implicitly generated __require/__ensure // functions for in/out contracts cannot be internalized. The reason // for the latter is that contract functions, despite being nested, can be // referenced from other D modules e.g. in the case of contracts on // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). if (canInternalize) { if (FuncDeclaration* fd = sym->isFuncDeclaration()) { if ((fd->naked != 0) || (fd->ident == Id::require) || (fd->ident == Id::ensure)) { canInternalize = false; } } } // Any symbol nested in a function that cannot be inlined can't be // referenced directly from outside that function, so we can give // such symbols internal linkage. This holds even if nested indirectly, // such as member functions of aggregates nested in functions. // // Note: This must be checked after things like template member-ness or // symbols nested in templates would get duplicated for each module, // breaking things like // --- // int counter(T)() { static int i; return i++; }" // --- // if instances get emitted in multiple object files because they'd use // different instances of 'i'. // TODO: Check if we are giving away too much inlining potential due to // canInline being overly conservative here. if (canInternalize) { for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { FuncDeclaration *fd = parent->isFuncDeclaration(); if (fd && !fd->canInline(fd->needThis())) { // We also cannot internalize nested functions which are // leaked to the outside via a templated return type, because // that type will also be codegen'd in any caller modules (see // GitHub issue #131). // Since we can't easily determine if this is really the case // here, just don't internalize it if the parent returns a // template at all, to be safe. TypeFunction* tf = static_cast<TypeFunction*>(fd->type); if (!DtoIsTemplateInstance(tf->next->toDsymbol(fd->scope))) return llvm::GlobalValue::InternalLinkage; } } } // default to external linkage return llvm::GlobalValue::ExternalLinkage; }