Search
lxdream.org :: lxdream/src/xlat/xir.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/xir.c
changeset 1012:0b8cc74ac83a
prev1011:fdd58619b760
author nkeynes
date Sun Apr 19 05:14:19 2009 +0000 (15 years ago)
branchxlat-refactor
permissions -rw-r--r--
last change Remove branch instructions and replace with direct modification of PC + EXIT
Add MIN/MAX instructions (for bound checks)
Implement x86_target_is_legal
Correct a few sh4 instructions
file annotate diff log raw
nkeynes@1006
     1
/**
nkeynes@1006
     2
 * $Id: xir.h 931 2008-10-31 02:57:59Z nkeynes $
nkeynes@1006
     3
 * 
nkeynes@1006
     4
 * This file provides support functions for the translation IR.
nkeynes@1006
     5
 *
nkeynes@1006
     6
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1006
     7
 *
nkeynes@1006
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1006
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1006
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1006
    11
 * (at your option) any later version.
nkeynes@1006
    12
 *
nkeynes@1006
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1006
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1006
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1006
    16
 * GNU General Public License for more details.
nkeynes@1006
    17
 */
nkeynes@1006
    18
nkeynes@1006
    19
#include <stdio.h>
nkeynes@1006
    20
#include <string.h>
nkeynes@1006
    21
#include <assert.h>
nkeynes@1006
    22
#include "xlat/xir.h"
nkeynes@1011
    23
#include "xlat/xlat.h" 
nkeynes@1006
    24
nkeynes@1006
    25
static const struct xir_symbol_entry *xir_symbol_table = NULL;
nkeynes@1006
    26
nkeynes@1006
    27
static const char *XIR_CC_NAMES[] = {
nkeynes@1006
    28
        "ov", "no", "uge", "ult", "ule", "ugt", "eq", "ne",
nkeynes@1006
    29
        "neg", "pos", "sge", "slt", "sle", "sgt" };
nkeynes@1011
    30
static const char XIR_TYPE_CODES[] = { 'l', 'q', 'f', 'd', 'v', 'm' };
nkeynes@1011
    31
nkeynes@1011
    32
const int XIR_OPERAND_SIZE[] = { 4, 8, 4, 8, 16, 64, (sizeof(void *)), 0 };
nkeynes@1011
    33
nkeynes@1006
    34
nkeynes@1006
    35
