]>
Commit | Line | Data |
---|---|---|
86d7f2db | 1 | /* Output bytecodes for GNU C-compiler. |
e3b79a32 | 2 | Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. |
86d7f2db JB |
3 | |
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
940d9d63 RK |
18 | the Free Software Foundation, 59 Temple Place - Suite 330, |
19 | Boston, MA 02111-1307, USA. */ | |
86d7f2db JB |
20 | |
21 | ||
86d7f2db | 22 | #include "config.h" |
4f90e4a0 | 23 | #ifdef __STDC__ |
04fe4385 | 24 | #include <stdarg.h> |
4f90e4a0 | 25 | #else |
c1758a9c | 26 | #include <varargs.h> |
4f90e4a0 | 27 | #endif |
86d7f2db JB |
28 | #include "machmode.h" |
29 | #include "rtl.h" | |
30 | #include "real.h" | |
31 | #include "obstack.h" | |
32 | #include "bytecode.h" | |
a05afb95 | 33 | #ifdef __GNUC__ |
a8ac57d3 | 34 | #include "bytetypes.h" |
a05afb95 | 35 | #endif |
86d7f2db JB |
36 | #include "bc-emit.h" |
37 | #include "bc-opcode.h" | |
38 | #include "bc-typecd.h" | |
39 | #include "bi-run.h" | |
40 | ||
2ed5f8c2 RS |
41 | #include <stdio.h> |
42 | ||
bc3d8521 | 43 | extern char *xmalloc (), *xrealloc (); |
86d7f2db JB |
44 | |
45 | extern struct obstack *rtl_obstack; | |
46 | ||
86d7f2db JB |
47 | /* Indexed by mode class, gives the narrowest mode for each class. */ |
48 | ||
bacacd4d | 49 | extern enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS]; |
86d7f2db JB |
50 | |
51 | /* Commonly used modes. */ | |
52 | /* Mode whose width is BITS_PER_UNIT */ | |
bacacd4d | 53 | extern enum machine_mode byte_mode; |
86d7f2db JB |
54 | |
55 | /* Mode whose width is BITS_PER_WORD */ | |
bacacd4d | 56 | extern enum machine_mode word_mode; |
86d7f2db | 57 | |
0f41302f | 58 | /* Vector indexed by opcode giving info about the args for each opcode. */ |
86d7f2db JB |
59 | static struct arityvec arityvec[] = { |
60 | #include "bc-arity.h" | |
61 | }; | |
62 | ||
63 | /* How to print a symbol name for the assembler. */ | |
0f41302f | 64 | |
86d7f2db JB |
65 | static void |
66 | prsym (file, s) | |
67 | FILE *file; | |
68 | char *s; | |
69 | { | |
70 | if (*s == '*') | |
71 | fprintf (file, "%s", s + 1); | |
72 | else | |
73 | ||
74 | #ifdef NAMES_HAVE_UNDERSCORES | |
75 | fprintf (file, "_%s", s); | |
76 | #else | |
77 | fprintf (file, "%s", s); | |
78 | #endif | |
79 | ||
80 | } | |
81 | ||
0f41302f | 82 | /* Maintain a bucket hash table for symbol names. */ |
86d7f2db JB |
83 | |
84 | #define HASH_BITS 32 | |
85 | #define HASH_SIZE 509 | |
86 | ||
87 | static struct bc_sym *hashtab[HASH_SIZE]; | |
88 | ||
89 | static unsigned int | |
90 | hash (name) | |
91 | char *name; | |
92 | { | |
93 | unsigned int hash = 0; | |
94 | ||
95 | while (*name) | |
96 | { | |
97 | hash = hash << 3 | hash >> HASH_BITS - 3; | |
98 | hash += *name++; | |
99 | } | |
100 | ||
101 | return hash % HASH_SIZE; | |
102 | } | |
103 | ||
104 | ||
0f41302f MS |
105 | /* Look up the named symbol, creating it if it doesn't exist. */ |
106 | ||
0aa4232c | 107 | struct bc_sym * |
86d7f2db JB |
108 | sym_lookup (name) |
109 | char *name; | |
110 | { | |
111 | int i; | |
112 | struct bc_sym *s; | |
113 | ||
bc3d8521 | 114 | i = hash (name); |
86d7f2db JB |
115 | for (s = hashtab[i]; s; s = s->next) |
116 | if (!strcmp (s->name, name)) | |
117 | return s; | |
118 | ||
119 | s = (struct bc_sym *) xmalloc (sizeof (struct bc_sym)); | |
120 | s->name = xmalloc (strlen (name) + 1); | |
121 | strcpy (s->name, name); | |
122 | s->defined = s->global = s->common = 0; | |
123 | s->val = 0; | |
124 | s->next = hashtab[i]; | |
125 | hashtab[i] = s; | |
126 | return s; | |
127 | } | |
128 | ||
129 | ||
130 | /* Write out .globl and common symbols to the named file. */ | |
0f41302f | 131 | |
86d7f2db JB |
132 | static void |
133 | bc_sym_write (file) | |
134 | FILE *file; | |
135 | { | |
136 | int i; | |
137 | struct bc_sym *s; | |
138 | ||
139 | for (i = 0; i < HASH_SIZE; ++i) | |
140 | for (s = hashtab[i]; s; s = s->next) | |
141 | { | |
142 | if (s->global) | |
143 | { | |
144 | fprintf (file, "\n\t.globl "); | |
145 | prsym (file, s->name); | |
146 | putc ('\n', file); | |
147 | if (s->common) | |
148 | { | |
149 | fprintf (file, "\n\t.comm "); | |
150 | prsym (file, s->name); | |
1395fc23 | 151 | fprintf (file, ", %lu\n", s->val); |
86d7f2db JB |
152 | } |
153 | } | |
154 | else if (s->common) | |
155 | { | |
156 | fprintf (file, "\n\t.lcomm "); | |
157 | prsym (file, s->name); | |
1395fc23 | 158 | fprintf (file, ", %lu\n", s->val); |
86d7f2db JB |
159 | } |
160 | } | |
161 | } | |
162 | ||
163 | \f | |
164 | ||
165 | ||
0f41302f MS |
166 | /* Create and initialize a new segment. */ |
167 | ||
86d7f2db JB |
168 | static struct bc_seg * |
169 | seg_create () | |
170 | { | |
171 | struct bc_seg *result; | |
172 | ||
bc3d8521 | 173 | result = (struct bc_seg *) xmalloc (sizeof (struct bc_seg)); |
86d7f2db | 174 | result->alloc = 256; |
bc3d8521 | 175 | result->data = xmalloc (result->alloc); |
86d7f2db JB |
176 | result->size = 0; |
177 | result->syms = 0; | |
178 | result->relocs = 0; | |
179 | return result; | |
180 | } | |
181 | ||
182 | ||
0f41302f MS |
183 | /* Advance the segment index to the next alignment boundary. */ |
184 | ||
86d7f2db JB |
185 | static void |
186 | seg_align (seg, log) | |
187 | struct bc_seg *seg; | |
188 | int log; | |
189 | { | |
190 | unsigned int oldsize = seg->size; | |
191 | ||
192 | seg->size = seg->size + (1 << log) - 1 & ~((1 << log) - 1); | |
193 | if (seg->size > seg->alloc) | |
194 | { | |
195 | while (seg->size > seg->alloc) | |
196 | seg->alloc *= 2; | |
bc3d8521 | 197 | seg->data = xrealloc (seg->data, seg->alloc); |
86d7f2db | 198 | } |
bc3d8521 | 199 | bzero (seg->data + oldsize, seg->size - oldsize); |
86d7f2db JB |
200 | } |
201 | ||
202 | ||
0f41302f MS |
203 | /* Append the given data to the given segment. */ |
204 | ||
86d7f2db JB |
205 | static void |
206 | seg_data (seg, data, size) | |
207 | struct bc_seg *seg; | |
208 | char *data; | |
209 | unsigned int size; | |
210 | { | |
211 | if (seg->size + size > seg->alloc) | |
212 | { | |
213 | while (seg->size + size > seg->alloc) | |
214 | seg->alloc *= 2; | |
215 | seg->data = xrealloc (seg->data, seg->alloc); | |
216 | } | |
217 | ||
e2aa1185 | 218 | bcopy (data, seg->data + seg->size, size); |
86d7f2db JB |
219 | seg->size += size; |
220 | } | |
221 | ||
222 | ||
223 | /* Append a zero-filled skip to the given segment. */ | |
0f41302f | 224 | |
86d7f2db JB |
225 | static void |
226 | seg_skip (seg, size) | |
227 | struct bc_seg *seg; | |
228 | unsigned int size; | |
229 | { | |
230 | if (seg->size + size > seg->alloc) | |
231 | { | |
232 | while (seg->size + size > seg->alloc) | |
233 | seg->alloc *= 2; | |
234 | seg->data = xrealloc (seg->data, seg->alloc); | |
235 | } | |
236 | ||
237 | memset (seg->data + seg->size, 0, size); | |
238 | seg->size += size; | |
239 | } | |
240 | ||
241 | ||
242 | /* Define the given name as the current offset in the given segment. It | |
243 | is an error if the name is already defined. Return 0 or 1 indicating | |
0f41302f MS |
244 | failure or success respectively. */ |
245 | ||
86d7f2db JB |
246 | static int |
247 | seg_defsym (seg, name) | |
248 | struct bc_seg *seg; | |
249 | char *name; | |
250 | { | |
251 | struct bc_sym *sym; | |
252 | struct bc_segsym *segsym; | |
253 | ||
bc3d8521 | 254 | sym = sym_lookup (name); |
86d7f2db JB |
255 | if (sym->defined) |
256 | return 0; | |
257 | ||
258 | sym->defined = 1; | |
259 | sym->val = seg->size; | |
bc3d8521 | 260 | segsym = (struct bc_segsym *) xmalloc (sizeof (struct bc_segsym)); |
86d7f2db JB |
261 | segsym->sym = sym; |
262 | segsym->next = seg->syms; | |
263 | seg->syms = segsym; | |
264 | return 1; | |
265 | } | |
266 | ||
267 | ||
268 | /* Generate in seg's data a reference to the given sym, adjusted by | |
0f41302f MS |
269 | the given offset. */ |
270 | ||
86d7f2db JB |
271 | static void |
272 | seg_refsym (seg, name, offset) | |
273 | struct bc_seg *seg; | |
274 | char *name; | |
275 | int offset; | |
276 | { | |
277 | struct bc_sym *sym; | |
278 | struct bc_segreloc *segreloc; | |
279 | ||
bc3d8521 RS |
280 | sym = sym_lookup (name); |
281 | segreloc = (struct bc_segreloc *) xmalloc (sizeof (struct bc_segreloc)); | |
86d7f2db JB |
282 | segreloc->offset = seg->size; |
283 | segreloc->sym = sym; | |
284 | segreloc->next = seg->relocs; | |
285 | seg->relocs = segreloc; | |
45d7f9b9 | 286 | seg_data (seg, (char *) &offset, sizeof offset); |
86d7f2db JB |
287 | } |
288 | ||
289 | ||
0f41302f MS |
290 | /* Concatenate the contents of given segments into the first argument. */ |
291 | ||
86d7f2db JB |
292 | static void |
293 | seg_concat (result, seg) | |
294 | struct bc_seg *result, *seg; | |
295 | { | |
296 | unsigned int fix; | |
297 | struct bc_segsym *segsym; | |
298 | struct bc_segreloc *segreloc; | |
299 | ||
bc3d8521 | 300 | seg_align (result, MACHINE_SEG_ALIGN); |
86d7f2db | 301 | fix = result->size; |
bc3d8521 RS |
302 | seg_data (result, seg->data, seg->size); |
303 | free (seg->data); | |
86d7f2db JB |
304 | |
305 | /* Go through the symbols and relocs of SEG, adjusting their offsets | |
0f41302f | 306 | for their new location in RESULT. */ |
86d7f2db JB |
307 | if (seg->syms) |
308 | { | |
309 | segsym = seg->syms; | |
310 | do | |
311 | segsym->sym->val += fix; | |
312 | while (segsym->next && (segsym = segsym->next)); | |
313 | segsym->next = result->syms; | |
314 | result->syms = seg->syms; | |
315 | } | |
316 | if (seg->relocs) | |
317 | { | |
318 | segreloc = seg->relocs; | |
319 | do | |
320 | segreloc->offset += fix; | |
321 | while (segreloc->next && (segreloc = segreloc->next)); | |
322 | segreloc->next = result->relocs; | |
323 | result->relocs = seg->relocs; | |
324 | } | |
325 | ||
bc3d8521 | 326 | free ((char *) seg); |
86d7f2db JB |
327 | } |
328 | ||
329 | /* Write a segment to a file. */ | |
0f41302f | 330 | |
86d7f2db JB |
331 | static void |
332 | bc_seg_write (seg, file) | |
333 | struct bc_seg *seg; | |
334 | FILE *file; | |
335 | { | |
336 | struct bc_segsym *segsym, *nsegsym, *psegsym; | |
337 | struct bc_segreloc *segreloc, *nsegreloc, *psegreloc; | |
338 | int i, offset, flag; | |
339 | ||
340 | /* Reverse the list of symbols. */ | |
341 | for (psegsym = 0, segsym = seg->syms; segsym; segsym = nsegsym) | |
342 | { | |
343 | nsegsym = segsym->next; | |
344 | segsym->next = psegsym; | |
345 | psegsym = segsym; | |
346 | } | |
347 | seg->syms = psegsym; | |
348 | ||
349 | /* Reverse the list of relocs. */ | |
350 | for (psegreloc = 0, segreloc = seg->relocs; segreloc; segreloc = nsegreloc) | |
351 | { | |
352 | nsegreloc = segreloc->next; | |
353 | segreloc->next = psegreloc; | |
354 | psegreloc = segreloc; | |
355 | } | |
356 | seg->relocs = psegreloc; | |
357 | ||
358 | /* Output each byte of the segment. */ | |
359 | for (i = 0, segsym = seg->syms, segreloc = seg->relocs; i < seg->size; ++i) | |
360 | { | |
361 | while (segsym && segsym->sym->val == i) | |
362 | { | |
363 | if (i % 8 != 0) | |
bc3d8521 | 364 | putc ('\n', file); |
86d7f2db JB |
365 | |
366 | BC_WRITE_SEGSYM (segsym, file); | |
367 | segsym = segsym->next; | |
368 | flag = 1; | |
369 | } | |
370 | if (segreloc && segreloc->offset == i) | |
371 | { | |
372 | if (i % 8 != 0) | |
373 | putc ('\n', file); | |
374 | ||
4c9a05bc | 375 | bcopy (seg->data + i, (char *) &offset, sizeof (int)); |
86d7f2db JB |
376 | i += sizeof (int) - 1; |
377 | ||
378 | BC_WRITE_RELOC_ENTRY (segreloc, file, offset); | |
379 | segreloc = segreloc->next; | |
380 | flag = 1; | |
381 | } | |
382 | else | |
383 | { | |
384 | if (i % 8 == 0 || flag) | |
385 | BC_START_BYTECODE_LINE (file); | |
386 | ||
387 | BC_WRITE_BYTECODE (i % 8 == 0 || flag ? ' ' : ',', | |
388 | seg->data[i] & 0xFF, | |
389 | file); | |
390 | flag = 0; | |
391 | if (i % 8 == 7) | |
392 | putc ('\n', file); | |
393 | } | |
394 | } | |
395 | ||
396 | /* Paranoia check--we should have visited all syms and relocs during | |
397 | the output pass. */ | |
398 | ||
399 | if (segsym || segreloc) | |
400 | abort (); | |
401 | } | |
402 | ||
403 | \f | |
404 | ||
0f41302f | 405 | /* Text and data segments of the object file in making. */ |
86d7f2db JB |
406 | static struct bc_seg *bc_text_seg; |
407 | static struct bc_seg *bc_data_seg; | |
408 | ||
0f41302f MS |
409 | /* Called before anything else in this module. */ |
410 | ||
86d7f2db JB |
411 | void |
412 | bc_initialize () | |
413 | { | |
414 | int min_class_size[(int) MAX_MODE_CLASS]; | |
415 | enum machine_mode mode; | |
416 | int i; | |
417 | ||
418 | bc_init_mode_to_code_map (); | |
419 | ||
420 | bc_text_seg = seg_create (); | |
421 | bc_data_seg = seg_create (); | |
422 | ||
a05afb95 RS |
423 | dconst0 = REAL_VALUE_ATOF ("0", DFmode); |
424 | dconst1 = REAL_VALUE_ATOF ("1", DFmode); | |
425 | dconst2 = REAL_VALUE_ATOF ("2", DFmode); | |
426 | dconstm1 = REAL_VALUE_ATOF ("-1", DFmode); | |
86d7f2db JB |
427 | |
428 | /* Find the narrowest mode for each class and compute the word and byte | |
429 | modes. */ | |
430 | ||
431 | for (i = 0; i < (int) MAX_MODE_CLASS; i++) | |
432 | min_class_size[i] = 1000; | |
433 | ||
434 | for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; | |
435 | mode = (enum machine_mode) ((int) mode + 1)) | |
436 | { | |
437 | if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)]) | |
438 | { | |
439 | class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode; | |
440 | min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode); | |
441 | } | |
442 | if (GET_MODE_CLASS (mode) == MODE_INT | |
443 | && GET_MODE_BITSIZE (mode) == BITS_PER_UNIT) | |
444 | byte_mode = mode; | |
445 | ||
446 | if (GET_MODE_CLASS (mode) == MODE_INT | |
447 | && GET_MODE_BITSIZE (mode) == BITS_PER_WORD) | |
448 | word_mode = mode; | |
449 | } | |
450 | } | |
451 | ||
452 | ||
453 | /* External addresses referenced in a function. Rather than trying to | |
454 | work relocatable address directly into bytecoded functions (which would | |
455 | require us to provide hairy location info and possibly obey alignment | |
ddd5a7c1 | 456 | rules imposed by the architecture) we build an auxiliary table of |
86d7f2db | 457 | pointer constants, and encode just offsets into this table into the |
0f41302f | 458 | actual bytecode. */ |
86d7f2db JB |
459 | static struct bc_seg *ptrconsts; |
460 | ||
461 | /* Trampoline code for the function entry. */ | |
462 | struct bc_seg *trampoline; | |
463 | ||
0f41302f | 464 | /* Actual byte code of the function. */ |
86d7f2db JB |
465 | struct bc_seg *bytecode; |
466 | ||
0f41302f | 467 | /* List of labels defined in the function. */ |
86d7f2db JB |
468 | struct bc_label *labels; |
469 | ||
0f41302f | 470 | /* List of label references in the function. */ |
86d7f2db JB |
471 | struct bc_labelref *labelrefs; |
472 | ||
473 | ||
474 | /* Add symbol to pointer table. Return offset into table where | |
475 | pointer was stored. The offset usually goes into the bytecode | |
0f41302f MS |
476 | stream as a constP literal. */ |
477 | ||
86d7f2db JB |
478 | int |
479 | bc_define_pointer (p) | |
480 | char *p; | |
481 | { | |
482 | int offset = ptrconsts->size; | |
483 | ||
484 | seg_refsym (ptrconsts, p, 0); | |
485 | return offset; | |
486 | } | |
487 | ||
488 | ||
489 | /* Begin a bytecoded function. */ | |
0f41302f | 490 | |
86d7f2db JB |
491 | int |
492 | bc_begin_function (name) | |
493 | char *name; | |
494 | { | |
495 | ptrconsts = seg_create (); | |
496 | trampoline = seg_create (); | |
497 | bytecode = seg_create (); | |
498 | return seg_defsym (trampoline, name); | |
499 | } | |
500 | ||
501 | ||
502 | /* Force alignment in inline bytecode. */ | |
0f41302f | 503 | |
86d7f2db JB |
504 | void |
505 | bc_align_bytecode (align) | |
506 | int align; | |
507 | { | |
508 | seg_align (bytecode, align); | |
509 | } | |
510 | ||
511 | ||
512 | /* Emit data inline into bytecode. */ | |
0f41302f | 513 | |
86d7f2db JB |
514 | void |
515 | bc_emit_bytecode_const (data, size) | |
516 | char *data; | |
517 | unsigned int size; | |
518 | { | |
519 | if (bytecode) | |
520 | seg_data (bytecode, data, size); | |
521 | } | |
522 | ||
523 | ||
524 | /* Create a new "bytecode label", to have its value defined later. | |
525 | Bytecode labels have nothing to do with the object file symbol table, | |
0f41302f MS |
526 | and are purely local to a given bytecoded function. */ |
527 | ||
86d7f2db JB |
528 | struct bc_label * |
529 | bc_get_bytecode_label () | |
530 | { | |
531 | struct bc_label *result; | |
532 | ||
533 | result = (struct bc_label *) xmalloc (sizeof (struct bc_label)); | |
534 | result->defined = 0; | |
535 | result->next = labels; | |
536 | result->uid = 0; | |
537 | labels = result; | |
538 | return result; | |
539 | } | |
540 | ||
541 | ||
0f41302f MS |
542 | /* Define the given label with the current location counter. */ |
543 | ||
86d7f2db JB |
544 | int |
545 | bc_emit_bytecode_labeldef (label) | |
546 | struct bc_label *label; | |
547 | { | |
548 | extern int bc_new_uid (); | |
549 | ||
550 | if (!label || label->defined) | |
551 | return 0; | |
552 | ||
553 | label->offset = bytecode->size; | |
554 | label->defined = 1; | |
555 | label->uid = bc_new_uid (); | |
556 | ||
557 | #ifdef DEBUG_PRINT_CODE | |
558 | fprintf (stderr, "$%lx:\n", label); | |
559 | #endif | |
560 | ||
561 | return 1; | |
562 | } | |
563 | ||
564 | ||
565 | /* Generate a location-relative reference to the given bytecode label. | |
0f41302f MS |
566 | It need not be defined yet; label references will be backpatched later. */ |
567 | ||
86d7f2db JB |
568 | void |
569 | bc_emit_bytecode_labelref (label) | |
570 | struct bc_label *label; | |
571 | { | |
572 | struct bc_labelref *labelref; | |
573 | static int zero; | |
574 | ||
575 | labelref = (struct bc_labelref *) xmalloc (sizeof (struct bc_labelref)); | |
576 | labelref->label = label; | |
577 | labelref->offset = bytecode->size; | |
578 | labelref->next = labelrefs; | |
579 | labelrefs = labelref; | |
580 | ||
581 | #ifdef DEBUG_PRINT_CODE | |
582 | fprintf (stderr, " $%lx", label); | |
583 | #endif | |
584 | ||
585 | seg_data (bytecode, (char *) &zero, sizeof zero); | |
586 | } | |
587 | ||
588 | ||
589 | /* Emit a reference to an external address; generate the reference in the | |
0f41302f MS |
590 | ptrconst area, and emit an offset in the bytecode. */ |
591 | ||
86d7f2db JB |
592 | void |
593 | bc_emit_code_labelref (name, offset) | |
594 | char *name; | |
595 | int offset; | |
596 | { | |
597 | int ptroff; | |
598 | ||
599 | ptroff = ptrconsts->size / sizeof (char *); | |
600 | seg_data (bytecode, (char *) &ptroff, sizeof ptroff); | |
601 | seg_refsym (ptrconsts, name, offset); | |
602 | ||
603 | #ifdef DEBUG_PRINT_CODE | |
604 | fprintf (stderr, " [external <%x> %s]", ptroff, name); | |
605 | #endif | |
606 | } | |
607 | ||
608 | ||
609 | /* Backpatch label references in the byte code, and concatenate the bytecode | |
610 | and pointer constant segments to the cumulative text for the object file. | |
611 | Return a label name for the pointer constants region. */ | |
0f41302f | 612 | |
86d7f2db JB |
613 | char * |
614 | bc_end_function () | |
615 | { | |
616 | int addr; | |
617 | struct bc_label *label, *next; | |
618 | struct bc_labelref *ref, *nextref; | |
619 | char ptrconsts_label[20]; | |
620 | static int nlab; | |
621 | ||
0f41302f | 622 | /* Backpatch bytecode label references. */ |
86d7f2db JB |
623 | for (ref = labelrefs; ref; ref = ref->next) |
624 | if (ref->label->defined) | |
625 | { | |
626 | addr = ref->label->offset; | |
4c9a05bc | 627 | bcopy ((char *) &addr, bytecode->data + ref->offset, sizeof addr); |
86d7f2db JB |
628 | } |
629 | ||
0f41302f | 630 | /* Free the chains of labelrefs and labeldefs. */ |
86d7f2db JB |
631 | for (ref = labelrefs; ref; ref = nextref) |
632 | { | |
633 | nextref = ref->next; | |
634 | free ((char *) ref); | |
635 | } | |
636 | ||
637 | for (label = labels; label; label = next) | |
638 | { | |
639 | next = label->next; | |
640 | free ((char *) label); | |
641 | } | |
642 | ||
643 | seg_concat (trampoline, bytecode); | |
644 | seg_align (trampoline, MACHINE_SEG_ALIGN); | |
645 | sprintf (ptrconsts_label, "*LP%d", nlab++); | |
646 | seg_defsym (trampoline, ptrconsts_label); | |
647 | seg_concat (trampoline, ptrconsts); | |
648 | seg_concat (bc_text_seg, trampoline); | |
649 | ||
650 | labels = 0; | |
651 | labelrefs = 0; | |
652 | trampoline = 0; | |
653 | bytecode = 0; | |
654 | ptrconsts = 0; | |
655 | ||
656 | return sym_lookup (ptrconsts_label)->name; | |
657 | } | |
658 | ||
0f41302f MS |
659 | /* Force alignment in const data. */ |
660 | ||
86d7f2db JB |
661 | void |
662 | bc_align_const (align) | |
663 | int align; | |
664 | { | |
665 | seg_align (bc_text_seg, align); | |
666 | } | |
667 | ||
0f41302f MS |
668 | /* Emit const data. */ |
669 | ||
86d7f2db JB |
670 | void |
671 | bc_emit_const (data, size) | |
672 | char *data; | |
673 | unsigned int size; | |
674 | { | |
675 | seg_data (bc_text_seg, data, size); | |
676 | } | |
677 | ||
0f41302f MS |
678 | /* Emit a zero-filled constant skip. */ |
679 | ||
86d7f2db JB |
680 | void |
681 | bc_emit_const_skip (size) | |
682 | unsigned int size; | |
683 | { | |
684 | seg_skip (bc_text_seg, size); | |
685 | } | |
686 | ||
0f41302f MS |
687 | /* Emit a label definition in const data. */ |
688 | ||
86d7f2db JB |
689 | int |
690 | bc_emit_const_labeldef (name) | |
691 | char *name; | |
692 | { | |
693 | return seg_defsym (bc_text_seg, name); | |
694 | } | |
695 | ||
0f41302f MS |
696 | /* Emit a label reference in const data. */ |
697 | ||
86d7f2db JB |
698 | void |
699 | bc_emit_const_labelref (name, offset) | |
700 | char *name; | |
701 | int offset; | |
702 | { | |
703 | seg_refsym (bc_text_seg, name, offset); | |
704 | } | |
705 | ||
0f41302f MS |
706 | /* Force alignment in data. */ |
707 | ||
86d7f2db JB |
708 | void |
709 | bc_align_data (align) | |
710 | int align; | |
711 | { | |
712 | seg_align (bc_data_seg, align); | |
713 | } | |
714 | ||
0f41302f MS |
715 | /* Emit data. */ |
716 | ||
86d7f2db | 717 | void |
bc3d8521 | 718 | bc_emit_data (data, size) |
86d7f2db JB |
719 | char *data; |
720 | unsigned int size; | |
721 | { | |
722 | seg_data (bc_data_seg, data, size); | |
723 | } | |
724 | ||
725 | /* Emit a zero-filled data skip. */ | |
0f41302f | 726 | |
86d7f2db JB |
727 | void |
728 | bc_emit_data_skip (size) | |
729 | unsigned int size; | |
730 | { | |
bc3d8521 | 731 | seg_skip (bc_data_seg, size); |
86d7f2db JB |
732 | } |
733 | ||
0f41302f MS |
734 | /* Emit label definition in data. */ |
735 | ||
86d7f2db | 736 | int |
bc3d8521 | 737 | bc_emit_data_labeldef (name) |
86d7f2db JB |
738 | char *name; |
739 | { | |
bc3d8521 | 740 | return seg_defsym (bc_data_seg, name); |
86d7f2db JB |
741 | } |
742 | ||
0f41302f MS |
743 | /* Emit label reference in data. */ |
744 | ||
86d7f2db | 745 | void |
bc3d8521 | 746 | bc_emit_data_labelref (name, offset) |
86d7f2db JB |
747 | char *name; |
748 | int offset; | |
749 | { | |
bc3d8521 | 750 | seg_refsym (bc_data_seg, name, offset); |
86d7f2db JB |
751 | } |
752 | ||
753 | /* Emit a common block of the given name and size. Note that | |
754 | when the .o file is actually written non-global "common" | |
755 | blocks will have to be turned into space in the data section. */ | |
0f41302f | 756 | |
86d7f2db | 757 | int |
bc3d8521 | 758 | bc_emit_common (name, size) |
86d7f2db JB |
759 | char *name; |
760 | unsigned int size; | |
761 | { | |
762 | struct bc_sym *sym; | |
763 | ||
bc3d8521 | 764 | sym = sym_lookup (name); |
86d7f2db JB |
765 | if (sym->defined) |
766 | return 0; | |
767 | ||
768 | sym->defined = 1; | |
769 | sym->common = 1; | |
770 | sym->val = size; | |
771 | return 1; | |
772 | } | |
773 | ||
0f41302f MS |
774 | /* Globalize the given label. */ |
775 | ||
86d7f2db | 776 | void |
bc3d8521 | 777 | bc_globalize_label (name) |
86d7f2db JB |
778 | char *name; |
779 | { | |
780 | struct bc_sym *sym; | |
781 | ||
bc3d8521 | 782 | sym = sym_lookup (name); |
86d7f2db JB |
783 | sym->global = 1; |
784 | } | |
785 | ||
786 | static enum { in_text, in_data } section = in_text; | |
787 | ||
788 | void | |
789 | bc_text () | |
790 | { | |
791 | section = in_text; | |
792 | } | |
793 | ||
794 | void | |
795 | bc_data () | |
796 | { | |
797 | section = in_data; | |
798 | } | |
799 | ||
800 | void | |
801 | bc_align (align) | |
802 | int align; | |
803 | { | |
804 | if (section == in_text) | |
805 | bc_align_const (align); | |
806 | else | |
807 | bc_align_data (align); | |
808 | } | |
809 | ||
810 | void | |
811 | bc_emit (data, size) | |
812 | char *data; | |
813 | unsigned int size; | |
814 | { | |
815 | if (section == in_text) | |
816 | bc_emit_const (data, size); | |
817 | else | |
818 | bc_emit_data (data, size); | |
819 | } | |
820 | ||
821 | void | |
822 | bc_emit_skip (size) | |
823 | unsigned int size; | |
824 | { | |
825 | if (section == in_text) | |
826 | bc_emit_const_skip (size); | |
827 | else | |
828 | bc_emit_data_skip (size); | |
829 | } | |
830 | ||
831 | int | |
832 | bc_emit_labeldef (name) | |
833 | char *name; | |
834 | { | |
835 | if (section == in_text) | |
836 | return bc_emit_const_labeldef (name); | |
837 | else | |
838 | return bc_emit_data_labeldef (name); | |
839 | } | |
840 | ||
841 | void | |
842 | bc_emit_labelref (name, offset) | |
843 | char *name; | |
844 | int offset; | |
845 | { | |
846 | if (section == in_text) | |
847 | bc_emit_const_labelref (name, offset); | |
848 | else | |
849 | bc_emit_data_labelref (name, offset); | |
850 | } | |
851 | ||
852 | void | |
853 | bc_write_file (file) | |
854 | FILE *file; | |
855 | { | |
856 | BC_WRITE_FILE (file); | |
857 | } | |
858 | ||
04b2d6f5 RS |
859 | |
860 | /* Allocate a new bytecode rtx. | |
861 | If you supply a null BC_LABEL, we generate one. */ | |
862 | ||
863 | rtx | |
864 | bc_gen_rtx (label, offset, bc_label) | |
865 | char *label; | |
866 | int offset; | |
867 | struct bc_label *bc_label; | |
868 | { | |
869 | rtx r; | |
870 | ||
871 | if (bc_label == 0) | |
872 | bc_label = (struct bc_label *) xmalloc (sizeof (struct bc_label)); | |
873 | ||
874 | r = gen_rtx (CODE_LABEL, VOIDmode, label, bc_label); | |
875 | bc_label->offset = offset; | |
876 | ||
877 | return r; | |
878 | } | |
879 | ||
880 | ||
86d7f2db | 881 | /* Print bytecode rtx */ |
0f41302f | 882 | |
86d7f2db JB |
883 | void |
884 | bc_print_rtl (fp, r) | |
885 | FILE *fp; | |
886 | rtx r; | |
887 | { | |
04b2d6f5 RS |
888 | #if 0 /* This needs to get fixed to really work again. */ |
889 | /* BC_WRITE_RTL has a definition | |
890 | that doesn't even make sense for this use. */ | |
86d7f2db | 891 | BC_WRITE_RTL (r, fp); |
04b2d6f5 | 892 | #endif |
86d7f2db JB |
893 | } |
894 | ||
895 | ||
896 | /* Emit a bytecode, keeping a running tally of the stack depth. */ | |
0f41302f | 897 | |
86d7f2db JB |
898 | void |
899 | bc_emit_bytecode (bytecode) | |
900 | enum bytecode_opcode bytecode; | |
901 | { | |
902 | char byte; | |
86d7f2db JB |
903 | static int prev_lineno = -1; |
904 | ||
24556405 | 905 | byte = (char) bytecode; |
86d7f2db JB |
906 | |
907 | #ifdef BCDEBUG_PRINT_CODE | |
908 | if (lineno != prev_lineno) | |
909 | { | |
910 | fprintf (stderr, "<line %d>\n", lineno); | |
911 | prev_lineno = lineno; | |
912 | } | |
913 | ||
914 | fputs (opcode_name[(unsigned int) bytecode], stderr); | |
915 | #endif | |
916 | ||
917 | /* Due to errors we are often requested to output bytecodes that | |
918 | will cause an interpreter stack undeflow when executed. Instead of | |
919 | dumping core on such occasions, we omit the bytecode. Erroneous code | |
920 | should not be executed, regardless. This makes life much easier, since | |
0f41302f | 921 | we don't have to deceive ourselves about the known stack depth. */ |
86d7f2db JB |
922 | |
923 | bc_emit_bytecode_const (&byte, 1); | |
924 | ||
eecaa29b | 925 | if ((stack_depth -= arityvec[(int) bytecode].ninputs) >= 0) |
86d7f2db | 926 | { |
eecaa29b | 927 | if ((stack_depth += arityvec[(int) bytecode].noutputs) > max_stack_depth) |
86d7f2db JB |
928 | max_stack_depth = stack_depth; |
929 | } | |
930 | ||
a8ac57d3 RS |
931 | #ifdef VALIDATE_STACK_FOR_BC |
932 | VALIDATE_STACK_FOR_BC (); | |
86d7f2db JB |
933 | #endif |
934 | } | |
935 | ||
936 | ||
937 | #ifdef BCDEBUG_PRINT_CODE | |
938 | #define PRLIT(TYPE, PTR) fprintf (stderr, " [%x]", *(TYPE *) PTR) | |
939 | #else | |
940 | #define PRLIT(X,Y) | |
941 | #endif | |
942 | ||
943 | /* Emit a complete bytecode instruction, expecting the correct number | |
944 | of literal values in the call. First argument is the instruction, the | |
0f41302f MS |
945 | remaining arguments are literals of size HOST_WIDE_INT or smaller. */ |
946 | ||
86d7f2db | 947 | void |
4f90e4a0 | 948 | bc_emit_instruction VPROTO((enum bytecode_opcode opcode, ...)) |
86d7f2db | 949 | { |
4f90e4a0 | 950 | #ifndef __STDC__ |
86d7f2db | 951 | enum bytecode_opcode opcode; |
4f90e4a0 RK |
952 | #endif |
953 | va_list arguments; | |
86d7f2db JB |
954 | int nliteral, instruction; |
955 | ||
4f90e4a0 | 956 | VA_START (arguments, opcode); |
86d7f2db | 957 | |
4f90e4a0 RK |
958 | #ifndef __STDC__ |
959 | opcode = va_arg (arguments, enum bytecode_opcode); | |
960 | #endif | |
86d7f2db JB |
961 | |
962 | /* Emit instruction bytecode */ | |
86d7f2db JB |
963 | bc_emit_bytecode (opcode); |
964 | instruction = (int) opcode; | |
965 | ||
966 | /* Loop literals and emit as bytecode constants */ | |
967 | for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++) | |
968 | { | |
86d7f2db JB |
969 | switch (arityvec[instruction].literals[nliteral]) |
970 | { | |
a8ac57d3 RS |
971 | /* This conditional is a kludge, but it's necessary |
972 | because TYPE might be long long. */ | |
973 | #ifdef __GNUC__ | |
86d7f2db JB |
974 | /* Expand definitions into case statements */ |
975 | #define DEFTYPECODE(CODE, NAME, MODE, TYPE) \ | |
976 | case CODE: \ | |
a8ac57d3 RS |
977 | { \ |
978 | TYPE temp = va_arg (arguments, TYPE); \ | |
86d7f2db JB |
979 | bc_emit_bytecode_const ((void *) &temp, sizeof temp); \ |
980 | PRLIT (TYPE, &temp); } \ | |
981 | break; | |
982 | ||
983 | #include "bc-typecd.def" | |
984 | ||
985 | #undef DEFTYPECODE | |
a8ac57d3 | 986 | #endif /* __GNUC__ */ |
86d7f2db JB |
987 | |
988 | default: | |
989 | abort (); | |
990 | } | |
991 | } | |
992 | ||
4498659c RK |
993 | va_end (arguments); |
994 | ||
86d7f2db JB |
995 | #ifdef BCDEBUG_PRINT_CODE |
996 | fputc ('\n', stderr); | |
997 | #endif | |
998 | } | |
999 | \f | |
1000 | /* Emit the machine-code interface trampoline at the beginning of a byte | |
1001 | coded function. The argument is a label name of the interpreter | |
1002 | bytecode callinfo structure; the return value is a label name for | |
1003 | the beginning of the actual bytecode. */ | |
0f41302f | 1004 | |
86d7f2db JB |
1005 | char * |
1006 | bc_emit_trampoline (callinfo) | |
1007 | char *callinfo; | |
1008 | { | |
1009 | char mylab[20]; | |
1010 | static int n; | |
1011 | ||
1012 | sprintf (mylab, "*LB%d", n++); | |
1013 | ||
1014 | BC_EMIT_TRAMPOLINE (trampoline, callinfo); | |
1015 | ||
1016 | seg_defsym (bytecode, mylab); | |
1017 | return sym_lookup (mylab)->name; | |
1018 | } |