Search
lxdream.org :: lxdream/src/xlat/target.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/target.c
changeset 1006:3a169c224c12
author nkeynes
date Tue Apr 07 10:55:03 2009 +0000 (15 years ago)
branchxlat-refactor
permissions -rw-r--r--
last change Commit current work-in-progress to xlat-refactor branch
file annotate diff log raw
nkeynes@1006
     1
/**
nkeynes@1006
     2
 * $Id: target.c 931 2008-10-31 02:57:59Z nkeynes $
nkeynes@1006
     3
 * 
nkeynes@1006
     4
 * Target code-generation support - provides a generic harness around the raw
nkeynes@1006
     5
 * (machine-specific) code emitter.
nkeynes@1006
     6
 *
nkeynes@1006
     7
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1006
     8
 *
nkeynes@1006
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@1006
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@1006
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1006
    12
 * (at your option) any later version.
nkeynes@1006
    13
 *
nkeynes@1006
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@1006
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1006
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1006
    17
 * GNU General Public License for more details.
nkeynes@1006
    18
 */
nkeynes@1006
    19
nkeynes@1006
    20
#include <stdlib.h>
nkeynes@1006
    21
nkeynes@1006
    22
#include "lxdream.h"
nkeynes@1006
    23
#include "xlat/xir.h"
nkeynes@1006
    24
#include "xlat/machine.h"
nkeynes@1006
    25
nkeynes@1006
    26
#define DEFAULT_FIXUP_TABLE_SIZE 4096
nkeynes@1006
    27
#define ALIGN32(p) p += ((-(uintptr_t)p)&0x03)
nkeynes@1006
    28
#define ALIGN64(p) p += ((-(uintptr_t)p)&0x07)
nkeynes@1006
    29
nkeynes@1006
    30
/**
nkeynes@1006
    31
 * Currently we use a single static target_data so that we can reuse the 
nkeynes@1006
    32
 * allocated memory (and we only do one codegen at a time anyway). However
nkeynes@1006
    33
 * we keep this private so that other modules can't assume there's only one TD.
nkeynes@1006
    34
 */
nkeynes@1006
    35
static struct target_data TD; 
nkeynes@1006
    36
nkeynes@1006
    37
/**
nkeynes@1006
    38
 * Add a new fixup without setting a target value
nkeynes@1006
    39
 */
nkeynes@1006
    40
static target_fixup_t target_add_fixup( target_data_t td, int type, void *location ) 
nkeynes@1006
    41
{
nkeynes@1006
    42
    if( td->fixup_table_posn == td->fixup_table_size ) {
nkeynes@1006
    43
        td->fixup_table_size <<= 1;
nkeynes@1006
    44
        td->fixup_table = realloc(td->fixup_table, td->fixup_table_size * sizeof(struct target_fixup_struct));
nkeynes@1006
    45
        assert( td->fixup_table != NULL );
nkeynes@1006
    46
    }
nkeynes@1006
    47
    target_fixup_t fixup = &td->fixup_table[td->fixup_table_posn++];
nkeynes@1006
    48
    fixup->fixup_type = type | TARGET_FIXUP_CONST32;
nkeynes@1006
    49
    fixup->fixup_offset = ((uint8_t *)location) - (uint8_t *)&td->block->code[0];
nkeynes@1006
    50
    return fixup;
nkeynes@1006
    51
}    
nkeynes@1006
    52
nkeynes@1006
    53
void target_add_const32_fixup( target_data_t td, int mode, void *location, uint32_t i )
nkeynes@1006
    54
{
nkeynes@1006
    55
    target_add_fixup(td, mode|TARGET_FIXUP_CONST32, location)->value.i = i;
nkeynes@1006
    56
}
nkeynes@1006
    57
nkeynes@1006
    58
void target_add_const64_fixup( target_data_t td, int mode, void *location, uint64_t q )
nkeynes@1006
    59
{
nkeynes@1006
    60
    target_add_fixup(td, mode|TARGET_FIXUP_CONST64, location)->value.q = q;
nkeynes@1006
    61
}
nkeynes@1006
    62
