Example #1
0
static void genhelpers(Module *m)
{
    // If module assert
    for (int i = 0; i < 3; i++)
    {
        Symbol *ma;
        unsigned rt;
        unsigned bc;
        switch (i)
        {
            case 0:     ma = toModuleArray(m);    rt = RTLSYM_DARRAY;     bc = BCexit; break;
            case 1:     ma = toModuleAssert(m);   rt = RTLSYM_DASSERT;    bc = BCexit; break;
            case 2:     ma = toModuleUnittest(m); rt = RTLSYM_DUNITTEST;  bc = BCret;  break;
            default:    assert(0);
        }

        if (!ma)
            continue;


        localgot = NULL;

        // Call dassert(filename, line)
        // Get sole parameter, linnum
        Symbol *sp = symbol_calloc("linnum");
        sp->Stype = type_fake(TYint);
        sp->Stype->Tcount++;
        sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar;

        FuncParamRegs fpr(TYjfunc);
        fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2);

        sp->Sflags &= ~SFLspill;
        sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast;
        cstate.CSpsymtab = &ma->Sfunc->Flocsym;
        symbol_add(sp);

        elem *elinnum = el_var(sp);


        elem *efilename = toEfilename(m);
        if (config.exe == EX_WIN64)
            efilename = addressElem(efilename, Type::tstring, true);

        elem *e = el_var(getRtlsym(rt));
        e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename));

        block *b = block_calloc();
        b->BC = bc;
        b->Belem = e;
        ma->Sfunc->Fstartline.Sfilename = m->arg;
        ma->Sfunc->Fstartblock = b;
        ma->Sclass = SCglobal;
        ma->Sfl = 0;
        ma->Sflags |= getRtlsym(rt)->Sflags & SFLexit;
        writefunc(ma);
    }
}
Example #2
0
void genObjFile(Module *m, bool multiobj)
{
    //EEcontext *ee = env->getEEcontext();

    //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, m->toChars());

    if (m->ident == Id::entrypoint)
    {
        bool v = global.params.verbose;
        global.params.verbose = false;

        for (size_t i = 0; i < m->members->dim; i++)
        {
            Dsymbol *member = (*m->members)[i];
            //printf("toObjFile %s %s\n", member->kind(), member->toChars());
            toObjFile(member, global.params.multiobj);
        }

        global.params.verbose = v;
        return;
    }

    lastmname = m->srcfile->toChars();

    objmod->initfile(lastmname, NULL, m->toPrettyChars());

    eictor = NULL;
    ictorlocalgot = NULL;
    sctors.setDim(0);
    ectorgates.setDim(0);
    sdtors.setDim(0);
    ssharedctors.setDim(0);
    esharedctorgates.setDim(0);
    sshareddtors.setDim(0);
    stests.setDim(0);

    if (m->doppelganger)
    {
        /* Generate a reference to the moduleinfo, so the module constructors
         * and destructors get linked in.
         */
        Module *mod = m->aimports[0];
        assert(mod);
        if (mod->sictor || mod->sctor || mod->sdtor || mod->ssharedctor || mod->sshareddtor)
        {
            Symbol *s = toSymbol(mod);
            //objextern(s);
            //if (!s->Sxtrnnum) objextdef(s->Sident);
            if (!s->Sxtrnnum)
            {
                //printf("%s\n", s->Sident);
#if 0 /* This should work, but causes optlink to fail in common/newlib.asm */
                objextdef(s->Sident);
#else
                Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr));
                sref->Sfl = FLdata;
                dtxoff(&sref->Sdt, s, 0, TYnptr);
                outdata(sref);
#endif
            }
        }
    }

    if (global.params.cov)
    {
        /* Create coverage identifier:
         *  private uint[numlines] __coverage;
         */
        m->cov = symbol_calloc("__coverage");
        m->cov->Stype = type_fake(TYint);
        m->cov->Stype->Tmangle = mTYman_c;
        m->cov->Stype->Tcount++;
        m->cov->Sclass = SCstatic;
        m->cov->Sfl = FLdata;
        dtnzeros(&m->cov->Sdt, 4 * m->numlines);
        outdata(m->cov);
        slist_add(m->cov);

        m->covb = (unsigned *)calloc((m->numlines + 32) / 32, sizeof(*m->covb));
    }

    for (size_t i = 0; i < m->members->dim; i++)
    {
        Dsymbol *member = (*m->members)[i];
        //printf("toObjFile %s %s\n", member->kind(), member->toChars());
        toObjFile(member, multiobj);
    }

    if (global.params.cov)
    {
        /* Generate
         *      bit[numlines] __bcoverage;
         */
        Symbol *bcov = symbol_calloc("__bcoverage");
        bcov->Stype = type_fake(TYuint);
        bcov->Stype->Tcount++;
        bcov->Sclass = SCstatic;
        bcov->Sfl = FLdata;
        dtnbytes(&bcov->Sdt, (m->numlines + 32) / 32 * sizeof(*m->covb), (char *)m->covb);
        outdata(bcov);

        free(m->covb);
        m->covb = NULL;

        /* Generate:
         *  _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename);
         * and prepend it to the static constructor.
         */

        /* t will be the type of the functions generated:
         *      extern (C) void func();
         */
        type *t = type_function(TYnfunc, NULL, 0, false, tsvoid);
        t->Tmangle = mTYman_c;

        m->sictor = toSymbolX(m, "__modictor", SCglobal, t, "FZv");
        cstate.CSpsymtab = &m->sictor->Sfunc->Flocsym;
        localgot = ictorlocalgot;

        elem *ecov  = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(m->cov));
        elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(bcov));

        if (config.exe == EX_WIN64)
        {
            ecov  = addressElem(ecov,  Type::tvoid->arrayOf(), false);
            ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false);
        }

        elem *efilename = toEfilename(m);
        if (config.exe == EX_WIN64)
            efilename = addressElem(efilename, Type::tstring, true);

        elem *e = el_params(
                      el_long(TYuchar, global.params.covPercent),
                      ecov,
                      ebcov,
                      efilename,
                      NULL);
        e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e);
        eictor = el_combine(e, eictor);
        ictorlocalgot = localgot;
    }

    // If coverage / static constructor / destructor / unittest calls
    if (eictor || sctors.dim || ectorgates.dim || sdtors.dim ||
        ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim)
    {
        if (eictor)
        {
            localgot = ictorlocalgot;

            block *b = block_calloc();
            b->BC = BCret;
            b->Belem = eictor;
            m->sictor->Sfunc->Fstartline.Sfilename = m->arg;
            m->sictor->Sfunc->Fstartblock = b;
            writefunc(m->sictor);
        }

        m->sctor = callFuncsAndGates(m, &sctors, &ectorgates, "__modctor");
        m->sdtor = callFuncsAndGates(m, &sdtors, NULL, "__moddtor");

        m->ssharedctor = callFuncsAndGates(m, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor");
        m->sshareddtor = callFuncsAndGates(m, &sshareddtors, NULL, "__modshareddtor");
        m->stest = callFuncsAndGates(m, &stests, NULL, "__modtest");

        if (m->doppelganger)
            genModuleInfo(m);
    }

    if (m->doppelganger)
    {
        objmod->termfile();
        return;
    }

    if (global.params.multiobj)
    {
        /* This is necessary because the main .obj for this module is written
         * first, but determining whether marray or massert or munittest are needed is done
         * possibly later in the doppelganger modules.
         * Another way to fix it is do the main one last.
         */
        toModuleAssert(m);
        toModuleUnittest(m);
        toModuleArray(m);
    }

    /* Always generate module info, because of templates and -cov.
     * But module info needs the runtime library, so disable it for betterC.
     */
    if (!global.params.betterC /*|| needModuleInfo()*/)
        genModuleInfo(m);

    genhelpers(m, false);

    objmod->termfile();
}
Example #3
0
File: s2ir.c Project: Faianca/dmd
    void visit(ReturnStatement *s)
    {
        Blockx *blx = irs->blx;
        enum BC bc;

        incUsage(irs, s->loc);
        if (s->exp)
        {
            elem *e;

            FuncDeclaration *func = irs->getFunc();
            assert(func);
            assert(func->type->ty == Tfunction);
            TypeFunction *tf = (TypeFunction *)(func->type);

            RET retmethod = retStyle(tf);
            if (retmethod == RETstack)
            {
                elem *es;

                /* If returning struct literal, write result
                 * directly into return value
                 */
                if (s->exp->op == TOKstructliteral)
                {
                    StructLiteralExp *se = (StructLiteralExp *)s->exp;
                    char save[sizeof(StructLiteralExp)];
                    memcpy(save, (void*)se, sizeof(StructLiteralExp));
                    se->sym = irs->shidden;
                    se->soffset = 0;
                    se->fillHoles = 1;
                    e = toElemDtor(s->exp, irs);
                    memcpy((void*)se, save, sizeof(StructLiteralExp));
                }
                else
                    e = toElemDtor(s->exp, irs);
                assert(e);

                if (s->exp->op == TOKstructliteral ||
                    (func->nrvo_can && func->nrvo_var))
                {
                    // Return value via hidden pointer passed as parameter
                    // Write exp; return shidden;
                    es = e;
                }
                else
                {
                    // Return value via hidden pointer passed as parameter
                    // Write *shidden=exp; return shidden;
                    int op;
                    tym_t ety;

                    ety = e->Ety;
                    es = el_una(OPind,ety,el_var(irs->shidden));
                    op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq;
                    es = el_bin(op, ety, es, e);
                    if (op == OPstreq)
                        es->ET = Type_toCtype(s->exp->type);
                }
                e = el_var(irs->shidden);
                e = el_bin(OPcomma, e->Ety, es, e);
            }
            else if (tf->isref)
            {
                // Reference return, so convert to a pointer
                e = toElemDtor(s->exp, irs);
                e = addressElem(e, s->exp->type->pointerTo());
            }
            else
            {
                e = toElemDtor(s->exp, irs);
                assert(e);
            }
            elem_setLoc(e, s->loc);
            block_appendexp(blx->curblock, e);
            bc = BCretexp;
        }
        else
            bc = BCret;

        if (block *finallyBlock = irs->getFinallyBlock())
        {
            assert(finallyBlock->BC == BC_finally);
            blx->curblock->appendSucc(finallyBlock);
        }

        block_next(blx, bc, NULL);
    }
Example #4
0
File: s2ir.c Project: Faianca/dmd
    void visit(SwitchStatement *s)
    {
        int string;
        Blockx *blx = irs->blx;

        //printf("SwitchStatement::toIR()\n");
        IRState mystate(irs,s);

        mystate.switchBlock = blx->curblock;

        /* Block for where "break" goes to
         */
        mystate.breakBlock = block_calloc(blx);

        /* Block for where "default" goes to.
         * If there is a default statement, then that is where default goes.
         * If not, then do:
         *   default: break;
         * by making the default block the same as the break block.
         */
        mystate.defaultBlock = s->sdefault ? block_calloc(blx) : mystate.breakBlock;

        size_t numcases = 0;
        if (s->cases)
            numcases = s->cases->dim;

        incUsage(irs, s->loc);
        elem *econd = toElemDtor(s->condition, &mystate);
        if (s->hasVars)
        {   /* Generate a sequence of if-then-else blocks for the cases.
             */
            if (econd->Eoper != OPvar)
            {
                elem *e = exp2_copytotemp(econd);
                block_appendexp(mystate.switchBlock, e);
                econd = e->E2;
            }

            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];

                elem *ecase = toElemDtor(cs->exp, &mystate);
                elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase);
                block *b = blx->curblock;
                block_appendexp(b, e);
                Label *clabel = getLabel(irs, blx, cs);
                block_next(blx, BCiftrue, NULL);
                b->appendSucc(clabel->lblock);
                b->appendSucc(blx->curblock);
            }

            /* The final 'else' clause goes to the default
             */
            block *b = blx->curblock;
            block_next(blx, BCgoto, NULL);
            b->appendSucc(mystate.defaultBlock);

            Statement_toIR(s->_body, &mystate);

            /* Have the end of the switch body fall through to the block
             * following the switch statement.
             */
            block_goto(blx, BCgoto, mystate.breakBlock);
            return;
        }

        if (s->condition->type->isString())
        {
            // Number the cases so we can unscramble things after the sort()
            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];
                cs->index = i;
            }

            s->cases->sort();

            /* Create a sorted array of the case strings, and si
             * will be the symbol for it.
             */
            dt_t *dt = NULL;
            Symbol *si = symbol_generate(SCstatic,type_fake(TYdarray));
            dtsize_t(&dt, numcases);
            dtxoff(&dt, si, Target::ptrsize * 2, TYnptr);

            for (size_t i = 0; i < numcases; i++)
            {   CaseStatement *cs = (*s->cases)[i];

                if (cs->exp->op != TOKstring)
                {   s->error("case '%s' is not a string", cs->exp->toChars()); // BUG: this should be an assert
                }
                else
                {
                    StringExp *se = (StringExp *)(cs->exp);
                    Symbol *si = toStringSymbol((char *)se->string, se->len, se->sz);
                    dtsize_t(&dt, se->len);
                    dtxoff(&dt, si, 0);
                }
            }

            si->Sdt = dt;
            si->Sfl = FLdata;
            outdata(si);

            /* Call:
             *      _d_switch_string(string[] si, string econd)
             */
            if (config.exe == EX_WIN64)
                econd = addressElem(econd, s->condition->type, true);
            elem *eparam = el_param(econd, (config.exe == EX_WIN64) ? el_ptr(si) : el_var(si));
            switch (s->condition->type->nextOf()->ty)
            {
                case Tchar:
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_STRING)), eparam);
                    break;
                case Twchar:
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_USTRING)), eparam);
                    break;
                case Tdchar:        // BUG: implement
                    econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_DSTRING)), eparam);
                    break;
                default:
                    assert(0);
            }
            elem_setLoc(econd, s->loc);
            string = 1;
        }
        else
            string = 0;
        block_appendexp(mystate.switchBlock, econd);
        block_next(blx,BCswitch,NULL);

        // Corresponding free is in block_free
        targ_llong *pu = (targ_llong *) ::malloc(sizeof(*pu) * (numcases + 1));
        mystate.switchBlock->BS.Bswitch = pu;
        /* First pair is the number of cases, and the default block
         */
        *pu++ = numcases;
        mystate.switchBlock->appendSucc(mystate.defaultBlock);

        /* Fill in the first entry in each pair, which is the case value.
         * CaseStatement::toIR() will fill in
         * the second entry for each pair with the block.
         */
        for (size_t i = 0; i < numcases; i++)
        {
            CaseStatement *cs = (*s->cases)[i];
            if (string)
            {
                pu[cs->index] = i;
            }
            else
            {
                pu[i] = cs->exp->toInteger();
            }
        }

        Statement_toIR(s->_body, &mystate);

        /* Have the end of the switch body fall through to the block
         * following the switch statement.
         */
        block_goto(blx, BCgoto, mystate.breakBlock);
    }
