⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gstmt68.c

📁 CC386 is a general-purpose 32-bit C compiler. It is not an optimizing compiler but given that the co
💻 C
📖 第 1 页 / 共 3 页
字号:
        if (compact) {
            int i;
            cs->ptrs = xalloc((cs->top - cs->bottom) * sizeof(struct cases));
            for (i = cs->bottom; i < cs->top; i++)
                cs->ptrs[i - cs->bottom].label = cs->deflab;
        } else
            cs->ptrs = xalloc((cs->count) * sizeof(struct cases));
        global_flag--;
    }
    while (stmt)
    {
        switch(stmt->stype) {        
             case st_tryblock:
                break;
            case st_throw:
                break;
            case st_return:
            case st_expr:
                break;
            case st_while:
            case st_do:
                gather_cases(stmt->s1,cs,compact);
                break;
            case st_for:
                gather_cases(stmt->s1,cs,compact);
                break;
            case st_if:
                gather_cases(stmt->s1,cs,compact);
                gather_cases(stmt->s2,cs,compact);
                break;
            case st_switch:
                break;
            case st_block:
                gather_cases(stmt->exp,cs,compact);
                break;
            case st_asm:
                break;
            case st_case:
                if (stmt->s2)
                 /* default case */
                {
                    cs->diddef = TRUE;
                    stmt->label = (SNODE*)cs->deflab;
                }
                else
                {
                    
                    if (compact) {
                        cs->ptrs[stmt->switchid - cs->bottom].label = nextlabel;
                        stmt->label = (SNODE*)nextlabel++;
                    } else {
                        cs->ptrs[cs->tablepos].label = nextlabel;
                        cs->ptrs[cs->tablepos].binlabel =  - 1;
                        cs->ptrs[cs->tablepos++].id = stmt->switchid;
                        stmt->label = (SNODE*)nextlabel++;
                    }
                }
                break;
        }
        stmt = stmt->next;
    }
}

//-------------------------------------------------------------------------

int analyzeswitch(SNODE *stmt, struct cases *cs)
/* 
 * Decide whitch type of switch statement to use
 */
{
    int size = natural_size(stmt->exp);
    count_cases(stmt->s1,cs) ;
    cs->top++;
    if (cs->count == 0)
        return (0);
    if (cs->count < 5)
        return 3;
    if (cs->count *10 / (cs->top - cs->bottom) >= 8)
        return (1);
    // do a simple switch instead of a binary if it is a long long
    if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
        return 3;
    return (2);
}

//-------------------------------------------------------------------------

void bingen(int lower, int avg, int higher, AMODE *ap1, struct cases *cs)
/*
 * Recursively output the compare/jump tree for a type of binary search
 * on the case value
 */
{
    AMODE *ap2 = make_immed(cs->ptrs[avg].id);
    AMODE *ap3 = make_label(cs->ptrs[avg].label);
    if (cs->ptrs[avg].binlabel !=  - 1)
        gen_label(cs->ptrs[avg].binlabel);
    gen_codes(op_cmp, BESZ_DWORD, ap2, ap1);
    gen_codes(op_beq, 0, ap3, 0);
    if (avg == lower)
    {
        if (cs->deflab < 0)
            cs->deflab = nextlabel++;
        ap3 = make_label(cs->deflab);
        gen_codes(op_bra, 0, ap3, 0);
    }
    else
    {
        int avg1 = (lower + avg) / 2;
        int avg2 = (higher + avg + 1) / 2;
        if (avg + 1 < higher)
            ap3 = make_label(cs->ptrs[avg2].binlabel = nextlabel++);
        else
            ap3 = make_label(cs->deflab);
        if (ap1->length < 0)
            gen_codes(op_bgt, 0, ap3, 0);
        else
            gen_codes(op_bhi, 0, ap3, 0);
        bingen(lower, avg1, avg, ap1, cs);
        if (avg + 1 < higher)
            bingen(avg + 1, avg2, higher, ap1, cs);
    }
}

