# HG changeset patch # User Frits van Bommel # Date 1244383213 -7200 # Node ID d9c5f5a434039cf7208e0bd9e17c3a25f1ebaa74 # Parent e0f03e11cdf83936fe83f4c301d28a97a01212fb Run `semantic3` on imported modules, and emit new symbols with `available_externally` linkage. This allows the inliner to inline functions from other modules while telling the code generator to ignore those functions (treat them as declarations) Still generates a few extra `TypeInfo`s and strings... Disabled when generating debug info because I don't really understand it, and it doesn't like this. diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/aggregate.h --- a/dmd/aggregate.h Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/aggregate.h Sun Jun 07 16:00:13 2009 +0200 @@ -106,6 +106,11 @@ #endif AggregateDeclaration *isAggregateDeclaration() { return this; } + +#if IN_LLVM + // Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; +#endif }; struct AnonymousAggregateDeclaration : AggregateDeclaration diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/declaration.c --- a/dmd/declaration.c Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/declaration.c Sun Jun 07 16:00:13 2009 +0200 @@ -635,6 +635,8 @@ offset2 = 0; nakedUse = false; + + availableExternally = true; // assume this unless proven otherwise #endif } @@ -1091,6 +1093,16 @@ } } +void VarDeclaration::semantic3(Scope *sc) +{ + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + // Preserve call chain + Declaration::semantic3(sc); +} + const char *VarDeclaration::kind() { return "variable"; @@ -1296,6 +1308,9 @@ void TypeInfoDeclaration::semantic(Scope *sc) { assert(linkage == LINKc); + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; } /***************************** TypeInfoConstDeclaration **********************/ diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/declaration.h --- a/dmd/declaration.h Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/declaration.h Sun Jun 07 16:00:13 2009 +0200 @@ -300,6 +300,11 @@ /// Set during type generation. unsigned aggrIndex; + /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + /// Override added to set above flag. + void semantic3(Scope *sc); + // FIXME: we're not using these anymore! AnonDeclaration* anonDecl; unsigned offset2; @@ -754,6 +759,9 @@ // if this is an array operation it gets a little special attention bool isArrayOp; + // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + // true if overridden with the pragma(allow_inline); stmt bool allowInlining; #endif diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/func.c --- a/dmd/func.c Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/func.c Sun Jun 07 16:00:13 2009 +0200 @@ -84,6 +84,8 @@ isArrayOp = false; allowInlining = false; + availableExternally = true; // assume this unless proven otherwise + // function types in ldc don't merge if the context parameter differs // so we actually don't care about the function declaration, but only // what kind of context parameter it has. @@ -674,6 +676,10 @@ return; semanticRun = 3; + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + if (!type || type->ty != Tfunction) return; f = (TypeFunction *)(type); diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/inline.c --- a/dmd/inline.c Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/inline.c Sun Jun 07 16:00:13 2009 +0200 @@ -83,14 +83,17 @@ { int cost; +#if !IN_LLVM /* Can't declare variables inside ?: expressions, so * we cannot inline if a variable is declared. */ if (arg) return COST_MAX; +#endif cost = condition->inlineCost(ics); +#if !IN_LLVM /* Specifically allow: * if (condition) * return exp1; @@ -108,6 +111,7 @@ //printf("cost = %d\n", cost); } else +#endif { ics->nested += 1; if (ifbody) @@ -121,9 +125,11 @@ int ReturnStatement::inlineCost(InlineCostState *ics) { +#if !IN_LLVM // Can't handle return statements nested in if's if (ics->nested) return COST_MAX; +#endif return exp ? exp->inlineCost(ics) : 0; } @@ -157,19 +163,23 @@ int ThisExp::inlineCost(InlineCostState *ics) { +#if !IN_LLVM FuncDeclaration *fd = ics->fd; if (!ics->hdrscan) if (fd->isNested() || !ics->hasthis) return COST_MAX; +#endif return 1; } int SuperExp::inlineCost(InlineCostState *ics) { +#if !IN_LLVM FuncDeclaration *fd = ics->fd; if (!ics->hdrscan) if (fd->isNested() || !ics->hasthis) return COST_MAX; +#endif return 1; } @@ -195,12 +205,16 @@ int FuncExp::inlineCost(InlineCostState *ics) { + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. // Right now, this makes the function be output to the .obj file twice. return COST_MAX; } int DelegateExp::inlineCost(InlineCostState *ics) { + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. return COST_MAX; } @@ -229,6 +243,8 @@ return td->objects->dim; #endif } + // This breaks on LDC too, since nested static variables have internal + // linkage and thus can't be referenced from other objects. if (!ics->hdrscan && vd->isDataseg()) return COST_MAX; cost += 1; @@ -246,6 +262,8 @@ } // These can contain functions, which when copied, get output twice. + // These break on LDC too, since nested static variables and functions have + // internal linkage and thus can't be referenced from other objects. if (declaration->isStructDeclaration() || declaration->isClassDeclaration() || declaration->isFuncDeclaration() || @@ -1269,6 +1287,10 @@ if (type) { assert(type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)(type); +#if IN_LLVM + // LDC: Only extern(C) varargs count. + if (tf->linkage != LINKd) +#endif if (tf->varargs == 1) // no variadic parameter lists goto Lno; @@ -1280,12 +1302,15 @@ !hdrscan) goto Lno; } +#if !IN_LLVM + // LDC: Only extern(C) varargs count, and ctors use extern(D). else { CtorDeclaration *ctor = isCtorDeclaration(); if (ctor && ctor->varargs == 1) goto Lno; } +#endif if ( !fbody || @@ -1299,17 +1324,20 @@ #endif isSynchronized() || isImportedSymbol() || +#if !IN_LLVM #if DMDV2 closureVars.dim || // no nested references to this frame #else nestedFrameRef || // no nested references to this frame #endif +#endif // !IN_LLVM (isVirtual() && !isFinal()) )) { goto Lno; } +#if !IN_LLVM /* If any parameters are Tsarray's (which are passed by reference) * or out parameters (also passed by reference), don't do inlining. */ @@ -1322,6 +1350,7 @@ goto Lno; } } +#endif memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; @@ -1334,8 +1363,10 @@ if (cost >= COST_MAX) goto Lno; +#if !IN_LLVM if (!hdrscan) // Don't scan recursively for header content scan inlineScan(); +#endif Lyes: if (!hdrscan) // Don't modify inlineStatus for header content scan diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/mars.h --- a/dmd/mars.h Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/mars.h Sun Jun 07 16:00:13 2009 +0200 @@ -237,6 +237,7 @@ bool llvmAnnotate; bool useInlineAsm; bool verbose_cg; + bool useAvailableExternally; // target stuff const char* llvmArch; diff -r e0f03e11cdf8 -r d9c5f5a43403 dmd/struct.c --- a/dmd/struct.c Sun Jun 07 15:07:29 2009 +0200 +++ b/dmd/struct.c Sun Jun 07 16:00:13 2009 +0200 @@ -52,6 +52,10 @@ ctor = NULL; defaultCtor = NULL; #endif + +#if IN_LLVM + availableExternally = true; // assume this unless proven otherwise +#endif } enum PROT AggregateDeclaration::prot() @@ -81,6 +85,10 @@ void AggregateDeclaration::semantic3(Scope *sc) { int i; + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); if (members) { diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/classes.cpp --- a/gen/classes.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/classes.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -491,7 +491,9 @@ { Logger::cout() << "src2: " << *src << '\n'; Logger::cout() << "index: " << field->index << '\n'; +#if 0 Logger::cout() << "srctype: " << *src->getType() << '\n'; +#endif } #endif LLValue* val = DtoGEPi(src, 0, field->index); diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/enums.h --- a/gen/enums.h Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/enums.h Sun Jun 07 16:00:13 2009 +0200 @@ -9,6 +9,5 @@ LLVMva_copy, LLVMva_end, LLVMva_arg, - LLVMldc, LLVMinline_asm }; diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/llvmhelpers.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -1328,6 +1328,48 @@ if (fd->isArrayOp) return true; + + if (global.params.useAvailableExternally && fd->availableExternally) { + // Emit extra functions if we're inlining. + // These will get available_externally linkage, + // so they shouldn't end up in object code. + + assert(fd->type->ty == Tfunction); + TypeFunction* tf = (TypeFunction*) fd->type; + // * If we define extra static constructors, static destructors + // and unittests they'll get registered to run, and we won't + // be calling them directly anyway. + // * If it's a large function, don't emit it unnecessarily. + // Use DMD's canInline() to determine whether it's large. + // inlineCost() members have been changed to pay less attention + // to DMDs limitations, but still have some issues. The most glaring + // offenders are any kind of control flow statements other than + // 'if' and 'return'. + if ( !fd->isStaticCtorDeclaration() + && !fd->isStaticDtorDeclaration() + && !fd->isUnitTestDeclaration() + && fd->canInline(true)) + { + return true; + } + + // This was only semantic'ed for inlining checks. + // We won't be inlining this, so we only need to emit a declaration. + return false; + } + } + + // Inlining checks may create some variable and class declarations + // we don't need to emit. + if (global.params.useAvailableExternally) + { + if (VarDeclaration* vd = s->isVarDeclaration()) + if (vd->availableExternally) + return false; + + if (ClassDeclaration* cd = s->isClassDeclaration()) + if (cd->availableExternally) + return false; } TemplateInstance* tinst = DtoIsTemplateInstance(s); diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/main.cpp --- a/gen/main.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/main.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -35,6 +35,7 @@ #include "gen/logger.h" #include "gen/linker.h" #include "gen/irstate.h" +#include "gen/optimizer.h" #include "gen/toobj.h" #include "gen/metadata.h" #include "gen/passes/Passes.h" @@ -811,6 +812,17 @@ * not be found at link time. */ if (!global.params.useArrayBounds && !global.params.useAssert) +#elif LLVM_REV >= 68940 + // This doesn't play nice with debug info at the moment + if (!global.params.symdebug && willInline()) + { + global.params.useAvailableExternally = true; + Logger::println("Running some extra semantic3's for inlining purposes"); +#else + // IN_LLVM, but available_externally not available yet. + if (false) + { +#endif { // Do pass 3 semantic analysis on all imported modules, // since otherwise functions in them cannot be inlined @@ -825,6 +837,7 @@ fatal(); } +#if !IN_LLVM for (int i = 0; i < modules.dim; i++) { m = (Module *)modules.data[i]; @@ -832,10 +845,10 @@ printf("inline scan %s\n", m->toChars()); m->inlineScan(); } +#endif } if (global.errors) fatal(); -#endif // write module dependencies to file if requested if (global.params.moduleDepsFile != NULL) diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/optimizer.cpp --- a/gen/optimizer.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/optimizer.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -12,6 +12,7 @@ #include "llvm/Support/PassNameParser.h" #include "root.h" // error() +#include // strcmp(); using namespace llvm; @@ -78,6 +79,19 @@ || (enableInlining == cl::BOU_UNSET && optimizeLevel >= 3); } +// Determine whether the inliner will be run. +bool willInline() { + if (doInline()) + return true; + // It may also have been specified explicitly on the command line as an explicit pass + typedef cl::list PL; + for (PL::iterator I = passList.begin(), E = passList.end(); I != E; ++I) { + if (!std::strcmp((*I)->getPassArgument(), "inline")) + return true; + } + return false; +} + // Some extra accessors for the linker: (llvm-ld version only, currently unused?) int optLevel() { return optimizeLevel; @@ -108,7 +122,6 @@ else addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createGlobalOptimizerPass()); - addPass(pm, createGlobalDCEPass()); } // -O2 @@ -208,6 +221,10 @@ addPass(pm, createConstantMergePass()); } + if (optimizeLevel >= 1) { + addPass(pm, createGlobalDCEPass()); + } + // level -O4 and -O5 are linktime optimizations } diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/optimizer.h --- a/gen/optimizer.h Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/optimizer.h Sun Jun 07 16:00:13 2009 +0200 @@ -5,7 +5,10 @@ bool ldc_optimize_module(llvm::Module* m); +// Determines whether the inliner will run in the -O list of passes bool doInline(); +// Determines whether the inliner will be run at all. +bool willInline(); int optLevel(); diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/tollvm.cpp --- a/gen/tollvm.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/tollvm.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -241,6 +241,13 @@ // global variable if (VarDeclaration* vd = sym->isVarDeclaration()) { + if (mustDefineSymbol(vd)) + Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars()); +#if LLVM_REV >= 68940 + // generated by inlining semantics run + if (vd->availableExternally && mustDefineSymbol(sym)) + return llvm::GlobalValue::AvailableExternallyLinkage; +#endif // template if (needsTemplateLinkage(sym)) return TEMPLATE_LINKAGE_TYPE; @@ -248,15 +255,22 @@ // function else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { + if (mustDefineSymbol(fdecl)) + Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); assert(fdecl->type->ty == Tfunction); TypeFunction* ft = (TypeFunction*)fdecl->type; + // intrinsics are always external + if (fdecl->llvmInternal == LLVMintrinsic) + return llvm::GlobalValue::ExternalLinkage; +#if LLVM_REV >= 68940 + // generated by inlining semantics run + if (fdecl->availableExternally && mustDefineSymbol(sym)) + return llvm::GlobalValue::AvailableExternallyLinkage; +#endif // array operations are always template linkage if (fdecl->isArrayOp) return TEMPLATE_LINKAGE_TYPE; - // intrinsics are always external - if (fdecl->llvmInternal == LLVMintrinsic) - return llvm::GlobalValue::ExternalLinkage; // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external @@ -269,6 +283,13 @@ // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { + if (mustDefineSymbol(cd)) + Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars()); +#if LLVM_REV >= 68940 + // generated by inlining semantics run + if (cd->availableExternally && mustDefineSymbol(sym)) + return llvm::GlobalValue::AvailableExternallyLinkage; +#endif // template if (needsTemplateLinkage(cd)) return TEMPLATE_LINKAGE_TYPE; @@ -278,8 +299,8 @@ assert(0 && "not global/function"); } - // The following breaks for nested naked functions, so check for that. - bool skipNestedCheck = false; + // The following breaks for nested naked functions and other declarations, so check for that. + bool skipNestedCheck = !mustDefineSymbol(sym); if (FuncDeclaration* fd = sym->isFuncDeclaration()) skipNestedCheck = (fd->naked != 0); @@ -306,16 +327,36 @@ return llvm::GlobalValue::ExternalLinkage; } +static bool isAvailableExternally(Dsymbol* sym) +{ + if (VarDeclaration* vd = sym->isVarDeclaration()) + return vd->availableExternally; + if (FuncDeclaration* fd = sym->isFuncDeclaration()) + return fd->availableExternally; + if (AggregateDeclaration* ad = sym->isAggregateDeclaration()) + return ad->availableExternally; + return false; +} + llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym) { - if (needsTemplateLinkage(sym)) + if (needsTemplateLinkage(sym)) { +#if LLVM_REV >= 68940 + if (isAvailableExternally(sym) && mustDefineSymbol(sym)) + return llvm::GlobalValue::AvailableExternallyLinkage; +#endif return TEMPLATE_LINKAGE_TYPE; + } else return llvm::GlobalValue::InternalLinkage; } llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym) { +#if LLVM_REV >= 68940 + if (isAvailableExternally(sym) && mustDefineSymbol(sym)) + return llvm::GlobalValue::AvailableExternallyLinkage; +#endif if (needsTemplateLinkage(sym)) return TEMPLATE_LINKAGE_TYPE; else diff -r e0f03e11cdf8 -r d9c5f5a43403 gen/typinf.cpp --- a/gen/typinf.cpp Sun Jun 07 15:07:29 2009 +0200 +++ b/gen/typinf.cpp Sun Jun 07 16:00:13 2009 +0200 @@ -42,6 +42,7 @@ #include "gen/linkage.h" #include "gen/metadata.h" #include "gen/rttibuilder.h" +#include "gen/llvm-version.h" #include "ir/irvar.h" #include "ir/irtype.h"