const struct xir_opcode_entry XIR_OPCODE_TABLE[] = { 
nkeynes@1006
    36
        { "NOP", OPM_NO },
nkeynes@1012
    37
        { "EXIT", OPM_NO | OPM_TERM },
nkeynes@1006
    38
        { "BARRIER", OPM_NO | OPM_CLB },
nkeynes@1006
    39
        { "DEC", OPM_RW_TW },
nkeynes@1006
    40
        { "LD", OPM_R | OPM_TW },
nkeynes@1006
    41
        { "ST", OPM_W | OPM_TR },
nkeynes@1006
    42
        { "RESTFLAGS", OPM_R | OPM_TW },
nkeynes@1006
    43
        { "SAVEFLAGS", OPM_W | OPM_TR },
nkeynes@1006
    44
        { "ENTER", OPM_R },
nkeynes@1006
    45
        { "CALL0", OPM_R | OPM_CLB },
nkeynes@1006
    46
        { "OCBI", OPM_R_EXC },
nkeynes@1006
    47
        { "OCBP", OPM_R_EXC },
nkeynes@1006
    48
        { "OCBWB", OPM_R_EXC },
nkeynes@1006
    49
        { "PREF", OPM_R_EXC },
nkeynes@1006
    50
     
nkeynes@1006
    51
        { "MOV", OPM_R_W },
nkeynes@1006
    52
        { "MOVQ", OPM_R_W|OPM_Q_Q },
nkeynes@1006
    53
        { "MOVV", OPM_R_W|OPM_V_V },
nkeynes@1006
    54
        { "MOVM", OPM_R_W|OPM_M_M },
nkeynes@1006
    55
        { "MOVSX8", OPM_R_W },
nkeynes@1006
    56
        { "MOVSX16", OPM_R_W },
nkeynes@1006
    57
        { "MOVSX32", OPM_R_W|OPM_I_Q },
nkeynes@1006
    58
        { "MOVZX8", OPM_R_W },
nkeynes@1006
    59
        { "MOVZX16", OPM_R_W },
nkeynes@1006
    60
        { "MOVZX32", OPM_R_W|OPM_I_Q },
nkeynes@1006
    61
        
nkeynes@1006
    62
        { "ADD", OPM_R_RW },
nkeynes@1006
    63
        { "ADDS", OPM_R_RW_TW }, 
nkeynes@1006
    64
        { "ADDC", OPM_R_RW_TR },
nkeynes@1006
    65
        { "ADDCS", OPM_R_RW_TRW },
nkeynes@1006
    66
        { "AND", OPM_R_RW },
nkeynes@1006
    67
        { "ANDS", OPM_R_RW_TW },
nkeynes@1006
    68
        { "CMP", OPM_R_R_TW },
nkeynes@1006
    69
        { "DIV", OPM_R_RW },
nkeynes@1006
    70
        { "DIVS", OPM_R_RW_TW },
nkeynes@1012
    71
        { "MAX", OPM_R_RW },
nkeynes@1012
    72
        { "MAXQ", OPM_R_RW },
nkeynes@1012
    73
        { "MIN", OPM_R_RW },
nkeynes@1012
    74
        { "MINQ", OPM_R_RW },
nkeynes@1006
    75
        { "MUL", OPM_R_RW },
nkeynes@1006
    76
        { "MULS", OPM_R_RW_TW },
nkeynes@1006
    77
        { "MULQ", OPM_R_RW|OPM_Q_Q },
nkeynes@1006
    78
        { "MULQS", OPM_R_RW_TW|OPM_Q_Q },
nkeynes@1006
    79
        { "NEG", OPM_R_W },
nkeynes@1006
    80
        { "NEGS", OPM_R_W_TW },
nkeynes@1006
    81
        { "NOT", OPM_R_W },
nkeynes@1006
    82
        { "NOTS", OPM_R_W_TW },
nkeynes@1006
    83
        { "OR", OPM_R_RW },
nkeynes@1006
    84
        { "ORS", OPM_R_RW_TW },
nkeynes@1006
    85
        { "RCL", OPM_R_RW_TRW },
nkeynes@1006
    86
        { "RCR", OPM_R_RW_TRW },
nkeynes@1006
    87
        { "ROL", OPM_R_RW },
nkeynes@1006
    88
        { "ROLS", OPM_R_RW_TW },
nkeynes@1006
    89
        { "ROR", OPM_R_RW },
nkeynes@1006
    90
        { "RORS", OPM_R_RW_TW },
nkeynes@1006
    91
        { "SAR", OPM_R_RW },
nkeynes@1006
    92
        { "SARS", OPM_R_RW_TW },
nkeynes@1006
    93
        { "SDIV", OPM_R_RW },
nkeynes@1006
    94
        { "SDIVS", OPM_R_RW_TW },
nkeynes@1006
    95
        { "SLL", OPM_R_RW },
nkeynes@1006
    96
        { "SLLS", OPM_R_RW_TW },
nkeynes@1006
    97
        { "SLR", OPM_R_RW },
nkeynes@1006
    98
        { "SLRS", OPM_R_RW_TW },
nkeynes@1006
    99
        { "SUB", OPM_R_RW },
nkeynes@1006
   100
        { "SUBS", OPM_R_RW_TW },
nkeynes@1006
   101
        { "SUBB", OPM_R_RW },
nkeynes@1006
   102
        { "SUBBS", OPM_R_RW_TRW },
nkeynes@1006
   103
        { "SHUFFLE", OPM_R_RW },
nkeynes@1006
   104
        { "TST", OPM_R_R_TW },
nkeynes@1006
   105
        { "XOR", OPM_R_RW },
nkeynes@1006
   106
        { "XORS", OPM_R_RW_TW },        
nkeynes@1006
   107
        
nkeynes@1006
   108
        { "ABSD", OPM_DR_DW },
nkeynes@1006
   109
        { "ABSF", OPM_FR_FW },
nkeynes@1006
   110
        { "ABSV", OPM_VR_VW },
nkeynes@1006
   111
        { "ADDD", OPM_DR_DRW },
nkeynes@1006
   112
        { "ADDF", OPM_FR_FRW },
nkeynes@1006
   113
        { "ADDV", OPM_VR_VRW },
nkeynes@1006
   114
        { "CMPD", OPM_DR_DR_TW },
nkeynes@1006
   115
        { "CMPF", OPM_FR_FR_TW },
nkeynes@1006
   116
        { "DIVD", OPM_DR_DRW },
nkeynes@1006
   117
        { "DIVF", OPM_FR_FRW },
nkeynes@1006
   118
        { "DIVV", OPM_VR_VRW },
nkeynes@1012
   119
        { "MAXD", OPM_DR_DRW },
nkeynes@1012
   120
        { "MAXF", OPM_FR_FRW },
nkeynes@1012
   121
        { "MAXV", OPM_VR_VRW },
nkeynes@1012
   122
        { "MIND", OPM_DR_DRW },
nkeynes@1012
   123
        { "MINF", OPM_FR_FRW },
nkeynes@1012
   124
        { "MINV", OPM_VR_VRW },
nkeynes@1006
   125
        { "MULD", OPM_DR_DRW },
nkeynes@1006
   126
        { "MULF", OPM_FR_FRW },
nkeynes@1006
   127
        { "MULV", OPM_VR_VRW },
nkeynes@1006
   128
        { "NEGD", OPM_DR_DW },
nkeynes@1006
   129
        { "NEGF", OPM_FR_FW },
nkeynes@1006
   130
        { "NEGV", OPM_VR_VW },
nkeynes@1006
   131
        { "SQRTD", OPM_DR_DW },
nkeynes@1006
   132
        { "SQRTF", OPM_FR_FW },
nkeynes@1006
   133
        { "SQRTV", OPM_VR_VW },
nkeynes@1006
   134
        { "RSQRTD", OPM_DR_DW },
nkeynes@1006
   135
        { "RSQRTF", OPM_FR_FW },
nkeynes@1006
   136
        { "RSQRTV", OPM_VR_VW },
nkeynes@1006
   137
        { "SUBD", OPM_DR_DRW },
nkeynes@1006
   138
        { "SUBF", OPM_FR_FRW },
nkeynes@1006
   139
        { "SUBV", OPM_VR_VRW },
nkeynes@1006
   140
nkeynes@1006
   141
        { "DTOF", OPM_R_W|OPM_D_F }, /* Round according to rounding mode */
nkeynes@1006
   142
        { "DTOI", OPM_R_W|OPM_D_I }, /* Truncate + saturate to signed 32-bits */
nkeynes@1006
   143
        { "FTOD", OPM_R_W|OPM_F_D }, /* Exact */
nkeynes@1006
   144
        { "FTOI", OPM_R_W|OPM_F_I }, /* Truncate + saturate to signed 32-bits */
nkeynes@1006
   145
        { "ITOD", OPM_R_W|OPM_I_D }, /* Exact */
nkeynes@1006
   146
        { "ITOF", OPM_R_W|OPM_I_F }, /* Round according to rounding mode */
nkeynes@1006
   147
nkeynes@1006
   148
        { "SINCOSF", OPM_FR_FRW },
nkeynes@1006
   149
nkeynes@1006
   150
        /* Compute the dot product of two vectors - the result is
nkeynes@1006
   151
         * stored in the last element of the target operand (and the
nkeynes@1006
   152
         * other elements are unchanged)
nkeynes@1006
   153
         */
nkeynes@1006
   154
        { "DOTPRODV", OPM_R_RW|OPM_V_V },
nkeynes@1006
   155
        /* Perform the matrix multiplication V * M and place the result
nkeynes@1006
   156
         * in V.
nkeynes@1006
   157
         */
nkeynes@1006
   158
        { "MATMULV", OPM_R_RW|OPM_V_M },
nkeynes@1006
   159
        
nkeynes@1006
   160
        { "LOAD.B", OPM_R_W_EXC },
nkeynes@1006
   161
        { "LOAD.BFW", OPM_R_W_EXC },
nkeynes@1006
   162
        { "LOAD.W", OPM_R_W_EXC },
nkeynes@1006
   163
        { "LOAD.L", OPM_R_W_EXC },
nkeynes@1006
   164
        { "LOAD.Q", OPM_R_W_EXC|OPM_I_Q },
nkeynes@1006
   165
        { "STORE.B", OPM_R_R_EXC },
nkeynes@1006
   166
        { "STORE.W", OPM_R_R_EXC },
nkeynes@1006
   167
        { "STORE.L", OPM_R_R_EXC },
nkeynes@1006
   168
        { "STORE.Q", OPM_R_R_EXC|OPM_I_Q },
nkeynes@1006
   169
        { "STORE.LCA", OPM_R_R_EXC },
nkeynes@1006
   170
nkeynes@1006
   171
        { "RAISE/ME", OPM_R_R | OPM_EXC },
nkeynes@1006
   172
        { "RAISE/MNE", OPM_R_R | OPM_EXC },
nkeynes@1006
   173
        
nkeynes@1011
   174
        /* Native/pointer operations */
nkeynes@1006
   175
        { "CALL/LUT", OPM_R_R | OPM_EXC },
nkeynes@1006
   176
        { "CALL1", OPM_R_R | OPM_CLB },
nkeynes@1006
   177
        { "CALLR", OPM_R_W | OPM_CLB },
nkeynes@1012
   178
        { "LOADPTRW", OPM_R_W | 0x060 },
nkeynes@1011
   179
        { "LOADPTRL", OPM_R_W | 0x060 },
nkeynes@1011
   180
        { "LOADPTRQ", OPM_R_W | 0x160 },
nkeynes@1011
   181
        { "XLAT", OPM_R_RW | 0x600 }, /* Xlat Rm, Rn - Read native [Rm+Rn] and store in Rn */ 
nkeynes@1006
   182
        
nkeynes@1006
   183
        { "ADDQSAT32", OPM_R_R | OPM_CLBT|OPM_Q_Q },
nkeynes@1006
   184
        { "ADDQSAT48", OPM_R_R | OPM_CLBT|OPM_Q_Q },
nkeynes@1006
   185
        { "CMP/STR", OPM_R_R_TW | OPM_CLBT },
nkeynes@1006
   186
        { "DIV1", OPM_R_RW_TRW | OPM_CLBT },
nkeynes@1006
   187
        { "SHAD", OPM_R_RW | OPM_CLBT },
nkeynes@1006
   188
        { "SHLD", OPM_R_RW | OPM_CLBT },
nkeynes@1006
   189
               
nkeynes@1006
   190
};
nkeynes@1006
   191
