bldcall.c

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

C
910
字号
        if( addr->flags & ADDR_CROSSED_BLOCKS ) {
            ins->result->v.usage |= USE_IN_ANOTHER_BLOCK;
        }
        curr = ins->result;
#if _TARGET & _TARG_AXP
        if( 1 ) {
#else
        if( addr->tipe->length == reg->n.size ) {
#endif
            ins = MakeMove( curr, reg, TypeClass( addr->tipe ) );
            AddIns( ins );
        } else if( !CvtOk( TypeClass(addr->tipe), reg->n.name_class ) ) {
            ins = NULL;
            FEMessage( MSG_BAD_PARM_REGISTER, (pointer) parm->num );
#if _TARGET & ( _TARG_IAPX86 | _TARG_80386 )
        } else if( HW_CEqual( reg->r.reg, HW_ABCD ) ) {
            ins = NULL;
            FEMessage( MSG_BAD_PARM_REGISTER, (pointer) parm->num );
#endif
        } else {
            ins = MakeConvert( curr, reg,
                               reg->n.name_class, TypeClass( addr->tipe ) );
            AddIns( ins );
        }
        addr->format = NF_ADDR;
#if _TARGET & _TARG_80386
        if( state->attr & ROUTINE_STACK_RESERVE ) {
            // this is for the stupid OS/2 _Optlink calling convention
            ReserveStack( state, ins, addr->tipe->length );
        }
#else
        state = state;
#endif
        BGDone( addr );
        parm->ins = ins;
        parm = parm->next;
    }
}


extern  void    BGZapBase( name *base, type_def *tipe ) {
/********************************************************
    for FORTRAN. Generate a NOP with result of base[temp], so that we
    know that a pass by reference argument can be modified by the
    call. The NOP instruction right after the call.
*/

    instruction *ins;

    if( base == NULL ) return;
    if( _IsntModel( FORTRAN_ALIASING ) ) return;
    if( !( tipe->attr & TYPE_POINTER ) ) return;
    ins = MakeNop();
    if( DummyIndex == NULL ) DummyIndex = AllocTemp( WD );
    ins->result = ScaleIndex( DummyIndex, base, 0, XX, tipe->length,
                              0, X_FAKE_BASE );
    ins->flags.nop_flags |= NOP_ZAP_INFO;
    AddIns( ins );
}


extern  void    BGReturn( an retval, type_def *tipe ) {
/******************************************************
    generate the instructions to return the value 'retval', then
    go off and call generate to optimize the whole routine and
    spew it out into the object file.
*/

    instruction         *ins;
    instruction         *last_ins;
    instruction         *ret_ins;
    name                *name;
    type_class_def      class;
    type_class_def      aclass;

    ins = MakeNop();
    last_ins = NULL;
    if( retval != NULL ) {
        class = TypeClass( tipe );
        aclass = ReturnClass( tipe, CurrProc->state.attr );
        UpdateReturn( & CurrProc->state, tipe, aclass,
                       FEAuxInfo( AskForLblSym(CurrProc->label), AUX_LOOKUP ) );
        if( _IsModel( DBG_LOCALS ) ){  // d1+ or d2
            DbgRetLoc();
        }
        if( aclass == XX ) {
            name = StReturn( retval, tipe, &last_ins );
            AddIns( MakeMove( GenIns( retval ), name, class ) );
        } else {
            if( HW_CEqual( CurrProc->state.return_reg, HW_EMPTY ) ) {
                name = StReturn( retval, tipe, &last_ins );
            } else {
                name = AllocRegName( CurrProc->state.return_reg );
            }
#if _TARGET & _TARG_AXP
            if( class == U4 && aclass == I8 ) {
                ret_ins = MakeConvert( GenIns( retval ), name, I8, I4 );
            } else {
#endif
                if( tipe->length == name->n.size ) {
                    ret_ins = MakeMove( GenIns( retval ),
                                        name, name->n.name_class );
                } else {
                    ret_ins = MakeConvert( GenIns( retval ), name,
                                           name->n.name_class, class );
                }
                // BBB - we can get a situation where we are returning
                // a float in eax (when compiling -3s) and we don't want
                // to do a convert - ack.
                // ret_ins = MakeConvert( GenIns( retval ), name,
                //                     name->n.name_class, class );
#if _TARGET & _TARG_AXP
            }
#endif
            AddIns( ret_ins );
        }
        BGDone( retval );
    } else {
        ins->zap = &AllocRegName( CurrProc->state.return_reg )->r;
        ins->flags.nop_flags |= NOP_ZAP_INFO;
    }
    AddIns( ins );
    if( last_ins != NULL ) AddIns( last_ins );
    GenBlock( RETURN, 0 );
    if( AddrList != NULL ) {
        _Zoiks( ZOIKS_003 );
    }
    Generate( TRUE );
    TargetModel = SaveModel;
}

#if _TARGET & _TARG_RISC