//-------------------------------------------------------------------------
int sortcmp(const void *one, const void *two)
{
    if (((struct caseptrs *)one)->id < ((struct caseptrs *)two)->id)
        return -1;
    if (((struct caseptrs *)one)->id > ((struct caseptrs *)two)->id)
        return 1;
    return 0;
}

void genbinaryswitch(SNODE *stmt, struct cases *cs)
/*
 * Main routine for handling the binary switch setup
 */
{
    AMODE *ap1;
    initstack();
    ap1 = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
    do_extend(ap1, ap1->length, F_DREG);
    gather_cases(stmt->s1,cs,FALSE);
    qsort(cs->ptrs,cs->count, sizeof(cs->ptrs[0]), sortcmp);
    bingen(0, (cs->count) / 2, cs->count, ap1, cs);
    freeop(ap1);
}

//-------------------------------------------------------------------------

void gencompactswitch(SNODE *stmt, struct cases *cs)
/*
 * Generate a table lookup mechanism if the switch table isn't too sparse
 */
{
    int tablab, i, size;
    AMODE *ap,  *ap1,  *ap2,  *ap3;
    tablab = nextlabel++;
    initstack();
    ap = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
    size = ap->length;
    do_extend(ap, BESZ_DWORD, F_DREG | F_VOL);
    initstack();
    if (size == BESZ_QWORD || size == - BESZ_QWORD)
    {
        if (cs->bottom)
        {
            int label = nextlabel++;
            #if sizeof(LLONG_TYPE) == 4
                gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom < 0
                    ?  - 1: 0), makedreg(1));
            #else 
                gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom >>
                    32), makedreg(1));
            #endif 
            if (size < 0)
                gen_1branch(op_blt, make_label(cs->deflab));
            else
            {
                peep_tail->noopt = TRUE;
                gen_1branch(op_bcs, make_label(cs->deflab));
            }
            gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom), makedreg(0));
            gen_1branch(op_bcc, make_label(label));
            gen_code(op_subq, make_immed(1), makedreg(1));
            if (size < 0)
                gen_1branch(op_blt, make_label(cs->deflab));
            else
            {
                peep_tail->noopt = TRUE;
                gen_1branch(op_bcs, make_label(cs->deflab));
            }
            gen_label(label);
        }
        else
            if (size < 0)
            {
                gen_codes(op_tst, BESZ_DWORD, makedreg(1), makedreg(1));
                gen_1branch(op_blt, make_label(cs->deflab));
            }
            gen_codes(op_cmp, BESZ_DWORD, make_immed(cs->top - cs->bottom), makedreg(0));
    }
    else  {
        if (cs->bottom)
        {
            gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom), ap);
            if (size < 0)
                gen_codes(op_blt, 0, make_label(cs->deflab), 0);
            else
            {
                peep_tail->noopt = TRUE;
                gen_codes(op_bcs, 0, make_label(cs->deflab), 0);
            }
        }
        else
        {
            if (size < 0)
            {
                gen_codes(op_tst, BESZ_DWORD, ap, 0);
                gen_codes(op_blt, 0, make_label(cs->deflab), 0);
            }
        }
        gen_codes(op_cmp, BESZ_DWORD, make_immed(cs->top - cs->bottom), ap);
    }
    if (size < 0)
        gen_codes(op_bhs, 0, make_label(cs->deflab), 0);
    else
        gen_codes(op_bcc, 0, make_label(cs->deflab), 0);
    ap1 = temp_addr();
    if (prm_68020 || prm_coldfire)
    {
        ap2 = xalloc(sizeof(AMODE));
        ap2->preg = ap1->preg;
        ap2->mode = am_pcindxdata;
        ap2->scale = 2;
        ap2->offset = makenode(en_labcon, (char*)tablab, 0);
        gen_codes(op_lea, BESZ_DWORD, ap2, ap1);
        ap3 = xalloc(sizeof(AMODE));
        ap3->sreg = ap->preg;
        ap3->preg = ap1->preg;
        ap3->scale = 0;
        ap3->offset = makeintnode(en_icon, 0);
        ap3->mode = am_ind;
        gen_codes(op_adda, BESZ_DWORD, ap3, ap1);
    }
    else
    {
        ap2 = xalloc(sizeof(AMODE));
        if (prm_pcrel)
        {
            ap2->preg = ap1->preg;
            ap2->mode = am_pcindx;
        }
        else
        {
            ap2->mode = am_adirect;
            if (prm_smallcode)
                ap2->preg = 2;
            else
                ap2->preg = 4;
        }
        ap2->offset = makeintnode(en_labcon, tablab);
        gen_codes(op_lea, 0, ap2, ap1);
        if (prm_datarel || prm_smallcode)
            gen_codes(op_asl, BESZ_DWORD, make_immed(1), ap);
        else
            gen_codes(op_asl, BESZ_DWORD, make_immed(2), ap);
        if (prm_datarel)
        {
            gen_codes(op_add, BESZ_DWORD, ap, ap1);
            ap2->mode = am_ind;
            gen_codes(op_add, 2, ap2, ap1);
        }
        else
        {
            ap3 = xalloc(sizeof(AMODE));
            ap3->sreg = ap->preg;
            ap3->preg = ap1->preg;
            ap3->scale = 0;
            ap3->offset = makeintnode(en_icon, 0);
            ap3->mode = am_baseindxdata;
            gen_codes(op_move, BESZ_DWORD, ap3, ap1);
        }
    }
    ap1->mode = am_ind;
    gen_codes(op_jmp, 0, ap1, 0);

    initstack();
    gen_label(tablab);
    gather_cases(stmt->s1,cs,TRUE);
    for (i = 0; i < cs->top - cs->bottom; i++)
        if (!prm_coldfire && (prm_smallcode || prm_pcrel))
            gen_codes(op_dcl, 2, make_label(cs->ptrs[i].label), 0);
        else
            gen_codes(op_dcl, BESZ_DWORD, make_label(cs->ptrs[i].label), 0);
}