nkeynes@1006
    63
void target_add_raise_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
nkeynes@1006
    64
{
nkeynes@1006
    65
    target_add_fixup(td, mode|TARGET_FIXUP_RAISE, location)->value.exc = exc;
nkeynes@1006
    66
}
nkeynes@1006
    67
nkeynes@1006
    68
void target_add_raiseext_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
nkeynes@1006
    69
{
nkeynes@1006
    70
    target_add_fixup(td, mode|TARGET_FIXUP_RAISEEXT, location)->value.exc = exc;
nkeynes@1006
    71
}
nkeynes@1006
    72
nkeynes@1006
    73
void target_add_offset_fixup( target_data_t td, int type, void *location, uint32_t off )
nkeynes@1006
    74
{
nkeynes@1006
    75
    target_add_fixup(td, mode|TARGET_FIXUP_OFFSET, location)->target_offset = off;
nkeynes@1006
    76
}
nkeynes@1006
    77
nkeynes@1006
    78
void target_add_pointer_fixup( target_data_t td, int type, void *location, void *p )
nkeynes@1006
    79
{
nkeynes@1006
    80
    target_add_fixup(td, mode|TARGET_FIXUP_POINTER, location)->value.p = p;
nkeynes@1006
    81
}
nkeynes@1006
    82
nkeynes@1006
    83
nkeynes@1006
    84
nkeynes@1006
    85
void target_ensure_space( target_data_t td, int space_required )
nkeynes@1006
    86
{
nkeynes@1006
    87
    uint8_t *oldstart = td->block->code;
nkeynes@1006
    88
    uint32_t new_size = (td->xlat_output - oldstart) + space_required;
nkeynes@1006
    89
    if( new_size < td->block->size ) {
nkeynes@1006
    90
        xlat_current_block = xlat_extend_block( xlat_output - oldstart + MAX_INSTRUCTION_SIZE );
nkeynes@1006
    91
        eob = xlat_current_block->code + xlat_current_block->size;
nkeynes@1006
    92
        td->block = xlat_extend_block( new_size );
nkeynes@1006
    93
        xlat_output = td->block->code + (xlat_output - oldstart);        
nkeynes@1006
    94
    }
nkeynes@1006
    95
}
nkeynes@1006
    96
nkeynes@1006
    97
/**
nkeynes@1006
    98
 * Generate the exception table and exception bodies from the fixup data
nkeynes@1006
    99
 * Note that this may add additional constants to the fixup table.
nkeynes@1006
   100
 */
nkeynes@1006
   101
static void target_gen_exception_table( )
nkeynes@1006
   102
{
nkeynes@1006
   103
    int exc_size = 0, num_raiseext = 0;
nkeynes@1006
   104
    
nkeynes@1006
   105
    for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &TD.fixup_table[TD.fixup_table_posn]; fixup++ ) {
nkeynes@1006
   106
        int type = 
nkeynes@1006
   107
        switch(TARGET_FIXUP_TARGET(fixup->type)) {
nkeynes@1006
   108
        case TARGET_FIXUP_RAISEEXT:
nkeynes@1006
   109
            num_raiseext++;
nkeynes@1006
   110
            /* fallthrough */
nkeynes@1006
   111
        case TARGET_FIXUP_RAISE:
nkeynes@1006
   112
            exc_size += TD.get_code_size(fixup->value.exc, NULL);
nkeynes@1006
   113
        }
nkeynes@1006
   114
    }
nkeynes@1006
   115
nkeynes@1006
   116
    ALIGN64(TD.xlat_output);
nkeynes@1006
   117
    target_ensure_space( td, exc_size + num_raiseext*sizeof(struct xlat_exception_record) );
nkeynes@1006
   118
    uint8_t *blockstart = &TD.block->code[0];
nkeynes@1006
   119
    struct xlat_exception_record *exc_record = (struct xlat_exception_record *)TD.xlat_output;
nkeynes@1006
   120
    TD.block->exc_table_offset = TD.xlat_output - blockstart;
nkeynes@1006
   121
    TD.block->exc_table_size = num_raiseext;
