コード例 #1
0
ファイル: s2ir.c プロジェクト: 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);
    }
コード例 #2
0
ファイル: s2ir.c プロジェクト: Rayerd/dmd
void SwitchStatement::toIR(IRState *irs)
{
    int string;
    Blockx *blx = irs->blx;

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

    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 = sdefault ? block_calloc(blx) : mystate.breakBlock;

    int numcases = 0;
    if (cases)
        numcases = cases->dim;

    incUsage(irs, loc);
    elem *econd = condition->toElemDtor(&mystate);
#if DMDV2
    if (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 (int i = 0; i < numcases; i++)
        {   CaseStatement *cs = cases->tdata()[i];

            elem *ecase = cs->exp->toElemDtor(&mystate);
            elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase);
            block *b = blx->curblock;
            block_appendexp(b, e);
            block *bcase = block_calloc(blx);
            cs->cblock = bcase;
            block_next(blx, BCiftrue, NULL);
            list_append(&b->Bsucc, bcase);
            list_append(&b->Bsucc, blx->curblock);
        }

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

        body->toIR(&mystate);

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

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

        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));
#if MACHOBJ
        si->Sseg = DATA;
#endif
        dtsize_t(&dt, numcases);
        dtxoff(&dt, si, PTRSIZE * 2, TYnptr);

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

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

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

        /* Call:
         *      _d_switch_string(string[] si, string econd)
         */
        elem *eparam = el_param(econd, el_var(si));
        switch (condition->type->nextOf()->ty)
        {
        case Tchar:
            econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_STRING]), eparam);
            break;
        case Twchar:
            econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_USTRING]), eparam);
            break;
        case Tdchar:        // BUG: implement
            econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_DSTRING]), eparam);
            break;
        default:
            assert(0);
        }
        elem_setLoc(econd, 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;
    list_append(&mystate.switchBlock->Bsucc, 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 (int i = 0; i < numcases; i++)
    {
        CaseStatement *cs = cases->tdata()[i];
        if (string)
        {
            pu[cs->index] = i;
        }
        else
        {
            pu[i] = cs->exp->toInteger();
        }
    }

    body->toIR(&mystate);

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