//-------------------------------------------------------------------------

void gensimpleswitch(SNODE *stmt, struct cases *cs)
{
    int i = 0, j;
    AMODE *ap1,*ap2,*ap3,*ap4;
    int size = natural_size(stmt->exp);
    initstack();
    ap1 = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
    do_extend(ap1, BESZ_DWORD, F_DREG);
    gather_cases(stmt->s1,cs,FALSE);
    qsort(cs->ptrs,cs->count, sizeof(cs->ptrs[0]), sortcmp);
    for (i = 0; i < cs->count; i++)
    {
        if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
        {
            int lab = nextlabel++;
            ap2 = make_immed(cs->ptrs[i].id);
            #if sizeof(LLONG_TYPE) == 4
                ap4 = make_immed(cs->ptrs[i].id < 0 ? 0xffffffff : 0);
            #else 
                ap4 = make_immed(cs->ptrs[i].id >> 32);
            #endif 
            ap3 = make_label(cs->ptrs[i].label);
            gen_coden(op_cmp, BESZ_DWORD, ap2, makedreg(0));
            gen_1branch(op_bne, make_label(lab));
            gen_codes(op_cmp, BESZ_DWORD, ap4, makedreg(1));
            gen_1branch(op_beq, ap3);
            gen_label(lab);
        }
        else {
            AMODE *ap2 = make_immed(cs->ptrs[i].id);
            AMODE *ap3 = make_label(cs->ptrs[i].label);
            gen_codes(op_cmp, ap1->length, ap2, ap1);
            gen_code(op_beq, ap3, 0);
        }
    }
    gen_1branch(op_bra, make_label(cs->deflab));
    freeop(ap1);
}

//-------------------------------------------------------------------------