nkeynes@1006
   122
    TD.xlat_output += (num_raiseext*sizeof(struct xlat_exception_record));
nkeynes@1006
   123
    
nkeynes@1006
   124
    for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
nkeynes@1006
   125
        switch( TARGET_FIXUP_TARGET(fixup->type) ) {
nkeynes@1006
   126
        case TARGET_FIXUP_RAISEEXT:
nkeynes@1006
   127
            exc_record->xlat_pc_offset = fixup->fixup_offset + 4;
nkeynes@1006
   128
            exc_record->xlat_exc_offset = TD.xlat_output - blockstart;
nkeynes@1006
   129
            /* fallthrough */
nkeynes@1006
   130
        case TARGET_FIXUP_RAISE:
nkeynes@1006
   131
            fixup->target_offset = TD.xlat_output - blockstart;
nkeynes@1006
   132
            TD.codegen( td, fixup->value.exc, NULL );
nkeynes@1006
   133
        }
nkeynes@1006
   134
    }
nkeynes@1006
   135
}
nkeynes@1006
   136
nkeynes@1006
   137
/** 
nkeynes@1006
   138
 * Generate constant table from the fixup data.
nkeynes@1006
   139
 */
nkeynes@1006
   140
static void target_gen_constant_table( )
nkeynes@1006
   141
{
nkeynes@1006
   142
    int numconst32=0, numconst64=0;
nkeynes@1006
   143
nkeynes@1006
   144
    /* Determine table size */
nkeynes@1006
   145
    for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
nkeynes@1006
   146
        int type = TARGET_FIXUP_TARGET(fixup->type);
nkeynes@1006
   147
        if( type == TARGET_FIXUP_CONST32 ) {
nkeynes@1006
   148
            numconst32++;
nkeynes@1006
   149
        } else if( type == TARGET_FIXUP_CONST64 ) {
nkeynes@1006
   150
            numconst64++;
nkeynes@1006
   151
        }
nkeynes@1006
   152
    }
nkeynes@1006
   153
    
nkeynes@1006
   154
    if( numconst64 != 0 ) {
nkeynes@1006
   155
        ALIGN64(TD.xlat_output);
nkeynes@1006
   156
    } else if( numconst32 != 0 ) {
nkeynes@1006
   157
        ALIGN32(TD.xlat_output);
nkeynes@1006
   158
    } else {
nkeynes@1006
   159
        return; /* no constants */
nkeynes@1006
   160
    }
nkeynes@1006
   161
    target_ensure_space( td, numconst64*8 + numconst32*4 );
nkeynes@1006
   162
    uint8_t *blockstart = &TD.block->code[0];
nkeynes@1006
   163
    
nkeynes@1006
   164
    /* TODO: Merge reused constant values */
nkeynes@1006
   165
    uint64_t *const64p = (uint64_t *)TD.xlat_output;
nkeynes@1006
   166
    uint32_t *const32p = (uint32_t *)(TD.xlat_output + numconst64*8);
nkeynes@1006
   167
    TD.xlat_output += (numconst64*8 + numconst32*4);
nkeynes@1006
   168
    
nkeynes@1006
   169
    for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
nkeynes@1006
   170
        switch(TARGET_FIXUP_TARGET(fixup->type)) {
nkeynes@1006
   171
        case TARGET_FIXUP_CONST32:
nkeynes@1006
   172
            fixup->target_offset =  ((uint8_t *)const32p) - blockstart;  
nkeynes@1006
   173
            *const32p++ = fixup->value.i;
nkeynes@1006
   174
            break;
nkeynes@1006
   175
        case TARGET_FIXUP_CONST64:
nkeynes@1006
   176
            fixup->target_offset =  ((uint8_t *)const64p) - blockstart;  
nkeynes@1006
   177
            *const64p++ = fixup->value.q;
nkeynes@1006
   178
            break;
nkeynes@1006
   179
        }
nkeynes@1006
   180
    }
nkeynes@1006
   181
}
nkeynes@1006
   182
nkeynes@1006
   183
/**
nkeynes@1006
   184
 * Apply all target fixups - assumes exceptions + constants have already been
nkeynes@1006
   185
 * generated.
nkeynes@1006
   186
 */
nkeynes@1006
   187
static void target_apply_fixups( )
nkeynes@1006
   188
{
nkeynes@1006
   189
    for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &TD.fixup_table[TD.fixup_table_posn]; fixup++ ) {
nkeynes@1006
   190
        void *target;
nkeynes@1006
   191
        if( TARGET_FIXUP_TARGET(fixup->type) == TARGET_FIXUP_POINTER ) {
nkeynes@1006
   192
            target = fixup->value.p;
nkeynes@1006
   193
        } else {
nkeynes@1006
   194
            target = &TD.block->code[fixup->target_offset];
nkeynes@1006
   195
        }
nkeynes@1006
   196
        
nkeynes@1006
   197
        uint32_t *loc = (uint32_t *)TD.block->code[fixup->fixup_offset];
nkeynes@1006
   198
        uint64_t *loc64 = (uint64_t *)TD.block->code[fixup->fixup_offset];
nkeynes@1006
   199
        switch(TARGET_FIXUP_MODE(fixup->fixup_type)) {
nkeynes@1006
   200
        case TARGET_FIXUP_REL32:
nkeynes@1006
   201
            *loc += (uint8_t *)target - (uint8_t *)(loc+1);
nkeynes@1006
   202
            break;
nkeynes@1006
   203
        case TARGET_FIXUP_REL64:
nkeynes@1006
   204
            *loc64 += (uint8_t *)target - (uint8_t *)(loc64+1);
nkeynes@1006
   205
            break;
nkeynes@1006
   206
        case TARGET_FIXUP_ABS32:
nkeynes@1006
   207
            *loc += (uint32_t)target;
nkeynes@1006
   208
            break;
nkeynes@1006
   209
        case TARGET_FIXUP_ABS64:
nkeynes@1006
   210
            *loc64 += (uint64_t)target;
nkeynes@1006
   211
            break;
nkeynes@1006
   212
        }
nkeynes@1006
   213
    }
nkeynes@1006
   214
}
nkeynes@1006
   215
nkeynes@1006
   216
void target_codegen( xlat_target_machine_t machine, source_data_t sd )
nkeynes@1006
   217
{
nkeynes@1006
   218
    /* Setup the target data struct */
nkeynes@1006
   219
    TD.mach = machine;
nkeynes@1006
   220
    TD.src = sd->machine;
nkeynes@1006
   221
    TD.block = xlat_start_block( sd->pc_start );
nkeynes@1006
   222
    TD.xlat_output = &TD.block->code[0];
nkeynes@1006
   223
    if( TD.fixup_table == NULL ) {
nkeynes@1006
   224
        if( TD.fixup_table == NULL ) {
nkeynes@1006
   225
            TD.fixup_table_size = DEFAULT_FIXUP_TABLE_SIZE;
nkeynes@1006
   226
            TD.fixup_table = malloc( td->fixup_table_size * sizeof(struct target_fixup_struct) );
nkeynes@1006
   227
            assert( TD.fixup_table != NULL );
nkeynes@1006
   228
        }
nkeynes@1006
   229
    }
nkeynes@1006
   230
    TD.fixup_table_posn = 0;
nkeynes@1006
   231
    
nkeynes@1006
   232
    uint32_t code_size = machine->get_code_size(sd->ir_begin,sd->ir_end);
nkeynes@1006
   233
    target_ensure_space(&TD, code_size);
nkeynes@1006
   234
    
nkeynes@1006
   235
    machine->codegen(&TD, sd->begin, sd->end);
nkeynes@1006
   236
    
nkeynes@1006
   237
    target_gen_exception_table();
nkeynes@1006
   238
    target_gen_constant_table();
nkeynes@1006
   239
    target_apply_fixups();
nkeynes@1006
   240
    
nkeynes@1006
   241
    xlat_commit_block( TD.xlat_output - &TD.block->code[0], sd->pc_end-sd->pc_start );
nkeynes@1006
   242
    return &TD.block->code[0];
nkeynes@1006
   243
}
.