nkeynes@1011
   192
void xir_clear_basic_block( xir_basic_block_t xbb )
nkeynes@1006
   193
{
nkeynes@1011
   194
    xbb->next_temp_reg = 0;
nkeynes@1011
   195
    xir_alloc_temp_reg( xbb, XTY_LONG, -1 );
nkeynes@1011
   196
    xir_alloc_temp_reg( xbb, XTY_LONG, -1 );
nkeynes@1011
   197
    xir_alloc_temp_reg( xbb, XTY_LONG, -1 );
nkeynes@1011
   198
    xir_alloc_temp_reg( xbb, XTY_QUAD, -1 );
nkeynes@1011
   199
    xir_alloc_temp_reg( xbb, XTY_QUAD, -1 );
nkeynes@1012
   200
    xir_alloc_temp_reg( xbb, XTY_FLOAT, -1 );
nkeynes@1012
   201
    xir_alloc_temp_reg( xbb, XTY_DOUBLE, -1 );
nkeynes@1011
   202
}
nkeynes@1011
   203
nkeynes@1011
   204
uint32_t xir_alloc_temp_reg( xir_basic_block_t xbb, xir_type_t type, int home )
nkeynes@1011
   205
{
nkeynes@1011
   206
    assert( xbb->next_temp_reg <= MAX_TEMP_REGISTER );
nkeynes@1011
   207
    int reg = xbb->next_temp_reg++;
nkeynes@1011
   208
    xbb->temp_regs[reg].type = type;
nkeynes@1011
   209
    xbb->temp_regs[reg].home_register = home;
nkeynes@1011
   210
    return reg;
nkeynes@1006
   211
}
nkeynes@1006
   212
