Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}