Search
lxdream.org :: lxdream/src/xlat/target.c :: diff
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 (11 years ago)
branchxlat-refactor
permissions -rw-r--r--
last change Commit current work-in-progress to xlat-refactor branch
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/xlat/target.c Tue Apr 07 10:55:03 2009 +0000
1.3 @@ -0,0 +1,243 @@
1.4 +/**
1.5 + * $Id: target.c 931 2008-10-31 02:57:59Z nkeynes $
1.6 + *
1.7 + * Target code-generation support - provides a generic harness around the raw
1.8 + * (machine-specific) code emitter.
1.9 + *
1.10 + * Copyright (c) 2009 Nathan Keynes.
1.11 + *
1.12 + * This program is free software; you can redistribute it and/or modify
1.13 + * it under the terms of the GNU General Public License as published by
1.14 + * the Free Software Foundation; either version 2 of the License, or
1.15 + * (at your option) any later version.
1.16 + *
1.17 + * This program is distributed in the hope that it will be useful,
1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 + * GNU General Public License for more details.
1.21 + */
1.22 +
1.23 +#include <stdlib.h>
1.24 +
1.25 +#include "lxdream.h"
1.26 +#include "xlat/xir.h"
1.27 +#include "xlat/machine.h"
1.28 +
1.29 +#define DEFAULT_FIXUP_TABLE_SIZE 4096
1.30 +#define ALIGN32(p) p += ((-(uintptr_t)p)&0x03)
1.31 +#define ALIGN64(p) p += ((-(uintptr_t)p)&0x07)
1.32 +
1.33 +/**
1.34 + * Currently we use a single static target_data so that we can reuse the
1.35 + * allocated memory (and we only do one codegen at a time anyway). However
1.36 + * we keep this private so that other modules can't assume there's only one TD.
1.37 + */
1.38 +static struct target_data TD;
1.39 +
1.40 +/**
1.41 + * Add a new fixup without setting a target value
1.42 + */
1.43 +static target_fixup_t target_add_fixup( target_data_t td, int type, void *location )
1.44 +{
1.45 + if( td->fixup_table_posn == td->fixup_table_size ) {
1.46 + td->fixup_table_size <<= 1;
1.47 + td->fixup_table = realloc(td->fixup_table, td->fixup_table_size * sizeof(struct target_fixup_struct));
1.48 + assert( td->fixup_table != NULL );
1.49 + }
1.50 + target_fixup_t fixup = &td->fixup_table[td->fixup_table_posn++];
1.51 + fixup->fixup_type = type | TARGET_FIXUP_CONST32;
1.52 + fixup->fixup_offset = ((uint8_t *)location) - (uint8_t *)&td->block->code[0];
1.53 + return fixup;
1.54 +}
1.55 +
1.56 +void target_add_const32_fixup( target_data_t td, int mode, void *location, uint32_t i )
1.57 +{
1.58 + target_add_fixup(td, mode|TARGET_FIXUP_CONST32, location)->value.i = i;
1.59 +}
1.60 +
1.61 +void target_add_const64_fixup( target_data_t td, int mode, void *location, uint64_t q )
1.62 +{
1.63 + target_add_fixup(td, mode|TARGET_FIXUP_CONST64, location)->value.q = q;
1.64 +}
1.65 +
1.66 +void target_add_raise_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
1.67 +{
1.68 + target_add_fixup(td, mode|TARGET_FIXUP_RAISE, location)->value.exc = exc;
1.69 +}
1.70 +
1.71 +void target_add_raiseext_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
1.72 +{
1.73 + target_add_fixup(td, mode|TARGET_FIXUP_RAISEEXT, location)->value.exc = exc;
1.74 +}
1.75 +
1.76 +void target_add_offset_fixup( target_data_t td, int type, void *location, uint32_t off )
1.77 +{
1.78 + target_add_fixup(td, mode|TARGET_FIXUP_OFFSET, location)->target_offset = off;
1.79 +}
1.80 +
1.81 +void target_add_pointer_fixup( target_data_t td, int type, void *location, void *p )
1.82 +{
1.83 + target_add_fixup(td, mode|TARGET_FIXUP_POINTER, location)->value.p = p;
1.84 +}
1.85 +
1.86 +
1.87 +
1.88 +void target_ensure_space( target_data_t td, int space_required )
1.89 +{
1.90 + uint8_t *oldstart = td->block->code;
1.91 + uint32_t new_size = (td->xlat_output - oldstart) + space_required;
1.92 + if( new_size < td->block->size ) {
1.93 + xlat_current_block = xlat_extend_block( xlat_output - oldstart + MAX_INSTRUCTION_SIZE );
1.94 + eob = xlat_current_block->code + xlat_current_block->size;
1.95 + td->block = xlat_extend_block( new_size );
1.96 + xlat_output = td->block->code + (xlat_output - oldstart);
1.97 + }
1.98 +}
1.99 +
1.100 +/**
1.101 + * Generate the exception table and exception bodies from the fixup data
1.102 + * Note that this may add additional constants to the fixup table.
1.103 + */
1.104 +static void target_gen_exception_table( )
1.105 +{
1.106 + int exc_size = 0, num_raiseext = 0;
1.107 +
1.108 + for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &TD.fixup_table[TD.fixup_table_posn]; fixup++ ) {
1.109 + int type =
1.110 + switch(TARGET_FIXUP_TARGET(fixup->type)) {
1.111 + case TARGET_FIXUP_RAISEEXT:
1.112 + num_raiseext++;
1.113 + /* fallthrough */
1.114 + case TARGET_FIXUP_RAISE:
1.115 + exc_size += TD.get_code_size(fixup->value.exc, NULL);
1.116 + }
1.117 + }
1.118 +
1.119 + ALIGN64(TD.xlat_output);
1.120 + target_ensure_space( td, exc_size + num_raiseext*sizeof(struct xlat_exception_record) );
1.121 + uint8_t *blockstart = &TD.block->code[0];
1.122 + struct xlat_exception_record *exc_record = (struct xlat_exception_record *)TD.xlat_output;
1.123 + TD.block->exc_table_offset = TD.xlat_output - blockstart;
1.124 + TD.block->exc_table_size = num_raiseext;
1.125 + TD.xlat_output += (num_raiseext*sizeof(struct xlat_exception_record));
1.126 +
1.127 + for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
1.128 + switch( TARGET_FIXUP_TARGET(fixup->type) ) {
1.129 + case TARGET_FIXUP_RAISEEXT:
1.130 + exc_record->xlat_pc_offset = fixup->fixup_offset + 4;
1.131 + exc_record->xlat_exc_offset = TD.xlat_output - blockstart;
1.132 + /* fallthrough */
1.133 + case TARGET_FIXUP_RAISE:
1.134 + fixup->target_offset = TD.xlat_output - blockstart;
1.135 + TD.codegen( td, fixup->value.exc, NULL );
1.136 + }
1.137 + }
1.138 +}
1.139 +
1.140 +/**
1.141 + * Generate constant table from the fixup data.
1.142 + */
1.143 +static void target_gen_constant_table( )
1.144 +{
1.145 + int numconst32=0, numconst64=0;
1.146 +
1.147 + /* Determine table size */
1.148 + for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
1.149 + int type = TARGET_FIXUP_TARGET(fixup->type);
1.150 + if( type == TARGET_FIXUP_CONST32 ) {
1.151 + numconst32++;
1.152 + } else if( type == TARGET_FIXUP_CONST64 ) {
1.153 + numconst64++;
1.154 + }
1.155 + }
1.156 +
1.157 + if( numconst64 != 0 ) {
1.158 + ALIGN64(TD.xlat_output);
1.159 + } else if( numconst32 != 0 ) {
1.160 + ALIGN32(TD.xlat_output);
1.161 + } else {
1.162 + return; /* no constants */
1.163 + }
1.164 + target_ensure_space( td, numconst64*8 + numconst32*4 );
1.165 + uint8_t *blockstart = &TD.block->code[0];
1.166 +
1.167 + /* TODO: Merge reused constant values */
1.168 + uint64_t *const64p = (uint64_t *)TD.xlat_output;
1.169 + uint32_t *const32p = (uint32_t *)(TD.xlat_output + numconst64*8);
1.170 + TD.xlat_output += (numconst64*8 + numconst32*4);
1.171 +
1.172 + for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &td_fixup_table[TD.fixup_table_posn]; fixup++ ) {
1.173 + switch(TARGET_FIXUP_TARGET(fixup->type)) {
1.174 + case TARGET_FIXUP_CONST32:
1.175 + fixup->target_offset = ((uint8_t *)const32p) - blockstart;
1.176 + *const32p++ = fixup->value.i;
1.177 + break;
1.178 + case TARGET_FIXUP_CONST64:
1.179 + fixup->target_offset = ((uint8_t *)const64p) - blockstart;
1.180 + *const64p++ = fixup->value.q;
1.181 + break;
1.182 + }
1.183 + }
1.184 +}
1.185 +
1.186 +/**
1.187 + * Apply all target fixups - assumes exceptions + constants have already been
1.188 + * generated.
1.189 + */
1.190 +static void target_apply_fixups( )
1.191 +{
1.192 + for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &TD.fixup_table[TD.fixup_table_posn]; fixup++ ) {
1.193 + void *target;
1.194 + if( TARGET_FIXUP_TARGET(fixup->type) == TARGET_FIXUP_POINTER ) {
1.195 + target = fixup->value.p;
1.196 + } else {
1.197 + target = &TD.block->code[fixup->target_offset];
1.198 + }
1.199 +
1.200 + uint32_t *loc = (uint32_t *)TD.block->code[fixup->fixup_offset];
1.201 + uint64_t *loc64 = (uint64_t *)TD.block->code[fixup->fixup_offset];
1.202 + switch(TARGET_FIXUP_MODE(fixup->fixup_type)) {
1.203 + case TARGET_FIXUP_REL32:
1.204 + *loc += (uint8_t *)target - (uint8_t *)(loc+1);
1.205 + break;
1.206 + case TARGET_FIXUP_REL64:
1.207 + *loc64 += (uint8_t *)target - (uint8_t *)(loc64+1);
1.208 + break;
1.209 + case TARGET_FIXUP_ABS32:
1.210 + *loc += (uint32_t)target;
1.211 + break;
1.212 + case TARGET_FIXUP_ABS64:
1.213 + *loc64 += (uint64_t)target;
1.214 + break;
1.215 + }
1.216 + }
1.217 +}
1.218 +
1.219 +void target_codegen( xlat_target_machine_t machine, source_data_t sd )
1.220 +{
1.221 + /* Setup the target data struct */
1.222 + TD.mach = machine;
1.223 + TD.src = sd->machine;
1.224 + TD.block = xlat_start_block( sd->pc_start );
1.225 + TD.xlat_output = &TD.block->code[0];
1.226 + if( TD.fixup_table == NULL ) {
1.227 + if( TD.fixup_table == NULL ) {
1.228 + TD.fixup_table_size = DEFAULT_FIXUP_TABLE_SIZE;
1.229 + TD.fixup_table = malloc( td->fixup_table_size * sizeof(struct target_fixup_struct) );
1.230 + assert( TD.fixup_table != NULL );
1.231 + }
1.232 + }
1.233 + TD.fixup_table_posn = 0;
1.234 +
1.235 + uint32_t code_size = machine->get_code_size(sd->ir_begin,sd->ir_end);
1.236 + target_ensure_space(&TD, code_size);
1.237 +
1.238 + machine->codegen(&TD, sd->begin, sd->end);
1.239 +
1.240 + target_gen_exception_table();
1.241 + target_gen_constant_table();
1.242 + target_apply_fixups();
1.243 +
1.244 + xlat_commit_block( TD.xlat_output - &TD.block->code[0], sd->pc_end-sd->pc_start );
1.245 + return &TD.block->code[0];
1.246 +}
.