nkeynes@1006
   213
void xir_set_symbol_table( const struct xir_symbol_entry *symtab )
nkeynes@1006
   214
{
nkeynes@1006
   215
    xir_symbol_table = symtab;
nkeynes@1006
   216
}
nkeynes@1006
   217
nkeynes@1006
   218
const char *xir_lookup_symbol( const void *ptr ) 
nkeynes@1006
   219
{
nkeynes@1006
   220
    if( xir_symbol_table != NULL ) {
nkeynes@1006
   221
        const struct xir_symbol_entry *p;
nkeynes@1006
   222
        for( p = xir_symbol_table; p->name != NULL; p++ ) {
nkeynes@1006
   223
            if( p->ptr == ptr ) {
nkeynes@1006
   224
                return p->name;
nkeynes@1006
   225
            }
nkeynes@1006
   226
        }
nkeynes@1006
   227
    }
nkeynes@1006
   228
    return NULL;
nkeynes@1006
   229
}   
nkeynes@1006
   230
nkeynes@1011
   231
static int xir_snprint_operand( char *buf, int buflen, xir_basic_block_t xbb, xir_operand_t op, xir_type_t ty )
nkeynes@1006
   232
{
nkeynes@1006
   233
    const char *name;
nkeynes@1011
   234
    xir_temp_register_t tmp;
nkeynes@1011
   235
    
nkeynes@1011
   236
    switch( op->form ) {
nkeynes@1011
   237
    case IMMEDIATE_OPERAND:
nkeynes@1011
   238
        switch( ty ) {
nkeynes@1011
   239
        case XTY_LONG:
nkeynes@1011
   240
            return snprintf( buf, buflen, "$0x%x", op->value.i );
nkeynes@1011
   241
        case XTY_QUAD:
nkeynes@1011
   242
            return snprintf( buf, buflen, "$0x%lld", op->value.q );
nkeynes@1011
   243
        case XTY_FLOAT:
nkeynes@1011
   244
            return snprintf( buf, buflen, "%f", op->value.f );
nkeynes@1011
   245
        case XTY_DOUBLE:
nkeynes@1011
   246
            return snprintf( buf, buflen, "%f", op->value.f );
nkeynes@1011
   247
        case XTY_PTR:
nkeynes@1011
   248
            name = xir_lookup_symbol( op->value.p );
nkeynes@1011
   249
            if( name != NULL ) {
nkeynes@1011
   250
                return snprintf( buf, buflen, "*%s", name );
nkeynes@1011
   251
            } else {
nkeynes@1011
   252
                return snprintf( buf, buflen, "*%p", op->value.p );
nkeynes@1011
   253
            }
nkeynes@1011
   254
        default:
nkeynes@1011
   255
            return snprintf( buf, buflen, "ILLOP" );
nkeynes@1011
   256
        }
nkeynes@1011
   257
        break;
nkeynes@1011
   258
    case SOURCE_OPERAND:
nkeynes@1011
   259
        name = xbb->source->get_register_name(op->value.i, ty);
nkeynes@1006
   260
        if( name != NULL ) {
nkeynes@1011
   261
            return snprintf( buf, buflen, "%%%s", name );
nkeynes@1006
   262
        } else {
nkeynes@1011
   263
            return snprintf( buf, buflen, "%%src%d", op->value.i );
nkeynes@1006
   264
        }
nkeynes@1011
   265
        break;
nkeynes@1011
   266
    case TEMP_OPERAND:
nkeynes@1011
   267
        tmp = &xbb->temp_regs[op->value.i];
nkeynes@1011
   268
        if( tmp->home_register != -1 && 
nkeynes@1011
   269
            (name = xbb->source->get_register_name(tmp->home_register,ty)) != NULL ) {
nkeynes@1011
   270
            return snprintf( buf, buflen, "%%%s.%c%d", name,
nkeynes@1011
   271
                    XIR_TYPE_CODES[tmp->type], op->value.i );
nkeynes@1006
   272
        } else {
nkeynes@1011
   273
            return snprintf( buf, buflen, "%%tmp%c%d", 
nkeynes@1011
   274
                    XIR_TYPE_CODES[tmp->type], op->value.i );
nkeynes@1006
   275
        }
nkeynes@1011
   276
    case DEST_OPERAND:
nkeynes@1011
   277
        name = xbb->target->get_register_name(op->value.i, ty);
nkeynes@1011
   278
        if( name != NULL ) {
nkeynes@1011
   279
            return snprintf( buf, buflen, "%%%s", name );
nkeynes@1006
   280
        } else {
nkeynes@1011
   281
            return snprintf( buf, buflen, "%%dst%d", op->value.i );
nkeynes@1006
   282
        }
nkeynes@1006
   283
    default:
nkeynes@1006
   284
        return snprintf( buf, buflen, "ILLOP" );
nkeynes@1006
   285
    }
nkeynes@1006
   286
}
nkeynes@1006
   287
