bldsel.c

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

C
614
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Build code for a selection (switch) statement.
*
****************************************************************************/


#include "standard.h"
#include "cgdefs.h"
#include "coderep.h"
#include "opcodes.h"
#include "sysmacro.h"
#include "addrname.h"
#include "seldef.h"
#include "tree.h"
#include "zoiks.h"

#include "bldins.h"

extern  label_handle    AskForNewLabel(void);
extern  type_def        *TypeAddress(cg_type);
extern  void            AddTarget(label_handle,bool);
extern  signed_32       IfCost(select_node*,int);
extern  void            EnLink(label_handle,bool);
extern  name            *ScanCall(tbl_control*,name*,type_class_def);
extern  void            AddIns(instruction*);
extern  signed_32       JumpCost(select_node*);
extern  instruction     *NewIns(int);
extern  void            Generate(bool);
extern  signed_32       ScanCost(select_node*);
extern  void            GenBlock(int,int);
extern  name            *GenIns(an);
extern  tbl_control     *MakeScanTab(select_list*,signed_32,
                                     label_handle,cg_type,cg_type);
extern  tbl_control     *MakeJmpTab(select_list*,signed_32,signed_32,
                                    label_handle);
extern  name_def        *SelIdx(tbl_control*,an);
extern  type_def        *SelNodeType(an,bool);
extern  void            *SortList(void *,unsigned,bool (*)(void*,void*) );
extern  void            MkSelOp( name *idx, cg_type tipe );

extern    type_def      *TypeInteger;

/* forward declarations */
extern  void    BGSelRange( select_node *s_node, signed_32 lo,
                            signed_32 hi, label_handle label );
static  void    ScanBlock( tbl_control *table, an node, cg_type tipe,
                           label_handle other );
static  void    SelectBlock( tbl_control *table, an node, label_handle other );

static  select_list *NewCase( signed_32 lo, signed_32 hi, label_handle label ) {
/******************************************************************************/

    select_list         *new_entry;

    _Alloc( new_entry, sizeof( select_list ) );
    new_entry->low = lo;
    new_entry->high = hi;
    new_entry->count = hi - lo + 1;
    new_entry->label = label;
    new_entry->next = NULL;
    return( new_entry );
}


extern  select_node     *BGSelInit() {
/************************************/

    select_node         *s_node;

    _Alloc( s_node, sizeof( select_node ) );
    s_node->num_cases = 0;
    s_node->other_wise = NULL;
    s_node->list = NULL;
#ifndef NDEBUG
    s_node->useinfo.hdltype = NO_HANDLE;
    s_node->useinfo.used = FALSE;
#endif
    return( s_node );
}


extern  void    BGSelCase( select_node *s_node, label_handle label,
                           signed_32 value ) {
/**************************************************************/

    BGSelRange( s_node, value, value, label );
}


extern  void    BGSelRange( select_node *s_node, signed_32 lo,
                            signed_32 hi, label_handle label ) {
/*************************************************************/

    select_list         *new_entry;

    if( ( hi ^ lo ) < 0 ) _Zoiks( ZOIKS_089 );
    new_entry = NewCase( lo, hi, label );
    new_entry->next = s_node->list;
    s_node->list = new_entry;
    s_node->num_cases += hi - lo + 1;
}


extern  void    BGSelOther( select_node *s_node, label_handle other ) {
/********************************************************************/

    s_node->other_wise = other;
}


static type_def         *SortTipe;

extern int SelCompare( signed_32 lo1, signed_32 lo2 ) {
/******************************************************/

    if( lo1 == lo2 ) return( 0 );
    if( SortTipe->attr & TYPE_SIGNED ) {
        if( lo1 < lo2 ) return( -1 );
    } else {
        if( (unsigned_32)lo1 < (unsigned_32)lo2 ) return( -1 );
    }
    return( 1 );
}


static  bool            NodeLess( void *s1, void *s2 ) {
/******************************************************/

    return( SelCompare( ((select_list *)s1)->low, ((select_list *)s2)->low ) < 0 );
}



static  void    SortNodeList( an node, select_node *s_node, bool is_signed ) {
/****************************************************************************/

    select_list *list;

    SortTipe = SelNodeType( node, is_signed );
    list = SortList( s_node->list, offsetof( select_list, next ), NodeLess );
    s_node->list = list;
    s_node->lower = list->low;
    while( list->next != NULL ) list = list->next;
    s_node->upper = list->high;
}


typedef enum sel_kind {
    U_SCAN,
    U_JUMP,
    U_IF,
    S_SCAN,
    S_JUMP,
    S_IF
} sel_kind;

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

    select_list *list;
    select_list *next;

    list = s_node->list;
    next = list->next;
    while( next != NULL ) {
        if( ( list->high + 1 == next->low ) && ( list->label == next->label ) ) {
            list->high = next->high;
            list->next = next->next;
            _Free( next, sizeof( select_list ) );
        } else {
            list = list->next;
        }
        next = list->next;
    }
}


static  signed_32       DistinctIfCost( select_node *s_node ) {
/*************************************************************/

    select_list *list;
    select_list *next;
    int         entries;

    entries = 1;
    list = s_node->list;
    next = list->next;
    while( next != NULL ) {
        if( ( list->high + 1 != next->low ) || ( list->label != next->label ) ) {
            ++entries;
            list = next;
        }
        next = next->next;
    }
    return( IfCost( s_node, entries ) );
}


extern  cg_type SelType( unsigned_32 value_range ) {
/**************************************************/

    cg_type     tipe;

    if( ( value_range & 0xFFFF0000 ) == 0 ) {
        if( ( value_range & 0xFF00 ) == 0 ) {
            tipe = T_UINT_1;
        } else {
            tipe = T_UINT_2;
        }
    } else {
        tipe = T_UINT_4;
    }
    if( tipe > SortTipe->refno ) {
        switch( SortTipe->refno ) {
        case T_UINT_1:
        case T_INT_1:
            tipe = T_UINT_1;
            break;
        case T_UINT_2:
        case T_INT_2:
            tipe = T_UINT_2;
            break;
        case T_UINT_4:
        case T_INT_4:
            tipe = T_UINT_4;
            break;
        }
    }
    return( tipe );
}


static  type_def        *UnSignedIntTipe( type_def *tipe ) {
/*******************************************************/

    switch( tipe->length ) {
    case 1:
        return( TypeAddress( T_UINT_1 ) );
    case 2:
        return( TypeAddress( T_UINT_2 ) );
    case 4:
        return( TypeAddress( T_UINT_4 ) );
    }
    _Zoiks( ZOIKS_102 );  /* if we get here bug */
    return( NULL );
}


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

    bn                  lt;
    type_class_def      value_type;
    type_class_def      real_type;

    value_type = SelType( s_node->upper - s_node->lower );
    real_type = tipe->refno;
    if( real_type != value_type ) {
        node = BGBinary( O_MINUS, node,
                          BGInteger( s_node->lower, tipe ), tipe, TRUE );
        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 );
        }
    }
    ScanBlock( MakeScanTab( s_node->list, s_node->upper, s_node->other_wise,
                            value_type, real_type ), node, value_type,
                            s_node->other_wise );
    return( node );
}


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

    bn          lt;

    if( s_node->lower != 0 ) {
        node = BGBinary( O_MINUS, node,
                          BGInteger( s_node->lower, tipe ), tipe , TRUE );

⌨️ 快捷键说明

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