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