nkeynes@1011
   288
static void xir_print_instruction( FILE *out, xir_basic_block_t xbb, xir_op_t i )
nkeynes@1006
   289
{
nkeynes@1006
   290
    char operands[64] = "";
nkeynes@1006
   291
    
nkeynes@1011
   292
    if( i->operand[0].form != NO_OPERAND ) {
nkeynes@1011
   293
        int pos = xir_snprint_operand( operands, sizeof(operands), xbb, &i->operand[0],
nkeynes@1011
   294
                XOP_OPTYPE(i,0));
nkeynes@1011
   295
        if( i->operand[1].form != NO_OPERAND ) {
nkeynes@1006
   296
            strncat( operands, ", ", sizeof(operands)-pos );
nkeynes@1006
   297
            pos += 2;
nkeynes@1011
   298
            xir_snprint_operand( operands+pos, sizeof(operands)-pos, xbb, &i->operand[1],
nkeynes@1011
   299
                                 XOP_OPTYPE(i,1) );
nkeynes@1006
   300
        }
nkeynes@1006
   301
    }
nkeynes@1006
   302
    if( i->cond == CC_TRUE ) {
nkeynes@1006
   303
        fprintf( out, "%-9s %-30s", XIR_OPCODE_TABLE[i->opcode].name, operands );
nkeynes@1006
   304
    } else {
nkeynes@1006
   305
        char buf[16];
nkeynes@1006
   306
        snprintf( buf, 16, "%s%s", XIR_OPCODE_TABLE[i->opcode].name, XIR_CC_NAMES[i->cond] );
nkeynes@1006
   307
        fprintf( out, "%-9s %-30s", buf, operands );
nkeynes@1006
   308
    }
nkeynes@1006
   309
}
nkeynes@1006
   310
