예제 #1
0
파일: toctype.c 프로젝트: rainers/dmd
type *TypeClass::toCtype()
{
    //printf("TypeClass::toCtype() %s\n", toChars());
    if (ctype)
        return ctype;

    type *t = type_struct_class(sym->toPrettyChars(), sym->alignsize, sym->structsize,
            NULL,
            NULL,
            false,
            true,
            true);

    ctype = type_pointer(t);

    /* Add in fields of the class
     * (after setting ctype to avoid infinite recursion)
     */
    if (global.params.symdebug)
        for (size_t i = 0; i < sym->fields.dim; i++)
        {   VarDeclaration *v = sym->fields[i];

            symbol_struct_addField(t->Ttag, v->ident->toChars(), v->type->toCtype(), v->offset);
        }

    if (0 && global.params.symdebug)
        sym->toDebug();

    return ctype;
}
예제 #2
0
파일: tocsym.c 프로젝트: andralex/dmd
Classsym *fake_classsym(Identifier *id)
{
    TYPE *t = type_struct_class(id->toChars(),8,0,
        NULL,NULL,
        false, false, true);

    t->Ttag->Sstruct->Sflags = STRglobal;
    t->Tflags |= TFsizeunknown | TFforward;
    assert(t->Tmangle == 0);
    t->Tmangle = mTYman_d;
    return t->Ttag;
}
예제 #3
0
파일: toctype.c 프로젝트: CyberShadow/dmd
    void visit(TypeClass *t)
    {
        //printf("TypeClass::toCtype() %s\n", toChars());
        type *tc = type_struct_class(t->sym->toPrettyChars(true), t->sym->alignsize, t->sym->structsize,
                NULL,
                NULL,
                false,
                true,
                true);

        t->ctype = type_pointer(tc);

        /* Add in fields of the class
         * (after setting ctype to avoid infinite recursion)
         */
        if (global.params.symdebug)
        {
            for (size_t i = 0; i < t->sym->fields.dim; i++)
            {
                VarDeclaration *v = t->sym->fields[i];
                symbol_struct_addField(tc->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset);
            }
        }
    }
예제 #4
0
/*************************************
 * Closures are implemented by taking the local variables that
 * need to survive the scope of the function, and copying them
 * into a gc allocated chuck of memory. That chunk, called the
 * closure here, is inserted into the linked list of stack
 * frames instead of the usual stack frame.
 *
 * buildClosure() inserts code just after the function prolog
 * is complete. It allocates memory for the closure, allocates
 * a local variable (sclosure) to point to it, inserts into it
 * the link to the enclosing frame, and copies into it the parameters
 * that are referred to in nested functions.
 * In VarExp::toElem and SymOffExp::toElem, when referring to a
 * variable that is in a closure, takes the offset from sclosure rather
 * than from the frame pointer.
 *
 * getEthis() and NewExp::toElem need to use sclosure, if set, rather
 * than the current frame pointer.
 */
void buildClosure(FuncDeclaration *fd, IRState *irs)
{
    if (fd->needsClosure())
    {
        // Generate closure on the heap
        // BUG: doesn't capture variadic arguments passed to this function

        /* BUG: doesn't handle destructors for the local variables.
         * The way to do it is to make the closure variables the fields
         * of a class object:
         *    class Closure {
         *        vtbl[]
         *        monitor
         *        ptr to destructor
         *        sthis
         *        ... closure variables ...
         *        ~this() { call destructor }
         *    }
         */
        //printf("FuncDeclaration::buildClosure() %s\n", toChars());

        /* Generate type name for closure struct */
        const char *name1 = "CLOSURE.";
        const char *name2 = fd->toPrettyChars();
        size_t namesize = strlen(name1)+strlen(name2)+1;
        char *closname = (char *) calloc(namesize, sizeof(char));
        strcat(strcat(closname, name1), name2);

        /* Build type for closure */
        type *Closstru = type_struct_class(closname, Target::ptrsize, 0, NULL, NULL, false, false, true);
        symbol_struct_addField(Closstru->Ttag, "__chain", Type_toCtype(Type::tvoidptr), 0);

        Symbol *sclosure;
        sclosure = symbol_name("__closptr", SCauto, type_pointer(Closstru));
        sclosure->Sflags |= SFLtrue | SFLfree;
        symbol_add(sclosure);
        irs->sclosure = sclosure;

        unsigned offset = Target::ptrsize;      // leave room for previous sthis
        for (size_t i = 0; i < fd->closureVars.dim; i++)
        {
            VarDeclaration *v = fd->closureVars[i];
            //printf("closure var %s\n", v->toChars());
            assert(v->isVarDeclaration());

            if (v->needsAutoDtor())
            {
                /* Because the value needs to survive the end of the scope!
                 */
                v->error("has scoped destruction, cannot build closure");
            }
            if (v->isargptr)
            {
                /* See Bugzilla 2479
                 * This is actually a bug, but better to produce a nice
                 * message at compile time rather than memory corruption at runtime
                 */
                v->error("cannot reference variadic arguments from closure");
            }
            /* Align and allocate space for v in the closure
             * just like AggregateDeclaration::addField() does.
             */
            unsigned memsize;
            unsigned memalignsize;
            structalign_t xalign;
            if (v->storage_class & STClazy)
            {
                /* Lazy variables are really delegates,
                 * so give same answers that TypeDelegate would
                 */
                memsize = Target::ptrsize * 2;
                memalignsize = memsize;
                xalign = STRUCTALIGN_DEFAULT;
            }
            else if (ISWIN64REF(v))
            {
                memsize = v->type->size();
                memalignsize = v->type->alignsize();
                xalign = v->alignment;
            }
            else if (ISREF(v, NULL))
            {
                // reference parameters are just pointers
                memsize = Target::ptrsize;
                memalignsize = memsize;
                xalign = STRUCTALIGN_DEFAULT;
            }
            else
            {
                memsize = v->type->size();
                memalignsize = v->type->alignsize();
                xalign = v->alignment;
            }
            AggregateDeclaration::alignmember(xalign, memalignsize, &offset);
            v->offset = offset;
            offset += memsize;

            /* Set Sscope to closure */
            Symbol *vsym = toSymbol(v);
            assert(vsym->Sscope == NULL);
            vsym->Sscope = sclosure;

            /* Add variable as closure type member */
            symbol_struct_addField(Closstru->Ttag, vsym->Sident, vsym->Stype, v->offset);
            //printf("closure field %s: memalignsize: %i, offset: %i\n", vsym->Sident, memalignsize, v->offset);

            /* Can't do nrvo if the variable is put in a closure, since
             * what the shidden points to may no longer exist.
             */
            if (fd->nrvo_can && fd->nrvo_var == v)
            {
                fd->nrvo_can = 0;
            }
        }
        // offset is now the size of the closure
        Closstru->Ttag->Sstruct->Sstructsize = offset;

        // Allocate memory for the closure
        elem *e = el_long(TYsize_t, offset);
        e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM_ALLOCMEMORY)), e);
        toTraceGC(irs, e, &fd->loc);

        // Assign block of memory to sclosure
        //    sclosure = allocmemory(sz);
        e = el_bin(OPeq, TYvoid, el_var(sclosure), e);

        // Set the first element to sthis
        //    *(sclosure + 0) = sthis;
        elem *ethis;
        if (irs->sthis)
            ethis = el_var(irs->sthis);
        else
            ethis = el_long(TYnptr, 0);
        elem *ex = el_una(OPind, TYnptr, el_var(sclosure));
        ex = el_bin(OPeq, TYnptr, ex, ethis);
        e = el_combine(e, ex);

        // Copy function parameters into closure
        for (size_t i = 0; i < fd->closureVars.dim; i++)
        {
            VarDeclaration *v = fd->closureVars[i];

            if (!v->isParameter())
                continue;
            tym_t tym = totym(v->type);
            bool win64ref = ISWIN64REF(v);
            if (win64ref)
            {
                if (v->storage_class & STClazy)
                    tym = TYdelegate;
            }
            else if (ISREF(v, NULL))
                tym = TYnptr;   // reference parameters are just pointers
            else if (v->storage_class & STClazy)
                tym = TYdelegate;
            ex = el_bin(OPadd, TYnptr, el_var(sclosure), el_long(TYsize_t, v->offset));
            ex = el_una(OPind, tym, ex);
            elem *ev = el_var(toSymbol(v));
            if (win64ref)
            {
                ev->Ety = TYnptr;
                ev = el_una(OPind, tym, ev);
                if (tybasic(ev->Ety) == TYstruct || tybasic(ev->Ety) == TYarray)
                    ev->ET = Type_toCtype(v->type);
            }
            if (tybasic(ex->Ety) == TYstruct || tybasic(ex->Ety) == TYarray)
            {
                ::type *t = Type_toCtype(v->type);
                ex->ET = t;
                ex = el_bin(OPstreq, tym, ex, ev);
                ex->ET = t;
            }
            else
                ex = el_bin(OPeq, tym, ex, ev);

            e = el_combine(e, ex);
        }

        block_appendexp(irs->blx->curblock, e);
    }
}
예제 #5
0
파일: toctype.c 프로젝트: CyberShadow/dmd
    void visit(TypeStruct *t)
    {
        //printf("TypeStruct::toCtype() '%s'\n", t->sym->toChars());
        Type *tm = t->mutableOf();
        if (tm->ctype)
        {
            t->ctype = type_alloc(tybasic(tm->ctype->Tty));
            t->ctype->Tcount++;
            if (t->ctype->Tty == TYstruct)
            {
                Symbol *s = tm->ctype->Ttag;
                t->ctype->Ttag = (Classsym *)s;            // structure tag name
            }
            // Add modifiers
            switch (t->mod)
            {
                case 0:
                    assert(0);
                    break;
                case MODconst:
                case MODwild:
                case MODwildconst:
                    t->ctype->Tty |= mTYconst;
                    break;
                case MODshared:
                    t->ctype->Tty |= mTYshared;
                    break;
                case MODshared | MODconst:
                case MODshared | MODwild:
                case MODshared | MODwildconst:
                    t->ctype->Tty |= mTYshared | mTYconst;
                    break;
                case MODimmutable:
                    t->ctype->Tty |= mTYimmutable;
                    break;
                default:
                    assert(0);
            }
        }
        else
        {
            StructDeclaration *sym = t->sym;
            if (sym->ident == Id::__c_long_double)
            {
                t->ctype = type_fake(TYdouble);
                t->ctype->Tcount++;
                return;
            }
            t->ctype = type_struct_class(sym->toPrettyChars(true), sym->alignsize, sym->structsize,
                    sym->arg1type ? Type_toCtype(sym->arg1type) : NULL,
                    sym->arg2type ? Type_toCtype(sym->arg2type) : NULL,
                    sym->isUnionDeclaration() != 0,
                    false,
                    sym->isPOD() != 0);

            tm->ctype = t->ctype;

            /* Add in fields of the struct
             * (after setting ctype to avoid infinite recursion)
             */
            if (global.params.symdebug)
            {
                for (size_t i = 0; i < sym->fields.dim; i++)
                {
                    VarDeclaration *v = sym->fields[i];
                    symbol_struct_addField(t->ctype->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset);
                }
            }
        }

        //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags);
    }
예제 #6
0
파일: toctype.c 프로젝트: rainers/dmd
type *TypeStruct::toCtype()
{
    if (ctype)
        return ctype;

    //printf("TypeStruct::toCtype() '%s'\n", sym->toChars());
    Type *tm = mutableOf();
    if (tm->ctype)
    {
        Symbol *s = tm->ctype->Ttag;
        type *t = type_alloc(TYstruct);
        t->Ttag = (Classsym *)s;            // structure tag name
        t->Tcount++;
        // Add modifiers
        switch (mod)
        {
            case 0:
                assert(0);
                break;
            case MODconst:
            case MODwild:
                t->Tty |= mTYconst;
                break;
            case MODimmutable:
                t->Tty |= mTYimmutable;
                break;
            case MODshared:
                t->Tty |= mTYshared;
                break;
            case MODshared | MODwild:
            case MODshared | MODconst:
                t->Tty |= mTYshared | mTYconst;
                break;
            default:
                assert(0);
        }
        ctype = t;
    }
    else
    {
        type *t = type_struct_class(sym->toPrettyChars(), sym->alignsize, sym->structsize,
                sym->arg1type ? sym->arg1type->toCtype() : NULL,
                sym->arg2type ? sym->arg2type->toCtype() : NULL,
                sym->isUnionDeclaration() != 0,
                false,
                sym->isPOD() != 0);

        tm->ctype = t;
        ctype = t;

        /* Add in fields of the struct
         * (after setting ctype to avoid infinite recursion)
         */
        if (global.params.symdebug)
            for (size_t i = 0; i < sym->fields.dim; i++)
            {   VarDeclaration *v = sym->fields[i];

                symbol_struct_addField(t->Ttag, v->ident->toChars(), v->type->toCtype(), v->offset);
            }
    }

    if (0 && global.params.symdebug)
        sym->toDebug();
    //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags);
    return ctype;
}
예제 #7
0
void FuncDeclaration_toObjFile(FuncDeclaration *fd, bool multiobj)
{
    ClassDeclaration *cd = fd->parent->isClassDeclaration();
    //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", fd, fd->parent->toChars(), fd->toChars());

    //if (type) printf("type = %s\n", type->toChars());
#if 0
    //printf("line = %d\n", getWhere() / LINEINC);
    EEcontext *ee = env->getEEcontext();
    if (ee->EEcompile == 2)
    {
        if (ee->EElinnum < (getWhere() / LINEINC) ||
            ee->EElinnum > (endwhere / LINEINC)
           )
            return;             // don't compile this function
        ee->EEfunc = toSymbol(this);
    }
#endif

    if (fd->semanticRun >= PASSobj) // if toObjFile() already run
        return;

    if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next == NULL)
        return;

    // If errors occurred compiling it, such as bugzilla 6118
    if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next->ty == Terror)
        return;

    if (fd->semantic3Errors)
        return;

    if (global.errors)
        return;

    if (!fd->fbody)
        return;

    UnitTestDeclaration *ud = fd->isUnitTestDeclaration();
    if (ud && !global.params.useUnitTests)
        return;

    if (multiobj && !fd->isStaticDtorDeclaration() && !fd->isStaticCtorDeclaration())
    {
        obj_append(fd);
        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.
         */
        fd->error("errors compiling the function");
        return;
    }
    assert(fd->semanticRun == PASSsemantic3done);
    assert(fd->ident != Id::empty);

    for (FuncDeclaration *fd2 = fd; fd2; )
    {
        if (fd2->inNonRoot())
            return;
        if (fd2->isNested())
            fd2 = fd2->toParent2()->isFuncDeclaration();
        else
            break;
    }

    if (UnitTestDeclaration *udp = needsDeferredNested(fd))
    {
        /* Can't do unittest's out of order, they are order dependent in that their
         * execution is done in lexical order.
         */
        udp->deferredNested.push(fd);
        //printf("%s @[%s]\n\t--> pushed to unittest @[%s]\n",
        //    fd->toPrettyChars(), fd->loc.toChars(), udp->loc.toChars());
        return;
    }

    if (fd->isArrayOp && isDruntimeArrayOp(fd->ident))
    {
        // Implementation is in druntime
        return;
    }

    // start code generation
    fd->semanticRun = PASSobj;

    if (global.params.verbose)
        fprintf(global.stdmsg, "function  %s\n", fd->toPrettyChars());

    Symbol *s = toSymbol(fd);
    func_t *f = s->Sfunc;

    // tunnel type of "this" to debug info generation
    if (AggregateDeclaration* ad = fd->parent->isAggregateDeclaration())
    {
        ::type* t = Type_toCtype(ad->getType());
        if (cd)
            t = t->Tnext; // skip reference
        f->Fclass = (Classsym *)t;
    }

    /* This is done so that the 'this' pointer on the stack is the same
     * distance away from the function parameters, so that an overriding
     * function can call the nested fdensure or fdrequire of its overridden function
     * and the stack offsets are the same.
     */
    if (fd->isVirtual() && (fd->fensure || fd->frequire))
        f->Fflags3 |= Ffakeeh;