static pn   BustUpStruct( pn parm, type_class_def from, type_class_def using ) {
/******************************************************************************/

    pn                  curr;
    pn                  last;
    type_length         len;
    type_length         offset;
    type_length         size;
    name                *temp;
    instruction         *ins;

    size = TypeClassSize[ using ];
    len = _RoundUp( parm->name->tipe->length, size );
    offset = len - size;
    temp = AllocTemp( from );
    temp->n.size = len;
    last = parm->next;
    parm->name->u.ins->result = temp;
    while( offset >= 0 ) {
        // create a parm node for this part of the struct
        _Alloc( curr, sizeof( parm_node ) );
        ins = MakeMove( STempOffset( temp, offset, using, size ), NULL, using );
        AddIns( ins );
        curr->next = last;
        curr->name = InsName( ins, ClassType( using ) );
        curr->name->flags = parm->name->flags;
        curr->alignment = 4;
        last = curr;
        offset -= size;
    }
    // only needed for first parm (PPC hack - doubles skip registers)
    curr->alignment = parm->alignment;
    return( curr );
}

static void SplitStructParms( pn *parm_list, call_state *state ) {
/*****************************************************************
    Split up any structures being passed as parms into
    smaller, independant chunks (system dependant).
*/

    pn                  parm;
    pn                  *last_parm;
    an                  name;
    type_class_def      tipe;
    type_class_def      class;

#if _TARGET & _TARG_PPC
    if( _IsTargetModel( CG_OS2_CC ) ) return;
    tipe = U4;
#elif _TARGET & _TARG_AXP
    state = state;
    tipe = U8;
#elif _TARGET & _TARG_MIPS
    tipe = U4;
#else
    #error Unknown RISC CPU
#endif
    last_parm = parm_list;
    parm = *last_parm;
    while( parm != NULL ) {
        name = parm->name;
        parm->alignment = ParmAlignment( name->tipe );
        class = TypeClass( name->tipe );
        if( class == XX
#if _TARGET & _TARG_PPC
                || ( ( class == FD ) && ( state->attr & ROUTINE_HAS_VARARGS ) )
#endif
        ) {
            if( ( class == FD ) || ( name->tipe->length > 7 ) ) {
                parm->alignment = 8;
            }
            *last_parm = BustUpStruct( parm, class, tipe );
            name->format = NF_ADDR;
            BGDone( name );
            _Free( parm, sizeof( parm_node ) );
            parm = *last_parm;
        }
        last_parm = &parm->next;
        parm = parm->next;
    }
}
#endif

extern  bool        AssgnParms( cn call, bool in_line ) {
/********************************************************
    Decide what registers the parms should go in.
    Assign registers to first parm first, etc. Also, assign a congolmeration
    of all the parameter registers to one of the operands of the call
    so that the dataflow knows that the registers are live between the
    move into them and the call.
*/


    pn                  parm;
    call_state          *state;
    bool                push_no_pop;
    int                 parms;
    instruction         *call_ins;
    type_class_def      parm_tipe;
    type_class_def      reg_tipe;


    push_no_pop = FALSE;
    parm = call->parms;
    state = call->state;
    call_ins = call->ins;
    parms = 0;
#if _TARGET & _TARG_RISC
    SplitStructParms( &call->parms, state );
    parm = call->parms;
#endif
    while( parm != NULL ) {
        if( in_line ) {
            parm->regs = ParmInLineReg( &state->parm );
            if( HW_CEqual( parm->regs, HW_EMPTY ) ) {
                if( !HW_CEqual( *(state->parm.curr_entry), HW_EMPTY ) ) {
                    FEMessage( MSG_ERROR,
                    "More parameters than registers in pragma" );
                } else {
                    parm->offset = ParmMem( parm->name->tipe->length, ParmAlignment( parm->name->tipe ), state );
                    push_no_pop = TRUE;
                }
            } else {
                parm_tipe = TypeClass( parm->name->tipe );
                reg_tipe  = AllocRegName( parm->regs )->n.name_class;
                if( parm_tipe != FD || reg_tipe != U8 ) {
                    if( !CvtOk( parm_tipe, reg_tipe ) ) {
                        FEMessage( MSG_BAD_PARM_REGISTER, (pointer)(parms + 1));
                    }
                }
            }
        } else {
        #if ( _TARGET & _TARG_PPC ) == 0
            parm->alignment = 1;
        #endif
            parm->regs = ParmReg( TypeClass( parm->name->tipe ),
                                   parm->name->tipe->length,
                                   parm->alignment,
                                   state );
            if( HW_CEqual( parm->regs, HW_EMPTY ) ) {
                parm->offset = ParmMem( parm->name->tipe->length, parm->alignment, state );
                push_no_pop = TRUE;
            }
        }
        ++parms;
        parm->num = parms;
        parm->ins = NULL;
        parm = parm->next;
    }
    ReverseParmNodeList( &call->parms );
    PushParms( call->parms, state );
    FPPushParms( call->parms, state );
    ParmIns( call->parms, state );
    ReverseParmNodeList( &call->parms );
    LinkParms( call_ins, &call->parms );
    if( call_ins->head.opcode == OP_CALL ) {
        call_ins->num_operands = 2;  /* special case for call so we*/
                                          /* ignore address in dataflow*/
        call_ins->operands[CALL_OP_USED] = AllocRegName( state->parm.used );
    } else {
        call_ins->operands[CALL_OP_USED] = AllocRegName( state->parm.used );
    }
    call_ins->operands[CALL_OP_POPS] = AllocS32Const( state->parm.offset );
    call_ins->zap = &AllocRegName( CallZap( state ) )->r;
    return( push_no_pop );
}

⌨️ 快捷键说明

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