Example #5
0
File: glue.c Project: alexrp/dmd
void Module::genobjfile(int multiobj)
{
    //EEcontext *ee = env->getEEcontext();

    //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars());

    lastmname = srcfile->toChars();

    objmod->initfile(lastmname, NULL, toPrettyChars());

    eictor = NULL;
    ictorlocalgot = NULL;
    sctors.setDim(0);
    ectorgates.setDim(0);
    sdtors.setDim(0);
    ssharedctors.setDim(0);
    esharedctorgates.setDim(0);
    sshareddtors.setDim(0);
    stests.setDim(0);
    dtorcount = 0;
    shareddtorcount = 0;

    if (doppelganger)
    {
        /* Generate a reference to the moduleinfo, so the module constructors
         * and destructors get linked in.
         */
        Module *m = aimports[0];
        assert(m);
        if (m->sictor || m->sctor || m->sdtor || m->ssharedctor || m->sshareddtor)
        {
            Symbol *s = m->toSymbol();
            //objextern(s);
            //if (!s->Sxtrnnum) objextdef(s->Sident);
            if (!s->Sxtrnnum)
            {
                //printf("%s\n", s->Sident);
#if 0 /* This should work, but causes optlink to fail in common/newlib.asm */
                objextdef(s->Sident);
#else
                Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr));
                sref->Sfl = FLdata;
                dtxoff(&sref->Sdt, s, 0, TYnptr);
                outdata(sref);
#endif
            }
        }
    }

    if (global.params.cov)
    {
        /* Create coverage identifier:
         *  private uint[numlines] __coverage;
         */
        cov = symbol_calloc("__coverage");
        cov->Stype = type_fake(TYint);
        cov->Stype->Tmangle = mTYman_c;
        cov->Stype->Tcount++;
        cov->Sclass = SCstatic;
        cov->Sfl = FLdata;
        dtnzeros(&cov->Sdt, 4 * numlines);
        outdata(cov);
        slist_add(cov);

        covb = (unsigned *)calloc((numlines + 32) / 32, sizeof(*covb));
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *member = (*members)[i];
        //printf("toObjFile %s %s\n", member->kind(), member->toChars());
        member->toObjFile(multiobj);
    }

    if (global.params.cov)
    {
        /* Generate
         *      bit[numlines] __bcoverage;
         */
        Symbol *bcov = symbol_calloc("__bcoverage");
        bcov->Stype = type_fake(TYuint);
        bcov->Stype->Tcount++;
        bcov->Sclass = SCstatic;
        bcov->Sfl = FLdata;
        dtnbytes(&bcov->Sdt, (numlines + 32) / 32 * sizeof(*covb), (char *)covb);
        outdata(bcov);

        free(covb);
        covb = NULL;

        /* Generate:
         *  _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename);
         * and prepend it to the static constructor.
         */

        /* t will be the type of the functions generated:
         *      extern (C) void func();
         */
        type *t = type_function(TYnfunc, NULL, 0, false, tsvoid);
        t->Tmangle = mTYman_c;

        sictor = toSymbolX("__modictor", SCglobal, t, "FZv");
        cstate.CSpsymtab = &sictor->Sfunc->Flocsym;
        localgot = ictorlocalgot;

        elem *ecov  = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(cov));
        elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(bcov));

        if (config.exe == EX_WIN64)
        {
            ecov  = addressElem(ecov,  Type::tvoid->arrayOf(), false);
            ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false);
        }

        elem *e = el_params(
                      el_long(TYuchar, global.params.covPercent),
                      ecov,
                      ebcov,
                      toEfilename(),
                      NULL);
        e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e);
        eictor = el_combine(e, eictor);
        ictorlocalgot = localgot;
    }

    // If coverage / static constructor / destructor / unittest calls
    if (eictor || sctors.dim || ectorgates.dim || sdtors.dim ||
        ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim)
    {
        if (eictor)
        {
            localgot = ictorlocalgot;

            block *b = block_calloc();
            b->BC = BCret;
            b->Belem = eictor;
            sictor->Sfunc->Fstartline.Sfilename = arg;
            sictor->Sfunc->Fstartblock = b;
            writefunc(sictor);
        }

        sctor = callFuncsAndGates(this, &sctors, &ectorgates, "__modctor");
        sdtor = callFuncsAndGates(this, &sdtors, NULL, "__moddtor");

#if DMDV2
        ssharedctor = callFuncsAndGates(this, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor");
        sshareddtor = callFuncsAndGates(this, &sshareddtors, NULL, "__modshareddtor");
#endif
        stest = callFuncsAndGates(this, &stests, NULL, "__modtest");

        if (doppelganger)
            genmoduleinfo();
    }

    if (doppelganger)
    {
        objmod->termfile();
        return;
    }

    if (global.params.multiobj)
    {   /* This is necessary because the main .obj for this module is written
         * first, but determining whether marray or massert or munittest are needed is done
         * possibly later in the doppelganger modules.
         * Another way to fix it is do the main one last.
         */
        toModuleAssert();
        toModuleUnittest();
        toModuleArray();
    }

    /* Always generate module info, because of templates and -cov.
     * But module info needs the runtime library, so disable it for betterC.
     */
    if (!global.params.betterC /*|| needModuleInfo()*/)
        genmoduleinfo();

    // If module assert
    for (int i = 0; i < 3; i++)
    {
        Symbol *ma;
        unsigned rt;
        unsigned bc;
        switch (i)
        {
            case 0:     ma = marray;    rt = RTLSYM_DARRAY;     bc = BCexit; break;
            case 1:     ma = massert;   rt = RTLSYM_DASSERTM;   bc = BCexit; break;
            case 2:     ma = munittest; rt = RTLSYM_DUNITTESTM; bc = BCret;  break;
            default:    assert(0);
        }

        if (ma)
        {
            elem *elinnum;

            localgot = NULL;

            // Call dassert(filename, line)
            // Get sole parameter, linnum
            {
                Symbol *sp = symbol_calloc("linnum");
                sp->Stype = type_fake(TYint);
                sp->Stype->Tcount++;
                sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar;

                FuncParamRegs fpr(TYjfunc);
                fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2);

                sp->Sflags &= ~SFLspill;
                sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast;
                cstate.CSpsymtab = &ma->Sfunc->Flocsym;
                symbol_add(sp);

                elinnum = el_var(sp);
            }

            elem *efilename = el_ptr(toSymbol());

            elem *e = el_var(rtlsym[rt]);
            e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename));

            block *b = block_calloc();
            b->BC = bc;
            b->Belem = e;
            ma->Sfunc->Fstartline.Sfilename = arg;
            ma->Sfunc->Fstartblock = b;
            ma->Sclass = SCglobal;
            ma->Sfl = 0;
            ma->Sflags |= rtlsym[rt]->Sflags & SFLexit;
            writefunc(ma);
        }
    }

    objmod->termfile();
}