bldsel.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 614 行 · 第 1/2 页

C
614
字号
    }
    /* generate if's to check if index in table*/
    if( s_node->other_wise != NULL ) {
        lt = BGCompare( O_LE, BGDuplicate(node),
                        BGInteger( s_node->upper - s_node->lower, tipe ), NULL,
                        UnSignedIntTipe( tipe ) );
        BGControl( O_IF_FALSE, lt, s_node->other_wise );
    }
    /* generate table*/
    /* index into table*/
    node = BGConvert( node, UnSignedIntTipe( tipe ) ); /* value an unsigned index */
    SelectBlock( MakeJmpTab( s_node->list, s_node->lower, s_node->upper,
                             s_node->other_wise ),
                 node, s_node->other_wise );
    return( node );
}


static  void    DoBinarySearch( an node, select_list *list, type_def *tipe,
                               int lo, int hi, label_handle other,
                               signed_32 lobound, signed_32 hibound,
                               bool have_lobound, bool have_hibound ) {
/****************************************************************/

    int                 num;
    int                 mid;
    select_list         *mid_list;
    bn                  cmp;
    label_handle        lt;

    mid = lo + ( hi - lo ) / 2;
    mid_list = list;
    num = mid;
    while( --num >= 0 ) {
        mid_list = mid_list->next;
    }
    if( lo == hi ) {
        if( have_lobound && lobound == mid_list->low
         && have_hibound && hibound == mid_list->high ) {
             BGControl( O_GOTO, NULL, mid_list->label );
             return;
        } else if( mid_list->low == mid_list->high ) {
            cmp = BGCompare( O_EQ, BGDuplicate( node ),
                             BGInteger( mid_list->low, tipe ), NULL, tipe );
            BGControl( O_IF_TRUE, cmp, mid_list->label );
            BGControl( O_GOTO, NULL, other );
            return;
        }
    }
    lt = AskForNewLabel();
    if( !have_lobound || SelCompare( lobound, mid_list->low ) < 0 ) {
        if( have_hibound && SelCompare( hibound, mid_list->low ) < 0 ) {
            BGControl( O_GOTO, NULL, lt );
        } else {
            cmp = BGCompare( O_LT, BGDuplicate( node ),
                             BGInteger( mid_list->low, tipe ), NULL, tipe );
            BGControl( O_IF_TRUE, cmp, lt );
        }
    }
    if( !have_lobound || SelCompare( lobound, mid_list->high ) <= 0 ) {
        if( have_hibound && SelCompare( hibound, mid_list->high ) <= 0 ) {
            BGControl( O_GOTO, NULL, mid_list->label );
        } else {
            cmp = BGCompare( O_LE, BGDuplicate( node ),
                             BGInteger( mid_list->high, tipe ), NULL, tipe );
            BGControl( O_IF_TRUE, cmp, mid_list->label );
        }
    }
    if( mid < hi ) {
        DoBinarySearch( node, list, tipe, mid+1, hi, other,
                        mid_list->high+1, hibound, TRUE, have_hibound );
    } else if( other != NULL ) {
        BGControl( O_GOTO, NULL, other );
    }
    BGControl( O_LABEL, NULL, lt );
    if( lo < mid ) {
        DoBinarySearch( node, list, tipe, lo, mid-1, other,
                        lobound, mid_list->low-1, have_lobound, TRUE );
    } else if( other != NULL ) {
        BGControl( O_GOTO, NULL, other );
    }
}


static  an      GenIfStmts( an node, select_node *s_node, type_def *tipe ) {
/**************************************************************************/

    select_list *list;
    int         nodes;

    nodes = 0;
    for( list = s_node->list; list != NULL; list = list->next ) {
        ++nodes;
    }
    DoBinarySearch( node, s_node->list, tipe, 0, nodes-1, s_node->other_wise,
                    0, 0, FALSE, FALSE );
    return( node );
}


extern  signed_32       NumValues( select_list *list, signed_32 hi ) {
/********************************************************************/

    signed_32           cases;

    cases = 0;
    while( list != NULL ) {
        if( SelCompare( list->high, hi ) > 0 ) break;
        cases += list->high - list->low + 1;
        list = list->next;
    }
    return( cases );
}