void genxswitch(SNODE *stmt)
/*
 *      analyze and generate best switch statement.
 */
{
    int oldbreak;
    struct cases cs;
    OCODE *result;
    oldbreak = breaklab;
    breaklab = nextlabel++;
    memset(&cs,0,sizeof(cs));
#if sizeof(LLONG_TYPE) == 4
    cs.top = INT_MIN;
    cs.bottom = INT_MAX;
#else
    cs.top = (a << 63); // LLONG_MIN
    cs.bottom = cs.top - 1; // LLONG_MAX
#endif
    cs.deflab = nextlabel++;
    switch (analyzeswitch(stmt,&cs))
    {
        case 3:
            gensimpleswitch(stmt, &cs);
            break;
        case 2:
            genbinaryswitch(stmt, &cs);
            break;
        case 1:
            gencompactswitch(stmt, &cs);
            break;
        case 0:
            break;
    }
    result = gen_codes(op_blockstart, 0, 0, 0);
    result->blocknum = (int)stmt->label;
    genstmt(stmt->s1);
    result = gen_codes(op_blockend, 0, 0, 0);
    result->blocknum = (int)stmt->label;
    if (!cs.diddef)
        gen_label(cs.deflab);
    gen_label(breaklab);
    breaklab = oldbreak;
}

//-------------------------------------------------------------------------

void AddProfilerData(void)
{
    char pname[256];
    if (prm_profiler)
    {
        sprintf(pname, "%s", currentfunc->name);
        plabel = stringlit(pname, FALSE, strlen(pname) + 1);
        gen_codes(op_pea, BESZ_DWORD, make_label(plabel), 0);
        call_library("__profile_in", 4);
    }
}

//-------------------------------------------------------------------------

void SubProfilerData(void)
{
    if (prm_profiler)
    {
        gen_codes(op_pea, BESZ_DWORD, make_label(plabel), 0);
        call_library("__profile_out", 4);
    }
}

//-------------------------------------------------------------------------

void genreturn(SNODE *stmt, int flag)
/*
 *      generate a return statement.
 */
{
    AMODE *ap,  *ap1,  *ap2,  *ap3;
    ENODE *mvn1;
    int size;
    SubProfilerData();
    if (stmt != 0 && stmt->exp != 0)
    {
        if (!genning_inline)
            initstack();
        if (currentfunc->tp->btp && isstructured(currentfunc->tp->btp))
        {
            size = currentfunc->tp->btp->size;
            ap = gen_expr(stmt->exp, FALSE, TRUE, BESZ_DWORD);
            returndreg = TRUE;
        }
        else if (currentfunc->tp->btp && currentfunc->tp->btp->type ==
            bt_memberptr)
        {
            size = BESZ_DWORD;
            ap = gen_expr(stmt->exp, FALSE, TRUE, BESZ_DWORD);
            returndreg = TRUE;

        }
        else
        {
            size = currentfunc->tp->btp->size;
            if (size == BESZ_DWORD && currentfunc->tp->btp->type == bt_float)
                size = BESZ_FLOAT;
            if (currentfunc->tp->btp->type == bt_longlong || currentfunc->tp
                ->btp->type == bt_unsignedlonglong)
            {
                size = currentfunc->tp->btp->type == bt_long ?  - BESZ_QWORD: BESZ_QWORD;
                ap = gen_expr(stmt->exp, FALSE, FALSE, size);
                do_extend(ap, size, F_DOUBLEREG);
            }
            else if (size > BESZ_QWORD)
            {
                retsize = BESZ_LDOUBLE;
                ap = gen_expr(stmt->exp, FALSE, FALSE, size);
                do_extend(ap, size, F_FREG);
            }
            else
            {
                returndreg = TRUE;
                retsize = BESZ_DWORD;
                ap = gen_expr(stmt->exp, FALSE, FALSE, size);
                do_extend(ap, size, F_DREG | F_VOL);
                if (!genning_inline && ap->preg != 0)
                {
                    gen_codes(op_move, size, makedreg(0), ap);
                    ap = makedreg(0);
                }
            }
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -