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 + -
显示快捷键?