static  void    ScanBlock( tbl_control *table, an node, cg_type tipe,
                           label_handle other ) {
/*******************************************************************/

    uint                i;
    uint                targets;
    name                *value;

    value = GenIns( node );
    MkSelOp( ScanCall( table, value, tipe ), tipe );
    i = 0;
    targets = 0;
    for(;;) {
        if( table->cases[ i ] != other ) {
            ++targets;
        }
        if( ++i == table->size ) break;
    }
    if( other != NULL ) {
        ++targets;
    }
    GenBlock( SELECT, targets );
    i = 0;
    for(;;) {
        if( table->cases[ i ] != other ) {
            AddTarget( table->cases[ i ], FALSE );
        }
        if( ++i == table->size ) break;
    }
    if( other != NULL ) {
        AddTarget( other, FALSE );
    }
    Generate( FALSE );
    EnLink( AskForNewLabel(), TRUE );
}


static  void    SelectBlock( tbl_control *table, an node, label_handle other ) {
/*****************************************************************************/

    uint                i;
    uint                targets;

    MkSelOp( (name *) SelIdx( table, node ), T_UINT_2 );
    i = 0;
    targets = 0;
    for(;;) {
        if( table->cases[ i ] != other ) {
            ++targets;
        }
        if( ++i == table->size ) break;
    }
    if( other != NULL ) {
        ++targets;
    }
    GenBlock( SELECT, targets );
    i = 0;
    for(;;) {
        if( table->cases[ i ] != other ) {
            AddTarget( table->cases[ i ], FALSE );
        }
        if( ++i == table->size ) break;
    }
    if( other != NULL ) {
        AddTarget( other, FALSE );
    }
    Generate( FALSE );
    EnLink( AskForNewLabel(), TRUE );
}


extern  void    FreeTable( tbl_control *table ) {
/***********************************************/

    _Free( table, (table->size-1)*sizeof(label_handle) + sizeof(tbl_control) );
}


static  void    FreeSelectNode( select_node *s_node ) {
/*****************************************************/

    select_list         *list;
    select_list         *prev;

    list = s_node->list;
    while( list != NULL ) {
        prev = list;
        list = list->next;
        _Free( prev, sizeof( select_list ) );
    }
    _Free( s_node, sizeof( select_node ) );
}


extern  void    BGSelect( select_node *s_node, an node, cg_switch_type allowed ) {
/********************************************************************************/

    signed_32   cost;
    signed_32   best;
    sel_kind    kind;

    if( ( allowed & CG_SWITCH_ALL ) == 0 ) {
        _Zoiks( ZOIKS_090 );
        allowed = CG_SWITCH_ALL;
    }
    node = Arithmetic( node, TypeInteger );
    if( s_node->num_cases != 0 ) {
        best = 0x7FFFFFFF;
        SortNodeList( node, s_node, TRUE ); /* sort signed */
        if( allowed & CG_SWITCH_SCAN ) {
            cost = ScanCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = S_SCAN;
            }
        }
        if( allowed & CG_SWITCH_TABLE ) {
            cost = JumpCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = S_JUMP;
            }
        }
        if( allowed & CG_SWITCH_BSEARCH ) {
            cost = DistinctIfCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = S_IF;
            }
        }
        SortNodeList( node, s_node, FALSE ); /* sort unsigned */
        if( allowed & CG_SWITCH_SCAN ) {
            cost = ScanCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = U_SCAN;
            }
        }
        if( allowed & CG_SWITCH_TABLE ) {
            cost = JumpCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = U_JUMP;
            }
        }
        if( allowed & CG_SWITCH_BSEARCH ) {
            cost = DistinctIfCost( s_node );
            if( cost <= best ) {
                best = cost;
                kind = U_IF;
            }
        }
        switch( kind ) {
        case S_SCAN:
        case S_JUMP:
        case S_IF:
            SortNodeList( node, s_node, TRUE ); /* sort signed */
            break;
        }
        node = BGConvert( node, SortTipe );

        /*
         * We generate this bogus add 0 node so that we have a temporary
         * for the actual value to switch on. If we don't do this, a
         * problem could occur if the switch variable was volatile and
         * we loaded it once to decide whether to use a scan table and
         * once to index into the scan table. This would be bad if it
         * changed in between.
         */
        node = BGBinary(O_PLUS, node, BGInteger( 0, SortTipe ), SortTipe, TRUE );

        MergeListEntries( s_node );
        switch( kind ) {
        case S_SCAN:
        case U_SCAN:
            node = GenScanTable( node, s_node, SortTipe );
            break;
        case S_JUMP:
        case U_JUMP:
            node = GenSelTable( node, s_node, SortTipe );
            break;
        case S_IF:
        case U_IF:
            node = GenIfStmts( node, s_node, SortTipe );
            break;
        }
    } else if( s_node->other_wise != NULL ) {
        BGControl( O_GOTO, NULL, s_node->other_wise );
    }
    BGDone( node );
    FreeSelectNode( s_node );
}

⌨️ 快捷键说明

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