nkeynes@1006
   311
/**
nkeynes@1006
   312
 * Sanity check a block of IR to make sure that
nkeynes@1006
   313
 * operands match up with the expected values etc
nkeynes@1006
   314
 */
nkeynes@1011
   315
void xir_verify_block( xir_basic_block_t xbb, xir_op_t start, xir_op_t end )
nkeynes@1006
   316
{
nkeynes@1006
   317
    xir_op_t it;
nkeynes@1006
   318
    int flags_written = 0;
nkeynes@1006
   319
    for( it = start; it != NULL; it = it->next ) {
nkeynes@1006
   320
        assert( it != NULL && "Unexpected end of block" );
nkeynes@1006
   321
        assert( it->cond >= CC_TRUE && it->cond <= CC_SGT && "Invalid condition code" );
nkeynes@1006
   322
        if( XOP_HAS_0_OPERANDS(it) ) {
nkeynes@1011
   323
            assert( it->operand[0].form == NO_OPERAND && it->operand[1].form == NO_OPERAND );
nkeynes@1006
   324
        } else if( XOP_HAS_1_OPERAND(it) ) {
nkeynes@1011
   325
            assert( it->operand[0].form != NO_OPERAND && it->operand[1].form == NO_OPERAND );
nkeynes@1006
   326
        } else if( XOP_HAS_2_OPERANDS(it) ) {
nkeynes@1011
   327
            assert( it->operand[0].form != NO_OPERAND && it->operand[1].form != NO_OPERAND );
nkeynes@1006
   328
        }
nkeynes@1006
   329
        
nkeynes@1006
   330
        if( it->opcode == OP_ENTER ) {
nkeynes@1006
   331
            assert( it->prev == NULL && "Enter instruction must have no predecessors" );
nkeynes@1006
   332
            assert( it == start && "Enter instruction must occur at the start of the block" );
nkeynes@1011
   333
            assert( it->operand[0].form == IMMEDIATE_OPERAND && "Enter instruction must have an immediate operand" );
nkeynes@1006
   334
        } else if( it->opcode == OP_ST || it->opcode == OP_LD ) {
nkeynes@1006
   335
            assert( it->cond != CC_TRUE && "Opcode not permitted with True condition code" );
nkeynes@1006
   336
        }
nkeynes@1006
   337
        
nkeynes@1006
   338
        if( XOP_WRITES_OP1(it) ) {
nkeynes@1011
   339
            assert( XOP_IS_REG(it,0) &&  "Writable operand 1 requires a register" );
nkeynes@1006
   340
        }
nkeynes@1006
   341
        if( XOP_WRITES_OP2(it) ) {
nkeynes@1011
   342
            assert( XOP_IS_REG(it,1) && "Writable operand 2 requires a register" );
nkeynes@1006
   343
        }
nkeynes@1011
   344
nkeynes@1011
   345
        if( XOP_IS_SRC(it,0) ) {
nkeynes@1011
   346
            assert( XOP_REG(it,0) <= MAX_SOURCE_REGISTER && "Undefined source register" );
nkeynes@1011
   347
        } else if( XOP_IS_TMP(it,0) ) {
nkeynes@1011
   348
            assert( XOP_REG(it,0) < xbb->next_temp_reg && "Undefined temporary register" );
nkeynes@1011
   349
        } else if( XOP_IS_DST(it,0) ) {
nkeynes@1011
   350
            assert( XOP_REG(it,0) <= MAX_DEST_REGISTER && "Undefined target register" );
nkeynes@1011
   351
        }
nkeynes@1011
   352
        if( XOP_IS_SRC(it,1) ) {
nkeynes@1011
   353
            assert( XOP_REG(it,1) <= MAX_SOURCE_REGISTER && "Undefined source register" );
nkeynes@1011
   354
        } else if( XOP_IS_TMP(it,1) ) {
nkeynes@1011
   355
            assert( XOP_REG(it,1) < xbb->next_temp_reg && "Undefined temporary register" );
nkeynes@1011
   356
        } else if( XOP_IS_DST(it,1) ) {
nkeynes@1011
   357
            assert( XOP_REG(it,1) <= MAX_DEST_REGISTER && "Undefined target register" );
nkeynes@1011
   358
        }
nkeynes@1011
   359
nkeynes@1006
   360
        if( XOP_READS_FLAGS(it) ) {
nkeynes@1006
   361
            assert( flags_written && "Flags used without prior definition in block" );
nkeynes@1006
   362
        }
nkeynes@1006
   363
        if( XOP_WRITES_FLAGS(it) ) {
nkeynes@1006
   364
            flags_written = 1;
nkeynes@1006
   365
        }
nkeynes@1006
   366
        
nkeynes@1006
   367
        if( XOP_HAS_EXCEPTION(it) ) {
nkeynes@1006
   368
            assert( it->exc != NULL && "Missing exception block" );
nkeynes@1006
   369
            assert( it->exc->prev == it && "Exception back-link broken" );
nkeynes@1011
   370
            xir_verify_block( xbb, it->exc, NULL ); // Verify exception sub-block
nkeynes@1006
   371
        } else {
nkeynes@1006
   372
            assert( it->exc == NULL && "Unexpected exception block" );
nkeynes@1006
   373
        }
nkeynes@1006
   374
        if( XOP_IS_TERMINATOR(it) ) {
nkeynes@1006
   375
            assert( it->next == NULL && "Unexpected next instruction on terminator" );
nkeynes@1006
   376
        } else {
nkeynes@1006
   377
            assert( it->next != NULL && "Missing terminator instruction at end of block" );
nkeynes@1006
   378
            assert( it->next->prev == it && "Linked-list chain broken" );
nkeynes@1006
   379
        }
nkeynes@1006
   380
        if( it == end )
nkeynes@1006
   381
            break;
nkeynes@1006
   382
    }
nkeynes@1006
   383
}
nkeynes@1006
   384
nkeynes@1011
   385
xir_op_t xir_append_op2( xir_basic_block_t xbb, int op, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 )
nkeynes@1006
   386
{
nkeynes@1006
   387
    xbb->ir_ptr->opcode = op;
nkeynes@1006
   388
    xbb->ir_ptr->cond = CC_TRUE;
nkeynes@1011
   389
    xbb->ir_ptr->operand[0].form = arg0form;
nkeynes@1006
   390
    xbb->ir_ptr->operand[0].value.i = arg0;
nkeynes@1011
   391
    xbb->ir_ptr->operand[1].form = arg1form;
nkeynes@1006
   392
    xbb->ir_ptr->operand[1].value.i = arg1;
nkeynes@1006
   393
    xbb->ir_ptr->exc = NULL;
nkeynes@1006
   394
    xbb->ir_ptr->next = xbb->ir_ptr+1;
nkeynes@1006
   395
    (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
nkeynes@1006
   396
    return xbb->ir_ptr++;
nkeynes@1006
   397
}
nkeynes@1006
   398
nkeynes@1011
   399
xir_op_t xir_append_op2cc( xir_basic_block_t xbb, int op, xir_cc_t cc, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 )
nkeynes@1006
   400
{
nkeynes@1006
   401
    xbb->ir_ptr->opcode = op;
nkeynes@1006
   402
    xbb->ir_ptr->cond = cc;
nkeynes@1011
   403
    xbb->ir_ptr->operand[0].form = arg0form;
nkeynes@1006
   404
    xbb->ir_ptr->operand[0].value.i = arg0;
nkeynes@1011
   405
    xbb->ir_ptr->operand[1].form = arg1form;
nkeynes@1006
   406
    xbb->ir_ptr->operand[1].value.i = arg1;
nkeynes@1006
   407
    xbb->ir_ptr->exc = NULL;
nkeynes@1006
   408
    xbb->ir_ptr->next = xbb->ir_ptr+1;
nkeynes@1006
   409
    (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
nkeynes@1006
   410
    return xbb->ir_ptr++;
nkeynes@1006
   411
}
nkeynes@1006
   412
nkeynes@1011
   413
xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1form, uint32_t arg1 )
nkeynes@1006
   414
{
nkeynes@1006
   415
    xbb->ir_ptr->opcode = op;
nkeynes@1006
   416
    xbb->ir_ptr->cond = CC_TRUE;
nkeynes@1011
   417
    xbb->ir_ptr->operand[0].form = IMMEDIATE_OPERAND;
nkeynes@1006
   418
    xbb->ir_ptr->operand[0].value.i = imm1;
nkeynes@1011
   419
    xbb->ir_ptr->operand[1].form = arg1form;
nkeynes@1006
   420
    xbb->ir_ptr->operand[1].value.i = arg1;
nkeynes@1006
   421
    xbb->ir_ptr->exc = NULL;
nkeynes@1006
   422
    xbb->ir_ptr->next = xbb->ir_ptr+1;
nkeynes@1006
   423
    (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
nkeynes@1006
   424
    return xbb->ir_ptr++;
nkeynes@1006
   425
}
nkeynes@1006
   426
nkeynes@1011
   427
xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1form, uint32_t arg1 )
nkeynes@1006
   428
{
nkeynes@1006
   429
    xbb->ir_ptr->opcode = op;
nkeynes@1006
   430
    xbb->ir_ptr->cond = CC_TRUE;
nkeynes@1011
   431
    xbb->ir_ptr->operand[0].form = IMMEDIATE_OPERAND;
nkeynes@1006
   432
    xbb->ir_ptr->operand[0].value.p = arg0;
nkeynes@1011
   433
    xbb->ir_ptr->operand[1].form = arg1form;
nkeynes@1006
   434
    xbb->ir_ptr->operand[1].value.i = arg1;
nkeynes@1006
   435
    xbb->ir_ptr->exc = NULL;
nkeynes@1006
   436
    xbb->ir_ptr->next = xbb->ir_ptr+1;
nkeynes@1006
   437
    (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
nkeynes@1006
   438
    return xbb->ir_ptr++;
nkeynes@1006
   439
}
nkeynes@1006
   440
nkeynes@1006
   441
void xir_insert_op( xir_op_t op, xir_op_t before )
nkeynes@1006
   442
{
nkeynes@1006
   443
    op->prev = before->prev;
nkeynes@1006
   444
    op->next = before;
nkeynes@1006
   445
    before->prev->next = op;
nkeynes@1006
   446
    before->prev = op;
nkeynes@1006
   447
}
nkeynes@1006
   448
nkeynes@1006
   449
void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before )
nkeynes@1006
   450
{
nkeynes@1006
   451
    start->prev = before->prev;
nkeynes@1006
   452
    end->next = before;
nkeynes@1006
   453
    before->prev->next = start;
nkeynes@1006
   454
    before->prev = end;
nkeynes@1006
   455
}
nkeynes@1006
   456
nkeynes@1006
   457
void xir_remove_op( xir_op_t op )
nkeynes@1006
   458
{
nkeynes@1006
   459
    if( op->next != NULL ) {
nkeynes@1006
   460
        op->next->prev = op->prev;
nkeynes@1006
   461
    }
nkeynes@1006
   462
    if( op->prev != NULL ) {
nkeynes@1006
   463
        if( op->prev->next == op ) {
nkeynes@1006
   464
            op->prev->next = op->next;
nkeynes@1006
   465
        } else {
nkeynes@1006
   466
            assert( op->prev->exc == op );
nkeynes@1006
   467
            op->prev->exc = op->next;
nkeynes@1006
   468
        }
nkeynes@1006
   469
    }
nkeynes@1006
   470
}
nkeynes@1006
   471
nkeynes@1011
   472
void xir_print_block( FILE *out, xir_basic_block_t xbb, xir_op_t start, xir_op_t end )
nkeynes@1006
   473
{
nkeynes@1006
   474
    xir_op_t it = start;
nkeynes@1006
   475
    xir_op_t exc = NULL;
nkeynes@1006
   476
    
nkeynes@1006
   477
    while( it != NULL ) {
nkeynes@1006
   478
        if( it->exc ) {
nkeynes@1006
   479
            while( exc ) {
nkeynes@1006
   480
                fprintf( out, "%40c   ", ' ' );
nkeynes@1011
   481
                xir_print_instruction( out, xbb, exc );
nkeynes@1006
   482
                fprintf( out, "\n" );
nkeynes@1006
   483
                exc = exc->next;
nkeynes@1006
   484
            }
nkeynes@1006
   485
            exc = it->exc;
nkeynes@1006
   486
        }
nkeynes@1011
   487
        xir_print_instruction( out, xbb, it );
nkeynes@1006
   488
        if( exc ) {
nkeynes@1006
   489
            if( it->exc ) {
nkeynes@1006
   490
                fprintf( out, "=> " );
nkeynes@1006
   491
            } else {
nkeynes@1006
   492
                fprintf( out, "   " );
nkeynes@1006
   493
            }
nkeynes@1011
   494
            xir_print_instruction( out, xbb, exc );
nkeynes@1006
   495
            exc = exc->next;
nkeynes@1006
   496
        }
nkeynes@1006
   497
        fprintf( out, "\n" );
nkeynes@1006
   498
        if( it == end )
nkeynes@1006
   499
            break;
nkeynes@1006
   500
        it = it->next;
nkeynes@1006
   501
    }
nkeynes@1006
   502
}
nkeynes@1006
   503
nkeynes@1011
   504
void xir_dump_block( xir_basic_block_t xbb )
nkeynes@1006
   505
{
nkeynes@1011
   506
    xir_print_block( stdout, xbb, xbb->ir_begin, xbb->ir_end );
nkeynes@1006
   507
}
.