bldcall.c

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

C
910
字号
/****************************************************************************
*
*                            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 a subroutine call.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "procdef.h"
#include "model.h"
#include "sysmacro.h"
#include "addrname.h"
#include "cgdefs.h"
#include "cgaux.h"
#include "zoiks.h"
#include "offset.h"
#include "feprotos.h"
#include "namelist.h"
#include "bldins.h"
#include "makeaddr.h"
#include "optask.h"
#include "bgcall.h"

extern  label_handle    AskForSymLabel(pointer,cg_class);
extern  instruction     *NewIns(int);
extern  type_def        *QParmType(sym_handle,sym_handle,type_def*);
extern  instruction     *MakeMove(name*,name*,type_class_def);
extern  instruction     *MakeUnary(opcode_defs,name*,name*,type_class_def);
extern  instruction     *MakeConvert(name*,name*,type_class_def,type_class_def);
extern  instruction     *MakeNop(void);
extern  hw_reg_set      ParmReg(type_class_def,type_length,type_length,call_state*);
extern  hw_reg_set      CallZap(call_state*);
extern  type_length     ParmMem(type_length,type_length,call_state*);
extern  hw_reg_set      ActualParmReg(hw_reg_set);
extern  type_class_def  CallState(aux_handle,type_def*,call_state*);
extern  hw_reg_set      ParmInLineReg(parm_state*);
extern  void            AddIns(instruction*);
extern  bool            CvtOk(type_class_def,type_class_def);
extern  void            CGFree(pointer);
extern  type_length     PushSize(type_length);
extern  type_class_def  ReturnClass(type_def*,call_attributes);
extern  type_class_def  InitCallState(type_def*);
extern  type_class_def  TypeClass(type_def*);
extern  void            DbgParmLoc(name_def*, sym_handle);
extern  void            DbgRetLoc(void);
extern  void            GenBlock(int,int);
extern  void            Generate(bool);
extern  void            PGBlip(char*);
extern  void            EnLink(label_handle,bool);
extern  void            UpdateReturn(call_state*,type_def*,type_class_def,aux_handle);
extern  void            FPPushParms(pn,call_state*);
extern  void            NewProc(int);
extern  name            *StReturn(an,type_def*,instruction**);
extern  hw_reg_set      StackReg(void);
extern  name            *SAllocIndex(name*,name*,type_length,type_class_def,type_length);
extern  name            *ScaleIndex(name*,name*,type_length,type_class_def,type_length,int,i_flags);
extern  instruction     *PushOneParm(instruction*,name*,type_class_def,type_length,call_state*);
extern  bool            IsVolatile(name*);
extern  void            TNZapParms(void);
extern  name            *AllocS32Const(signed_32);
extern  void            FPNotStack(name*);
extern  void            FreeIns(instruction*);
extern  void            PushInSameBlock(instruction*);
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
extern  void            TellObjVirtFuncRef(void *);
#endif
extern  void            TRAddParm(instruction*,instruction*);
extern  void            TRDeclareParm(instruction*);
extern  an              InsName(instruction*,type_def*);
extern  type_def        *ClassType(type_class_def);
extern  bool            SegIsCS( name * );
extern  pointer         FindAuxInfo( name *, aux_class );
extern  type_length     ParmAlignment( type_def * );
extern  void            SuffixIns( instruction *, instruction * );

extern  type_def        *TypeInteger;
extern  type_def        *TypeProcParm;
extern  type_def        *TypeNone;
extern  proc_def        *CurrProc;
extern  block           *CurrBlock;
extern  an              AddrList;
extern  type_length     MaxStack;
extern  name            *DummyIndex;
extern  bool            BlipsOn;

extern  type_class_def  AddCallBlock( sym_handle sym, type_def *tipe ) {
/***********************************************************************
    create the initial basic block for routine "sym", and call some
    other initialization routines.
*/

    type_class_def      class;

    if( BlipsOn ) {
        PGBlip( FEName( sym ) );
    }
    NewProc( FELexLevel( sym ) );
    EnLink( AskForSymLabel( sym, CG_FE ), FALSE );
    CurrProc->label = CurrBlock->label;
    CurrBlock->class |= BIG_LABEL;
    class = InitCallState( tipe );
    AddIns( MakeNop() );
    return( class );
}


extern  void    FreeCallNode( cn call )
/**************************************
    free up a call node
*/
{
    BGDone( call->name );
    CGFree( call->state->parm.table );
    _Free( call->state, sizeof( call_state ) );
    _Free( call, sizeof( call_node ) );
}


