Esempio n. 1
0
static  name    *GetNTTLSDataRef( instruction *ins, name *op, type_class_def tipe )
/**********************************************************************************
    Emit instructions to load allow a reference to op (a piece of
    TLS data) and return the resulting index name.
*/
{
    name                *tls_index;
    name                *tls_array;
    name                *t1;
    name                *t2;
    name                *t3;
    name                *temp_index;
    name                *result_index;
    instruction         *new_ins;

    tls_index = RTMemRef( RT_TLS_INDEX );
    tls_array = RTMemRef( RT_TLS_ARRAY );
    t1 = AllocTemp( WD );
    t2 = AllocTemp( WD );
    t3 = AllocTemp( WD );
    new_ins = MakeMove( tls_array, t1, WD );
    AddSegOverride( new_ins, HW_FS );
    PrefixIns( ins, new_ins );
    new_ins = MakeMove( tls_index, t2, WD );
    PrefixIns( ins, new_ins );
    new_ins = MakeBinary( OP_MUL, t2, AllocS32Const( 4 ), t2, WD );
    PrefixIns( ins, new_ins );
    new_ins = MakeBinary( OP_ADD, t1, t2, t1, WD );
    PrefixIns( ins, new_ins );
    temp_index = AllocIndex( t1, NULL, 0, WD );
    new_ins = MakeMove( temp_index, t3, WD );
    PrefixIns( ins, new_ins );
    result_index = ScaleIndex( t3, op, op->v.offset, tipe, TypeClassSize[ tipe ], 0, 0 );
    return( result_index );
}
Esempio n. 2
0
instruction      *rFIXSHIFT( instruction *ins )
/*********************************************/
{
    instruction         *new_ins;
#ifndef NDEBUG
    signed_32           shift_count;
#endif

    /* Fix up shift instructions that try to shift by too large amounts. This
     * can happen when optimizer merges adjacent shift instructions. Arithmetic
     * rights shifts must never exceed (REGISTER_BITS - 1), logical shifts can
     * be replaced with loads of zero constant.
     */
#ifndef NDEBUG
    assert( ins->operands[1]->n.class == N_CONSTANT );
    shift_count = ins->operands[1]->c.lo.int_value;
    assert( shift_count >= REG_SIZE * 8 );
#endif
    if( ins->head.opcode == OP_RSHIFT && Signed[ins->type_class] == ins->type_class ) {
        ins->operands[1] = AllocS32Const( REG_SIZE * 8 - 1 );
        return( ins );
    } else {
        new_ins = MoveConst( 0, ins->result, ins->type_class );
        DupSeg( ins, new_ins );
        ReplIns( ins, new_ins );
        return( new_ins );
    }
}
Esempio n. 3
0
instruction      *rCHANGESHIFT( instruction *ins )
/************************************************/
{
    signed_32   shift_count;

    shift_count = ins->operands[1]->c.lo.int_value;
    assert( shift_count >= 0 );
    ins->operands[1] = AllocS32Const( shift_count & ( ( WORD_SIZE * 8 ) - 1 ) );
    return( ins );
}
Esempio n. 4
0
static  void    Far16Parms( cn call ) {
/*************************************/

    instruction         *ins;
    type_length         parm_size;
    pn                  parm, next;
    instruction         *call_ins;
    name                *eax;
    name                *ecx;
    name                *esi;
    label_handle        lbl;
    type_length         offset;
    name                *parmlist;
    call_state          *state;
    rt_class            rtindex;

    call_ins = call->ins;
    parm_size = 0;
    state = call->state;
    for( parm = call->parms; parm != NULL; parm = parm->next ) {
        parm_size += _RoundUp( parm->name->tipe->length, 2 );
    }
    parmlist = SAllocTemp( XX, parm_size );
    parmlist->v.usage |= NEEDS_MEMORY | USE_IN_ANOTHER_BLOCK | USE_ADDRESS;
    offset = 0;
    for( parm = call->parms; parm != NULL; parm = parm->next ) {
        parm->name->u.i.ins->result = STempOffset( parmlist, offset,
                                                 TypeClass( parm->name->tipe ),
                                                 parm->name->tipe->length );
        offset += _RoundUp( parm->name->tipe->length, 2 );
    }
    for( parm = call->parms; parm != NULL; parm = next ) {
        next = parm->next;
        parm->name->format = NF_ADDR;   /* so instruction doesn't get freed! */
        BGDone( parm->name );
        CGFree( parm );
    }
    eax = AllocRegName( HW_EAX );
    ecx = AllocRegName( HW_ECX );
    esi = AllocRegName( HW_ESI );
    HW_TurnOn( state->parm.used, eax->r.reg );
    HW_TurnOn( state->parm.used, ecx->r.reg );
    HW_TurnOn( state->parm.used, esi->r.reg );
    ins = MakeMove( AllocS32Const( parm_size ), ecx, WD );
    AddIns( ins );
    ins = MakeUnary( OP_LA, parmlist, esi, WD );
    AddIns( ins );
    if( ins->head.opcode == OP_CALL ) {
        ins = MakeUnary( OP_LA, call->name->u.n.name, eax, WD );
    } else {
        ins = MakeMove( GenIns( call->name ), eax, WD );
        call_ins->head.opcode = OP_CALL;
    }
    call_ins->num_operands = 2;
    AddIns( ins );
    if( call_ins->type_class == XX ) {
        if( state->attr & ROUTINE_ALLOCS_RETURN ) {
            rtindex = RT_Far16Cdecl;
        } else {
            rtindex = RT_Far16Pascal;
        }
    } else {
        rtindex = RT_Far16Func;
    }
    lbl = RTLabel( rtindex );
    call->name->u.n.name = AllocMemory( lbl, 0, CG_LBL, WD );
    call_ins->flags.call_flags |= CALL_FAR16 | CALL_POPS_PARMS;
    call_ins->operands[CALL_OP_USED] = AllocRegName( state->parm.used );
    call_ins->operands[CALL_OP_POPS] = AllocS32Const( 0 );
    call_ins->zap = &call_ins->operands[CALL_OP_USED]->r;
}
Esempio n. 5
0
an      BGCall( cn call, bool use_return, bool in_line )
/******************************************************/
{
    instruction         *call_ins;
    call_state          *state;
    name                *ret_ptr = NULL;
    name                *result;
    name                *temp;
    name                *reg_name;
    instruction         *ret_ins = NULL;
    hw_reg_set          return_reg;
    hw_reg_set          zap_reg;

    if( call->name->tipe == TypeProcParm ) {
        SaveDisplay( OP_PUSH );
    }

    state = call->state;
    result = BGNewTemp( call->tipe );
    call_ins = call->ins;

/*   If we have a return value that won't fit in a register*/
/*   pass a pointer to result as the first parm*/

    if( call_ins->type_class == XX ) {
        if( _RoutineIsFar16( state->attr ) ) {
            if( state->attr & ROUTINE_ALLOCS_RETURN ) {
                HW_CAsgn( state->return_reg, HW_EAX );
            } else {
                HW_CAsgn( state->return_reg, HW_EBX );
            }
        }
        if( ( state->attr & ROUTINE_ALLOCS_RETURN ) == 0 ) {
            if( HW_CEqual( state->return_reg, HW_EMPTY ) ) {
                ret_ptr = AllocTemp( WD );
            } else {
                ret_ptr = AllocRegName( state->return_reg );
            }
            ret_ins = MakeUnary( OP_LA, result, ret_ptr, WD );
            HW_TurnOn( state->parm.used, state->return_reg );
            call_ins->flags.call_flags |= CALL_RETURNS_STRUCT;
        }
    }
    if( _IsTargetModel(FLOATING_DS) && (state->attr&ROUTINE_NEEDS_DS_LOADED) ) {
        HW_CTurnOn( state->parm.used, HW_DS );
    }
    if( _RoutineIsFar16( state->attr ) ) {
#if _TARGET & _TARG_80386
        Far16Parms( call );
#endif
    } else {
        if( AssgnParms( call, in_line ) ) {
            if( state->attr & ROUTINE_REMOVES_PARMS ) {
                call_ins->flags.call_flags |= CALL_POPS_PARMS;
            }
        }
    }

    if( state->attr & (ROUTINE_MODIFIES_NO_MEMORY | ROUTINE_NEVER_RETURNS) ) {
        /* a routine that never returns can not write any memory as far
            as this routine is concerned */
        call_ins->flags.call_flags |= CALL_WRITES_NO_MEMORY;
    }
    if( state->attr & ROUTINE_READS_NO_MEMORY ) {
        call_ins->flags.call_flags |= CALL_READS_NO_MEMORY;
    }
    if( state->attr & ROUTINE_NEVER_RETURNS ) {
        call_ins->flags.call_flags |= CALL_ABORTS;
    }
    if( _RoutineIsInterrupt( state->attr ) ) {
        call_ins->flags.call_flags |= CALL_INTERRUPT | CALL_POPS_PARMS;
    }
    if( !use_return ) {
        call_ins->flags.call_flags |= CALL_IGNORES_RETURN;
    }
    if( call_ins->type_class == XX ) {
        reg_name = AllocRegName( state->return_reg );
        if( state->attr & ROUTINE_ALLOCS_RETURN ) {
            call_ins->result = reg_name;
            AddCall( call_ins, call );
            if( use_return ) {
                temp = AllocTemp( WD ); /* assume near pointer*/
                AddIns( MakeMove( reg_name, temp, WD ) );
                temp = SAllocIndex( temp, NULL, 0,
                                    result->n.type_class, call->tipe->length );
                AddIns( MakeMove( temp, result, result->n.type_class ) );
            }
        } else {
            call_ins->result = result;
            AddIns( ret_ins );
            if( HW_CEqual( state->return_reg, HW_EMPTY ) ) {
                AddIns( MakeUnary( OP_PUSH, ret_ptr, NULL, WD ) );
                state->parm.offset += TypeClassSize[WD];
                call_ins->operands[CALL_OP_POPS] =
                        AllocS32Const( call_ins->operands[CALL_OP_POPS]->c.lo.int_value + TypeClassSize[WD] );
                if( state->attr & ROUTINE_REMOVES_PARMS ) {
                    call_ins->flags.call_flags |= CALL_POPS_PARMS;
                }
            }
            AddCall( call_ins, call );
        }
    } else {
        return_reg = state->return_reg;
        zap_reg = call_ins->zap->reg;
        HW_CTurnOn( zap_reg, HW_FLTS );
        HW_OnlyOn( return_reg, zap_reg );
        call_ins->result = AllocRegName( return_reg );
        reg_name = AllocRegName( state->return_reg );
        AddCall( call_ins, call );
        if( use_return ) {
            ret_ins = MakeMove( reg_name, result, result->n.type_class );
            if( HW_COvlap( reg_name->r.reg, HW_FLTS ) ) {
                ret_ins->stk_entry = 1;
                ret_ins->stk_exit = 0;
            }
            AddIns( ret_ins );
        }
    }
    if( state->parm.offset != 0 && ( state->attr & ROUTINE_REMOVES_PARMS ) == 0 ) {
        reg_name = AllocRegName( HW_SP );
        AddIns( MakeBinary( OP_ADD, reg_name,
                AllocS32Const( state->parm.offset ), reg_name, WD ) );
    }
    return( MakeTempAddr( result ) );
}
Esempio n. 6
0
static  bool    FindFlowOut( block *blk )
/***************************************/
{
    signed_32           false_cons;
    signed_32           true_cons;
    instruction         *ins;
    instruction         *ins0;
    instruction         *ins1;
    block               *true;
    block               *false;
    block               *join;
    block_edge          *new_edge;
    bool                reverse;
    name                *u4temp;
    name                *temp;
    name                *result;
    type_class_def      class;
    opcode_defs         oc;

    ins = blk->ins.hd.prev;
    while( !_OpIsCondition( ins->head.opcode ) ) {
        ins = ins->head.prev;
    }
    if( !isNiceCondIns( ins ) )
        return( FALSE );
    if( TypeClassSize[ ins->type_class ] > WORD_SIZE )
        return( FALSE );
    true = blk->edge[ _TrueIndex( ins ) ].destination.u.blk;
    if( true->inputs != 1 )
        return( FALSE );
    if( true->targets != 1 )
        return( FALSE );

    false = blk->edge[ _FalseIndex( ins ) ].destination.u.blk;
    if( false->inputs != 1 )
        return( FALSE );
    if( false->targets != 1 )
        return( FALSE );

    join = false->edge[0].destination.u.blk;
    if( join != true->edge[0].destination.u.blk )
        return( FALSE );
    if( join->inputs != 2 )
        return( FALSE );
    if( join->class & UNKNOWN_DESTINATION )
        return( FALSE );

    ins0 = SetToConst( false, &false_cons );
    if( ins0 == NULL )
        return( FALSE );
    ins1 = SetToConst( true, &true_cons );
    if( ins1 == NULL )
        return( FALSE );
    if( true_cons - false_cons == -1 ) {
        true_cons = false_cons;
        false_cons = true_cons - 1;
        reverse = TRUE;
    } else {
        if( true_cons - false_cons != 1 )
            return( FALSE );
        reverse = FALSE;
    }
    result = ins0->result;
    if( result != ins1->result )
        return( FALSE );
    class = ins0->type_class;
    if( class != ins1->type_class )
        return( FALSE );

    oc = ins->head.opcode;
    if( oc == OP_CMP_GREATER || oc == OP_CMP_GREATER_EQUAL )
        reverse = !reverse;

    /* Replace 'x <= const' with 'x < const + 1' */
    if( oc == OP_CMP_LESS_EQUAL || oc == OP_CMP_GREATER_EQUAL ) {
        signed_32           value;
        name                *op1;

        op1 = ins->operands[1];
        assert( op1->n.class == N_CONSTANT && op1->c.const_type == CONS_ABSOLUTE );
        value = op1->c.int_value;
        if( oc == OP_CMP_LESS_EQUAL )
            value += 1;
        else
            value -= 1;
        ins->operands[1] = AllocS32Const( value );
    }
Esempio n. 7
0
static  void    ExpandTlsOp( instruction *ins, name **pop )
/**********************************************************
    If *pop is a ref to a piece of thread-local data, replace
    it by a ref to an index [t1] and prepend the magic sequence
    to get the address of a piece of tls data to the instruction.
    Here is the sequence to access variable foo:
        mov fs:__tls_array -> t1
        mov __tls_index -> t2
        mov t2 * 4 -> t2
        add t1, t2 -> t1
        mov [ t1 ] -> t3
        mov foo[ t3 ] -> result
*/
{
    fe_attr             attr;
    name                *op;
    name                *temp;
    name                *tls_data;
    name                *index;
    name                *base;
    instruction         *new_ins;

    op = *pop;
    switch( op->n.class ) {
    case N_MEMORY:
        if( op->m.memory_type == CG_FE ) {
            attr = FEAttr( op->v.symbol );
            if( ( attr & FE_THREAD_DATA ) != 0 ) {
                *pop = GetTLSDataRef( ins, op, _OpClass(ins) );
            }
        }
        break;
    case N_INDEXED:
        // gotta check for the base being one of these stupid TLS things
        if( op->i.base != NULL && ( op->i.index_flags & X_FAKE_BASE ) == 0 ) {
            base = op->i.base;
            if( base->n.class != N_MEMORY || base->m.memory_type != CG_FE ) break;
            attr = FEAttr( base->v.symbol );
            if( ( attr & FE_THREAD_DATA ) == 0 ) break;
            tls_data = GetTLSDataRef( ins, base, _OpClass(ins) );
            temp = AllocTemp( WD );
            new_ins = MakeUnary( OP_LA, tls_data, temp, WD );
            PrefixIns( ins, new_ins );
            index = op->i.index;
            if( op->i.scale != 0 ) {
                const signed_32 values[] = { 1, 2, 4, 8, 16 };
                if( op->i.scale > 4 ) _Zoiks( ZOIKS_134 );
                index = AllocTemp( WD );
                new_ins = MakeBinary( OP_MUL, op->i.index,
                                AllocS32Const( values[ op->i.scale ] ),
                                index, WD );
                PrefixIns( ins, new_ins );
            }
            new_ins = MakeBinary( OP_ADD, temp, index, temp, WD );
            PrefixIns( ins, new_ins );
            *pop = ScaleIndex( temp, NULL, 0,
                            _OpClass(ins),
                            TypeClassSize[ _OpClass(ins) ],
                            0, 0 );
        }
        break;
    }