#if TARGET_OSX
    s->Sclass = SCcomdat;
#else
    s->Sclass = SCglobal;
#endif
    for (Dsymbol *p = fd->parent; p; p = p->parent)
    {
        if (p->isTemplateInstance())
        {
            s->Sclass = SCcomdat;
            break;
        }
    }

    /* Vector operations should be comdat's
     */
    if (fd->isArrayOp)
        s->Sclass = SCcomdat;

    if (fd->inlinedNestedCallees)
    {
        /* Bugzilla 15333: If fd contains inlined expressions that come from
         * nested function bodies, the enclosing of the functions must be
         * generated first, in order to calculate correct frame pointer offset.
         */
        for (size_t i = 0; i < fd->inlinedNestedCallees->dim; i++)
        {
            FuncDeclaration *f = (*fd->inlinedNestedCallees)[i];
            FuncDeclaration *fp = f->toParent2()->isFuncDeclaration();;
            if (fp && fp->semanticRun < PASSobj)
            {
                toObjFile(fp, multiobj);
            }
        }
    }

    if (fd->isNested())
    {
        //if (!(config.flags3 & CFG3pic))
        //    s->Sclass = SCstatic;
        f->Fflags3 |= Fnested;

        /* The enclosing function must have its code generated first,
         * in order to calculate correct frame pointer offset.
         */
        FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration();
        if (fdp && fdp->semanticRun < PASSobj)
        {
            toObjFile(fdp, multiobj);
        }
    }
    else
    {
        const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;

        // Pull in RTL startup code (but only once)
        if (fd->isMain() && onlyOneMain(fd->loc))
        {
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
            objmod->external_def("_main");
            objmod->ehsections();   // initialize exception handling sections
#endif
            if (global.params.mscoff)
            {
                objmod->external_def("main");
                objmod->ehsections();   // initialize exception handling sections
            }
            else if (config.exe == EX_WIN32)
            {
                objmod->external_def("_main");
                objmod->external_def("__acrtused_con");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
        else if (strcmp(s->Sident, "main") == 0 && fd->linkage == LINKc)
        {
            if (global.params.mscoff)
            {
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
            }
            else if (config.exe == EX_WIN32)
            {
                objmod->external_def("__acrtused_con");        // bring in C startup code
                objmod->includelib("snn.lib");          // bring in C runtime library
            }
            s->Sclass = SCglobal;
        }
#if TARGET_WINDOS
        else if (fd->isWinMain() && onlyOneMain(fd->loc))
        {
            if (global.params.mscoff)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }

        // Pull in RTL startup code
        else if (fd->isDllMain() && onlyOneMain(fd->loc))
        {
            if (global.params.mscoff)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused_dll");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
#endif
    }

    symtab_t *symtabsave = cstate.CSpsymtab;
    cstate.CSpsymtab = &f->Flocsym;

    // Find module m for this function
    Module *m = NULL;
    for (Dsymbol *p = fd->parent; p; p = p->parent)
    {
        m = p->isModule();
        if (m)
            break;
    }

    IRState irs(m, fd);
    Dsymbols deferToObj;                   // write these to OBJ file later
    irs.deferToObj = &deferToObj;
    void *labels = NULL;
    irs.labels = &labels;

    symbol *shidden = NULL;
    Symbol *sthis = NULL;
    tym_t tyf = tybasic(s->Stype->Tty);
    //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
    int reverse = tyrevfunc(s->Stype->Tty);

    assert(fd->type->ty == Tfunction);
    TypeFunction *tf = (TypeFunction *)fd->type;
    RET retmethod = retStyle(tf);
    if (retmethod == RETstack)
    {
        // If function returns a struct, put a pointer to that
        // as the first argument
        ::type *thidden = Type_toCtype(tf->next->pointerTo());
        char hiddenparam[5+4+1];
        static int hiddenparami;    // how many we've generated so far

        sprintf(hiddenparam,"__HID%d",++hiddenparami);
        shidden = symbol_name(hiddenparam,SCparameter,thidden);
        shidden->Sflags |= SFLtrue | SFLfree;
        if (fd->nrvo_can && fd->nrvo_var && fd->nrvo_var->nestedrefs.dim)
            type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile);
        irs.shidden = shidden;
        fd->shidden = shidden;
    }
    else
    {
        // Register return style cannot make nrvo.
        // Auto functions keep the nrvo_can flag up to here,
        // so we should eliminate it before entering backend.
        fd->nrvo_can = 0;
    }

    if (fd->vthis)
    {
        assert(!fd->vthis->csym);
        sthis = toSymbol(fd->vthis);
        irs.sthis = sthis;
        if (!(f->Fflags3 & Fnested))
            f->Fflags3 |= Fmember;
    }

    // Estimate number of parameters, pi
    size_t pi = (fd->v_arguments != NULL);
    if (fd->parameters)
        pi += fd->parameters->dim;

    // Create a temporary buffer, params[], to hold function parameters
    Symbol *paramsbuf[10];
    Symbol **params = paramsbuf;    // allocate on stack if possible
    if (pi + 2 > 10)                // allow extra 2 for sthis and shidden
    {
        params = (Symbol **)malloc((pi + 2) * sizeof(Symbol *));
        assert(params);
    }

    // Get the actual number of parameters, pi, and fill in the params[]
    pi = 0;
    if (fd->v_arguments)
    {
        params[pi] = toSymbol(fd->v_arguments);
        pi += 1;
    }
    if (fd->parameters)
    {
        for (size_t i = 0; i < fd->parameters->dim; i++)
        {
            VarDeclaration *v = (*fd->parameters)[i];
            //printf("param[%d] = %p, %s\n", i, v, v->toChars());
            assert(!v->csym);
            params[pi + i] = toSymbol(v);
        }
        pi += fd->parameters->dim;
    }

    if (reverse)
    {
        // Reverse params[] entries
        for (size_t i = 0; i < pi/2; i++)
        {
            Symbol *sptmp = params[i];
            params[i] = params[pi - 1 - i];
            params[pi - 1 - i] = sptmp;
        }
    }

    if (shidden)
    {
#if 0
        // shidden becomes last parameter
        params[pi] = shidden;
#else
        // shidden becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = shidden;
#endif
        pi++;
    }


    if (sthis)
    {
#if 0
        // sthis becomes last parameter
        params[pi] = sthis;
#else
        // sthis becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = sthis;
#endif
        pi++;
    }

    if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
         fd->linkage != LINKd && shidden && sthis)
    {
        /* swap shidden and sthis
         */
        Symbol *sp = params[0];
        params[0] = params[1];
        params[1] = sp;
    }

    for (size_t i = 0; i < pi; i++)
    {
        Symbol *sp = params[i];
        sp->Sclass = SCparameter;
        sp->Sflags &= ~SFLspill;
        sp->Sfl = FLpara;
        symbol_add(sp);
    }

    // Determine register assignments
    if (pi)
    {
        FuncParamRegs fpr(tyf);

        for (size_t i = 0; i < pi; i++)
        {
            Symbol *sp = params[i];
            if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2))
            {
                sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar;
                sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast;
            }
        }
    }

    // Done with params
    if (params != paramsbuf)
        free(params);
    params = NULL;

    if (fd->fbody)
    {
        localgot = NULL;

        Statement *sbody = fd->fbody;

        Blockx bx;
        memset(&bx,0,sizeof(bx));
        bx.startblock = block_calloc();
        bx.curblock = bx.startblock;
        bx.funcsym = s;
        bx.scope_index = -1;
        bx.classdec = cd;
        bx.member = fd;
        bx.module = fd->getModule();
        irs.blx = &bx;

        // Initialize argptr
        if (fd->v_argptr)
        {
            // Declare va_argsave
            if (global.params.is64bit &&
                !global.params.isWindows)
            {
                type *t = type_struct_class("__va_argsave_t", 16, 8 * 6 + 8 * 16 + 8 * 3, NULL, NULL, false, false, true);
                // The backend will pick this up by name
                Symbol *s = symbol_name("__va_argsave", SCauto, t);
                s->Stype->Tty |= mTYvolatile;
                symbol_add(s);
            }

            Symbol *s = toSymbol(fd->v_argptr);
            symbol_add(s);
            elem *e = el_una(OPva_start, TYnptr, el_ptr(s));
            block_appendexp(irs.blx->curblock, e);
        }

        /* Doing this in semantic3() caused all kinds of problems:
         * 1. couldn't reliably get the final mangling of the function name due to fwd refs
         * 2. impact on function inlining
         * 3. what to do when writing out .di files, or other pretty printing
         */
        if (global.params.trace && !fd->isCMain())
        {
            /* The profiler requires TLS, and TLS may not be set up yet when C main()
             * gets control (i.e. OSX), leading to a crash.
             */
            /* Wrap the entire function body in:
             *   trace_pro("funcname");
             *   try
             *     body;
             *   finally
             *     _c_trace_epi();
             */
            StringExp *se = StringExp::create(Loc(), s->Sident);
            se->type = Type::tstring;
            se->type = se->type->semantic(Loc(), NULL);
            Expressions *exps = Expressions_create();
            exps->push(se);
            FuncDeclaration *fdpro = FuncDeclaration::genCfunc(NULL, Type::tvoid, "trace_pro");
            Expression *ec = VarExp::create(Loc(), fdpro);
            Expression *e = CallExp::create(Loc(), ec, exps);
            e->type = Type::tvoid;
            Statement *sp = ExpStatement::create(fd->loc, e);

            FuncDeclaration *fdepi = FuncDeclaration::genCfunc(NULL, Type::tvoid, "_c_trace_epi");
            ec = VarExp::create(Loc(), fdepi);
            e = CallExp::create(Loc(), ec);
            e->type = Type::tvoid;
            Statement *sf = ExpStatement::create(fd->loc, e);

            Statement *stf;
            if (sbody->blockExit(fd, false) == BEfallthru)
                stf = CompoundStatement::create(Loc(), sbody, sf);
            else
                stf = TryFinallyStatement::create(Loc(), sbody, sf);
            sbody = CompoundStatement::create(Loc(), sp, stf);
        }

        if (fd->interfaceVirtual)
        {
            // Adjust the 'this' pointer instead of using a thunk
            assert(irs.sthis);
            elem *ethis = el_var(irs.sthis);
            elem *e = el_bin(OPminass, TYnptr, ethis, el_long(TYsize_t, fd->interfaceVirtual->offset));
            block_appendexp(irs.blx->curblock, e);
        }

        buildClosure(fd, &irs);

        if (config.ehmethod == EH_WIN32 && fd->isSynchronized() && cd &&
            !fd->isStatic() && !sbody->usesEH() && !global.params.trace)
        {
            /* The "jmonitor" hack uses an optimized exception handling frame
             * which is a little shorter than the more general EH frame.
             */
            s->Sfunc->Fflags3 |= Fjmonitor;
        }

        Statement_toIR(sbody, &irs);
        bx.curblock->BC = BCret;

        f->Fstartblock = bx.startblock;
//      einit = el_combine(einit,bx.init);

        if (fd->isCtorDeclaration())
        {
            assert(sthis);
            for (block *b = f->Fstartblock; b; b = b->Bnext)
            {
                if (b->BC == BCret)
                {
                    b->BC = BCretexp;
                    b->Belem = el_combine(b->Belem, el_var(sthis));
                }
            }
        }
        insertFinallyBlockCalls(f->Fstartblock);
    }

    // If static constructor
    if (fd->isSharedStaticCtorDeclaration())        // must come first because it derives from StaticCtorDeclaration
    {
        ssharedctors.push(s);
    }
    else if (fd->isStaticCtorDeclaration())
    {
        sctors.push(s);
    }

    // If static destructor
    if (fd->isSharedStaticDtorDeclaration())        // must come first because it derives from StaticDtorDeclaration
    {
        SharedStaticDtorDeclaration *f = fd->isSharedStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {
            /* Increment destructor's vgate at construction time
             */
            esharedctorgates.push(f);
        }

        sshareddtors.shift(s);
    }
    else if (fd->isStaticDtorDeclaration())
    {
        StaticDtorDeclaration *f = fd->isStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {
            /* Increment destructor's vgate at construction time
             */
            ectorgates.push(f);
        }

        sdtors.shift(s);
    }

    // If unit test
    if (ud)
    {
        stests.push(s);
    }

    if (global.errors)
    {
        // Restore symbol table
        cstate.CSpsymtab = symtabsave;
        return;
    }

    writefunc(s);
    // Restore symbol table
    cstate.CSpsymtab = symtabsave;

    if (fd->isExport())
        objmod->export_symbol(s, Para.offset);

    for (size_t i = 0; i < irs.deferToObj->dim; i++)
    {
        Dsymbol *s = (*irs.deferToObj)[i];
        toObjFile(s, false);
    }

    if (ud)
    {
        for (size_t i = 0; i < ud->deferredNested.dim; i++)
        {
            FuncDeclaration *fd = ud->deferredNested[i];
            toObjFile(fd, false);
        }
    }

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
    // A hack to get a pointer to this function put in the .dtors segment
    if (fd->ident && memcmp(fd->ident->toChars(), "_STD", 4) == 0)
        objmod->staticdtor(s);
#endif
    if (irs.startaddress)
    {
        //printf("Setting start address\n");
        objmod->startaddress(irs.startaddress);
    }
}