extern  cn      BGInitCall(an node,type_def *tipe,aux_handle aux) {
/******************************************************************
    initialize a call node for a call to routine "node", with type
    "tipe" and aux handle "aux". This also allocates the instruction
    to hold the call and parially initializes it.
*/

    cn                  new;
    type_class_def      class;
    name                *mem;
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
    void                *cookie;
#endif

    if( tipe->refno == T_DEFAULT ) {
        tipe = TypeInteger;
    }
    _Alloc( new, sizeof( call_node ) );
    _Alloc( new->state, sizeof( call_state ) );
    new->name = node;
    new->tipe = tipe;
    new->parms = NULL;
    new->ins = NewIns( 3 );
    if( node->format == NF_ADDR && node->class == CL_ADDR_GLOBAL ) {
        new->ins->head.opcode = OP_CALL;
        class = CallState( aux, tipe, new->state );
        mem = node->u.name;
        mem = (name *) SAllocMemory( mem->v.symbol, mem->v.offset, mem->m.memory_type,
                            mem->n.name_class, mem->n.size );
        node->u.name = mem;
    } else {
        new->ins->head.opcode = OP_CALL_INDIRECT;
        class = CallState( aux, tipe, new->state );
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
        cookie = FEAuxInfo( aux, VIRT_FUNC_REFERENCE );
        if( cookie != NULL ) TellObjVirtFuncRef( cookie );
#elif _TARGET & _TARG_PPC
        CurrProc->targ.toc_clobbered = TRUE;
#endif
    }
    new->ins->type_class = class;
    return( new );
}


extern  void    BGAddParm( cn call, an parm ) {
/**********************************************
    link a parm into the list of parms for a call node
*/

    pn          new;

    _Alloc( new, sizeof( parm_node ) );
    new->name = AddrToIns( parm );
    new->name->flags |= ADDR_OK_ACROSS_BLOCKS; /* always taken care of by BGCall*/
    new->next = call->parms;
    call->parms = new;
}


extern  void    BGAutoDecl( sym_handle sym, type_def *tipe ) {
/*************************************************************
    declare an automatic variable with name "sym" and type "tipe". This
    just creates the appropriate back end symbol table entry. (eg: N_TEMP)
*/

    BGDone( MakeAddrName( CG_FE, sym, tipe ) );
}

static  void    LinkParmIns( instruction *parm_def, instruction *ins ) {
/**********************************************************************/

    ins->operands[ 2 ] = (name *)parm_def; /* link them together*/
    parm_def->operands[ 2 ] = (name *)ins;
    ins->ins_flags |= INS_PARAMETER;
    parm_def->ins_flags |= INS_PARAMETER;
}

static  instruction *DoParmDef( name *result, type_class_def class ) {
/********************************************************************/

    instruction *parm_def;

    parm_def = NewIns( 0 );
    parm_def->head.opcode = OP_PARM_DEF;
    parm_def->type_class = class;
    parm_def->result = result;
    AddIns( parm_def );
    return( parm_def );
}

#if _TARGET & _TARG_RISC

#if _TARGET & _TARG_AXP
#define BASE_TYPE       U8
#define BASE_SIZE       8
#define BASE_ALIGNMENT  8
#else
#define BASE_TYPE       U4
#define BASE_SIZE       4
#define BASE_ALIGNMENT  4
#endif

static  name    *DoAlphaParmDecl( hw_reg_set reg, sym_handle sym, type_def *tipe, name *t2 ) {
/*********************************************************************************************
    N.B.: This was too weird to be incorporated in routine below.
    If we have a structure being passed by value on the Alpha, we start
    stuffing 8-byte chunks of data into any available parm registers, and
    put the remainder on the stack once those run out. In order to make
    this mess into an actual temp of the correct type, we create something
    which looks like:
        PARMDEF     => Ra
        MOV`     Ra => t2
        PARMDEF     => Rb
        MOV      Rb => t2+8
        ...
        PARMDEF     => t1
        MOV XX   t1 => t2+n
    which give us a real temp in t2, when all is said and done.
*/

    name                *t1;
    name                *reg_name;
    type_length         offset;
    instruction         *ins;
    instruction         *parm_def;
    type_length         len;

    sym = sym;
    offset = 0;
    len = _RoundUp( tipe->length, BASE_SIZE );
    t2->n.size = len;
    while( 1 ) {
        if( HW_CEqual( reg, HW_EMPTY ) ) {
            // put the rest of the structure on the stack
            t1 = AllocTemp( XX );
            t1->v.usage |= USE_IN_ANOTHER_BLOCK|NEEDS_MEMORY|HAS_MEMORY|USE_MEMORY;
            t1->n.size = len - offset;
            t1->t.temp_flags |= STACK_PARM;
            t1->t.location = ParmMem( t1->n.size, BASE_ALIGNMENT, &CurrProc->state );
            parm_def = DoParmDef( t1, XX );
            ins = MakeMove( t1, STempOffset( t2, offset, XX, t1->n.size ), XX );
            LinkParmIns( parm_def, ins );
            AddIns( ins );
            offset += t1->n.size;
        } else {
            reg_name = AllocRegName( reg );
            parm_def = DoParmDef( reg_name, BASE_TYPE );
            ins = MakeMove( reg_name, STempOffset( t2, offset, BASE_TYPE, BASE_SIZE ), BASE_TYPE );
            LinkParmIns( parm_def, ins );
            AddIns( ins );
            offset += BASE_SIZE;
        }
        if( offset >= len ) break;
        reg = ParmReg( BASE_TYPE, BASE_SIZE, BASE_ALIGNMENT, &CurrProc->state );
    }
    return( t2 );
}
#endif

⌨️ 快捷键说明

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