filename | src/xlat/target.c |
changeset | 1006:3a169c224c12 |
author | nkeynes |
date | Sun Apr 12 07:24:45 2009 +0000 (15 years ago) |
branch | xlat-refactor |
permissions | -rw-r--r-- |
last change | Restructure operand types - rename to forms to avoid conflict for actual data types temporary operands are now a first class form remove explicit types for immediates - now implied by opcode Initial work on promote-source-reg pass |
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 }
.