2 * $Id: target.c 931 2008-10-31 02:57:59Z nkeynes $
4 * Target code-generation support - provides a generic harness around the raw
5 * (machine-specific) code emitter.
7 * Copyright (c) 2009 Nathan Keynes.
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.
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.
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)
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.
35 static struct target_data TD;
38 * Add a new fixup without setting a target value
40 static target_fixup_t target_add_fixup( target_data_t td, int type, void *location )
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 );
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];
53 void target_add_const32_fixup( target_data_t td, int mode, void *location, uint32_t i )
55 target_add_fixup(td, mode|TARGET_FIXUP_CONST32, location)->value.i = i;
58 void target_add_const64_fixup( target_data_t td, int mode, void *location, uint64_t q )
60 target_add_fixup(td, mode|TARGET_FIXUP_CONST64, location)->value.q = q;
63 void target_add_raise_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
65 target_add_fixup(td, mode|TARGET_FIXUP_RAISE, location)->value.exc = exc;
68 void target_add_raiseext_fixup( target_data_t td, int type, void *location, xir_op_t *exc )
70 target_add_fixup(td, mode|TARGET_FIXUP_RAISEEXT, location)->value.exc = exc;
73 void target_add_offset_fixup( target_data_t td, int type, void *location, uint32_t off )
75 target_add_fixup(td, mode|TARGET_FIXUP_OFFSET, location)->target_offset = off;
78 void target_add_pointer_fixup( target_data_t td, int type, void *location, void *p )
80 target_add_fixup(td, mode|TARGET_FIXUP_POINTER, location)->value.p = p;
85 void target_ensure_space( target_data_t td, int space_required )
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);
98 * Generate the exception table and exception bodies from the fixup data
99 * Note that this may add additional constants to the fixup table.
101 static void target_gen_exception_table( )
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++ ) {
107 switch(TARGET_FIXUP_TARGET(fixup->type)) {
108 case TARGET_FIXUP_RAISEEXT:
111 case TARGET_FIXUP_RAISE:
112 exc_size += TD.get_code_size(fixup->value.exc, NULL);
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;
130 case TARGET_FIXUP_RAISE:
131 fixup->target_offset = TD.xlat_output - blockstart;
132 TD.codegen( td, fixup->value.exc, NULL );
138 * Generate constant table from the fixup data.
140 static void target_gen_constant_table( )
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 ) {
149 } else if( type == TARGET_FIXUP_CONST64 ) {
154 if( numconst64 != 0 ) {
155 ALIGN64(TD.xlat_output);
156 } else if( numconst32 != 0 ) {
157 ALIGN32(TD.xlat_output);
159 return; /* no constants */
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;
175 case TARGET_FIXUP_CONST64:
176 fixup->target_offset = ((uint8_t *)const64p) - blockstart;
177 *const64p++ = fixup->value.q;
184 * Apply all target fixups - assumes exceptions + constants have already been
187 static void target_apply_fixups( )
189 for( target_fixup_t fixup = &TD.fixup_table[0]; fixup != &TD.fixup_table[TD.fixup_table_posn]; fixup++ ) {
191 if( TARGET_FIXUP_TARGET(fixup->type) == TARGET_FIXUP_POINTER ) {
192 target = fixup->value.p;
194 target = &TD.block->code[fixup->target_offset];
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);
203 case TARGET_FIXUP_REL64:
204 *loc64 += (uint8_t *)target - (uint8_t *)(loc64+1);
206 case TARGET_FIXUP_ABS32:
207 *loc += (uint32_t)target;
209 case TARGET_FIXUP_ABS64:
210 *loc64 += (uint64_t)target;
216 void target_codegen( xlat_target_machine_t machine, source_data_t sd )
218 /* Setup the target data struct */
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 );
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];
.