summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/cc/cc_int/bc-emit.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cc/cc_int/bc-emit.c')
-rw-r--r--gnu/usr.bin/cc/cc_int/bc-emit.c991
1 files changed, 991 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc_int/bc-emit.c b/gnu/usr.bin/cc/cc_int/bc-emit.c
new file mode 100644
index 0000000..b5d0c6c
--- /dev/null
+++ b/gnu/usr.bin/cc/cc_int/bc-emit.c
@@ -0,0 +1,991 @@
+/* Output bytecodes for GNU C-compiler.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "machmode.h"
+#include "rtl.h"
+#include "real.h"
+#include "obstack.h"
+#include "bytecode.h"
+#ifdef __GNUC__
+#include "bytetypes.h"
+#endif
+#include "bc-emit.h"
+#include "bc-opcode.h"
+#include "bc-typecd.h"
+#include "bi-run.h"
+
+#include <stdio.h>
+
+extern char *xmalloc (), *xrealloc ();
+extern void free ();
+
+extern struct obstack *rtl_obstack;
+
+/* Indexed by mode class, gives the narrowest mode for each class. */
+
+extern enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
+
+/* Commonly used modes. */
+/* Mode whose width is BITS_PER_UNIT */
+extern enum machine_mode byte_mode;
+
+/* Mode whose width is BITS_PER_WORD */
+extern enum machine_mode word_mode;
+
+/* Vector indexed by opcode giving info about the args for each opcode. */
+static struct arityvec arityvec[] = {
+#include "bc-arity.h"
+};
+
+/* How to print a symbol name for the assembler. */
+static void
+prsym (file, s)
+ FILE *file;
+ char *s;
+{
+ if (*s == '*')
+ fprintf (file, "%s", s + 1);
+ else
+
+#ifdef NAMES_HAVE_UNDERSCORES
+ fprintf (file, "_%s", s);
+#else
+ fprintf (file, "%s", s);
+#endif
+
+}
+
+/* Maintain a bucket hash table for symbol names. */
+
+#define HASH_BITS 32
+#define HASH_SIZE 509
+
+static struct bc_sym *hashtab[HASH_SIZE];
+
+static unsigned int
+hash (name)
+ char *name;
+{
+ unsigned int hash = 0;
+
+ while (*name)
+ {
+ hash = hash << 3 | hash >> HASH_BITS - 3;
+ hash += *name++;
+ }
+
+ return hash % HASH_SIZE;
+}
+
+
+/* Look up the named symbol, creating it if it doesn't exist. */
+struct bc_sym *
+sym_lookup (name)
+ char *name;
+{
+ int i;
+ struct bc_sym *s;
+
+ i = hash (name);
+ for (s = hashtab[i]; s; s = s->next)
+ if (!strcmp (s->name, name))
+ return s;
+
+ s = (struct bc_sym *) xmalloc (sizeof (struct bc_sym));
+ s->name = xmalloc (strlen (name) + 1);
+ strcpy (s->name, name);
+ s->defined = s->global = s->common = 0;
+ s->val = 0;
+ s->next = hashtab[i];
+ hashtab[i] = s;
+ return s;
+}
+
+
+/* Write out .globl and common symbols to the named file. */
+static void
+bc_sym_write (file)
+ FILE *file;
+{
+ int i;
+ struct bc_sym *s;
+
+ for (i = 0; i < HASH_SIZE; ++i)
+ for (s = hashtab[i]; s; s = s->next)
+ {
+ if (s->global)
+ {
+ fprintf (file, "\n\t.globl ");
+ prsym (file, s->name);
+ putc ('\n', file);
+ if (s->common)
+ {
+ fprintf (file, "\n\t.comm ");
+ prsym (file, s->name);
+ fprintf (file, ", %d\n", s->val);
+ }
+ }
+ else if (s->common)
+ {
+ fprintf (file, "\n\t.lcomm ");
+ prsym (file, s->name);
+ fprintf (file, ", %d\n", s->val);
+ }
+ }
+}
+
+
+
+
+/* Create and initialize a new segment. */
+static struct bc_seg *
+seg_create ()
+{
+ struct bc_seg *result;
+
+ result = (struct bc_seg *) xmalloc (sizeof (struct bc_seg));
+ result->alloc = 256;
+ result->data = xmalloc (result->alloc);
+ result->size = 0;
+ result->syms = 0;
+ result->relocs = 0;
+ return result;
+}
+
+
+/* Advance the segment index to the next alignment boundary. */
+static void
+seg_align (seg, log)
+ struct bc_seg *seg;
+ int log;
+{
+ unsigned int oldsize = seg->size;
+
+ seg->size = seg->size + (1 << log) - 1 & ~((1 << log) - 1);
+ if (seg->size > seg->alloc)
+ {
+ while (seg->size > seg->alloc)
+ seg->alloc *= 2;
+ seg->data = xrealloc (seg->data, seg->alloc);
+ }
+ bzero (seg->data + oldsize, seg->size - oldsize);
+}
+
+
+/* Append the given data to the given segment. */
+static void
+seg_data (seg, data, size)
+ struct bc_seg *seg;
+ char *data;
+ unsigned int size;
+{
+ if (seg->size + size > seg->alloc)
+ {
+ while (seg->size + size > seg->alloc)
+ seg->alloc *= 2;
+ seg->data = xrealloc (seg->data, seg->alloc);
+ }
+
+ bcopy (data, seg->data + seg->size, size);
+ seg->size += size;
+}
+
+
+/* Append a zero-filled skip to the given segment. */
+static void
+seg_skip (seg, size)
+ struct bc_seg *seg;
+ unsigned int size;
+{
+ if (seg->size + size > seg->alloc)
+ {
+ while (seg->size + size > seg->alloc)
+ seg->alloc *= 2;
+ seg->data = xrealloc (seg->data, seg->alloc);
+ }
+
+ memset (seg->data + seg->size, 0, size);
+ seg->size += size;
+}
+
+
+/* Define the given name as the current offset in the given segment. It
+ is an error if the name is already defined. Return 0 or 1 indicating
+ failure or success respectively. */
+static int
+seg_defsym (seg, name)
+ struct bc_seg *seg;
+ char *name;
+{
+ struct bc_sym *sym;
+ struct bc_segsym *segsym;
+
+ sym = sym_lookup (name);
+ if (sym->defined)
+ return 0;
+
+ sym->defined = 1;
+ sym->val = seg->size;
+ segsym = (struct bc_segsym *) xmalloc (sizeof (struct bc_segsym));
+ segsym->sym = sym;
+ segsym->next = seg->syms;
+ seg->syms = segsym;
+ return 1;
+}
+
+
+/* Generate in seg's data a reference to the given sym, adjusted by
+ the given offset. */
+static void
+seg_refsym (seg, name, offset)
+ struct bc_seg *seg;
+ char *name;
+ int offset;
+{
+ struct bc_sym *sym;
+ struct bc_segreloc *segreloc;
+
+ sym = sym_lookup (name);
+ segreloc = (struct bc_segreloc *) xmalloc (sizeof (struct bc_segreloc));
+ segreloc->offset = seg->size;
+ segreloc->sym = sym;
+ segreloc->next = seg->relocs;
+ seg->relocs = segreloc;
+ seg_data (seg, (char *) &offset, sizeof offset);
+}
+
+
+/* Concatenate the contents of given segments into the first argument. */
+static void
+seg_concat (result, seg)
+ struct bc_seg *result, *seg;
+{
+ unsigned int fix;
+ struct bc_segsym *segsym;
+ struct bc_segreloc *segreloc;
+
+ seg_align (result, MACHINE_SEG_ALIGN);
+ fix = result->size;
+ seg_data (result, seg->data, seg->size);
+ free (seg->data);
+
+ /* Go through the symbols and relocs of SEG, adjusting their offsets
+ for their new location in RESULT. */
+ if (seg->syms)
+ {
+ segsym = seg->syms;
+ do
+ segsym->sym->val += fix;
+ while (segsym->next && (segsym = segsym->next));
+ segsym->next = result->syms;
+ result->syms = seg->syms;
+ }
+ if (seg->relocs)
+ {
+ segreloc = seg->relocs;
+ do
+ segreloc->offset += fix;
+ while (segreloc->next && (segreloc = segreloc->next));
+ segreloc->next = result->relocs;
+ result->relocs = seg->relocs;
+ }
+
+ free ((char *) seg);
+}
+
+/* Write a segment to a file. */
+static void
+bc_seg_write (seg, file)
+ struct bc_seg *seg;
+ FILE *file;
+{
+ struct bc_segsym *segsym, *nsegsym, *psegsym;
+ struct bc_segreloc *segreloc, *nsegreloc, *psegreloc;
+ int i, offset, flag;
+
+ /* Reverse the list of symbols. */
+ for (psegsym = 0, segsym = seg->syms; segsym; segsym = nsegsym)
+ {
+ nsegsym = segsym->next;
+ segsym->next = psegsym;
+ psegsym = segsym;
+ }
+ seg->syms = psegsym;
+
+ /* Reverse the list of relocs. */
+ for (psegreloc = 0, segreloc = seg->relocs; segreloc; segreloc = nsegreloc)
+ {
+ nsegreloc = segreloc->next;
+ segreloc->next = psegreloc;
+ psegreloc = segreloc;
+ }
+ seg->relocs = psegreloc;
+
+ /* Output each byte of the segment. */
+ for (i = 0, segsym = seg->syms, segreloc = seg->relocs; i < seg->size; ++i)
+ {
+ while (segsym && segsym->sym->val == i)
+ {
+ if (i % 8 != 0)
+ putc ('\n', file);
+
+ BC_WRITE_SEGSYM (segsym, file);
+ segsym = segsym->next;
+ flag = 1;
+ }
+ if (segreloc && segreloc->offset == i)
+ {
+ if (i % 8 != 0)
+ putc ('\n', file);
+
+ bcopy (seg->data + i, (char *) &offset, sizeof (int));
+ i += sizeof (int) - 1;
+
+ BC_WRITE_RELOC_ENTRY (segreloc, file, offset);
+ segreloc = segreloc->next;
+ flag = 1;
+ }
+ else
+ {
+ if (i % 8 == 0 || flag)
+ BC_START_BYTECODE_LINE (file);
+
+ BC_WRITE_BYTECODE (i % 8 == 0 || flag ? ' ' : ',',
+ seg->data[i] & 0xFF,
+ file);
+ flag = 0;
+ if (i % 8 == 7)
+ putc ('\n', file);
+ }
+ }
+
+ /* Paranoia check--we should have visited all syms and relocs during
+ the output pass. */
+
+ if (segsym || segreloc)
+ abort ();
+}
+
+
+
+/* Text and data segments of the object file in making. */
+static struct bc_seg *bc_text_seg;
+static struct bc_seg *bc_data_seg;
+
+/* Called before anything else in this module. */
+void
+bc_initialize ()
+{
+ int min_class_size[(int) MAX_MODE_CLASS];
+ enum machine_mode mode;
+ int i;
+
+ bc_init_mode_to_code_map ();
+
+ bc_text_seg = seg_create ();
+ bc_data_seg = seg_create ();
+
+ dconst0 = REAL_VALUE_ATOF ("0", DFmode);
+ dconst1 = REAL_VALUE_ATOF ("1", DFmode);
+ dconst2 = REAL_VALUE_ATOF ("2", DFmode);
+ dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
+
+ /* Find the narrowest mode for each class and compute the word and byte
+ modes. */
+
+ for (i = 0; i < (int) MAX_MODE_CLASS; i++)
+ min_class_size[i] = 1000;
+
+ for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
+ mode = (enum machine_mode) ((int) mode + 1))
+ {
+ if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)])
+ {
+ class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode;
+ min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode);
+ }
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_BITSIZE (mode) == BITS_PER_UNIT)
+ byte_mode = mode;
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
+ word_mode = mode;
+ }
+}
+
+
+/* External addresses referenced in a function. Rather than trying to
+ work relocatable address directly into bytecoded functions (which would
+ require us to provide hairy location info and possibly obey alignment
+ rules imposed by the architecture) we build an auxilary table of
+ pointer constants, and encode just offsets into this table into the
+ actual bytecode. */
+static struct bc_seg *ptrconsts;
+
+/* Trampoline code for the function entry. */
+struct bc_seg *trampoline;
+
+/* Actual byte code of the function. */
+struct bc_seg *bytecode;
+
+/* List of labels defined in the function. */
+struct bc_label *labels;
+
+/* List of label references in the function. */
+struct bc_labelref *labelrefs;
+
+
+/* Add symbol to pointer table. Return offset into table where
+ pointer was stored. The offset usually goes into the bytecode
+ stream as a constP literal. */
+int
+bc_define_pointer (p)
+ char *p;
+{
+ int offset = ptrconsts->size;
+
+ seg_refsym (ptrconsts, p, 0);
+ return offset;
+}
+
+
+/* Begin a bytecoded function. */
+int
+bc_begin_function (name)
+ char *name;
+{
+ ptrconsts = seg_create ();
+ trampoline = seg_create ();
+ bytecode = seg_create ();
+ return seg_defsym (trampoline, name);
+}
+
+
+/* Force alignment in inline bytecode. */
+void
+bc_align_bytecode (align)
+ int align;
+{
+ seg_align (bytecode, align);
+}
+
+
+/* Emit data inline into bytecode. */
+void
+bc_emit_bytecode_const (data, size)
+ char *data;
+ unsigned int size;
+{
+ if (bytecode)
+ seg_data (bytecode, data, size);
+}
+
+
+/* Create a new "bytecode label", to have its value defined later.
+ Bytecode labels have nothing to do with the object file symbol table,
+ and are purely local to a given bytecoded function. */
+struct bc_label *
+bc_get_bytecode_label ()
+{
+ struct bc_label *result;
+
+ result = (struct bc_label *) xmalloc (sizeof (struct bc_label));
+ result->defined = 0;
+ result->next = labels;
+ result->uid = 0;
+ labels = result;
+ return result;
+}
+
+
+/* Define the given label with the current location counter. */
+int
+bc_emit_bytecode_labeldef (label)
+ struct bc_label *label;
+{
+ extern int bc_new_uid ();
+
+ if (!label || label->defined)
+ return 0;
+
+ label->offset = bytecode->size;
+ label->defined = 1;
+ label->uid = bc_new_uid ();
+
+#ifdef DEBUG_PRINT_CODE
+ fprintf (stderr, "$%lx:\n", label);
+#endif
+
+ return 1;
+}
+
+
+/* Generate a location-relative reference to the given bytecode label.
+ It need not be defined yet; label references will be backpatched later. */
+void
+bc_emit_bytecode_labelref (label)
+ struct bc_label *label;
+{
+ struct bc_labelref *labelref;
+ static int zero;
+
+ labelref = (struct bc_labelref *) xmalloc (sizeof (struct bc_labelref));
+ labelref->label = label;
+ labelref->offset = bytecode->size;
+ labelref->next = labelrefs;
+ labelrefs = labelref;
+
+#ifdef DEBUG_PRINT_CODE
+ fprintf (stderr, " $%lx", label);
+#endif
+
+ seg_data (bytecode, (char *) &zero, sizeof zero);
+}
+
+
+/* Emit a reference to an external address; generate the reference in the
+ ptrconst area, and emit an offset in the bytecode. */
+void
+bc_emit_code_labelref (name, offset)
+ char *name;
+ int offset;
+{
+ int ptroff;
+
+ ptroff = ptrconsts->size / sizeof (char *);
+ seg_data (bytecode, (char *) &ptroff, sizeof ptroff);
+ seg_refsym (ptrconsts, name, offset);
+
+#ifdef DEBUG_PRINT_CODE
+ fprintf (stderr, " [external <%x> %s]", ptroff, name);
+#endif
+}
+
+
+/* Backpatch label references in the byte code, and concatenate the bytecode
+ and pointer constant segments to the cumulative text for the object file.
+ Return a label name for the pointer constants region. */
+char *
+bc_end_function ()
+{
+ int addr;
+ struct bc_label *label, *next;
+ struct bc_labelref *ref, *nextref;
+ char ptrconsts_label[20];
+ static int nlab;
+
+ /* Backpatch bytecode label references. */
+ for (ref = labelrefs; ref; ref = ref->next)
+ if (ref->label->defined)
+ {
+ addr = ref->label->offset;
+ bcopy ((char *) &addr, bytecode->data + ref->offset, sizeof addr);
+ }
+
+ /* Free the chains of labelrefs and labeldefs. */
+ for (ref = labelrefs; ref; ref = nextref)
+ {
+ nextref = ref->next;
+ free ((char *) ref);
+ }
+
+ for (label = labels; label; label = next)
+ {
+ next = label->next;
+ free ((char *) label);
+ }
+
+ seg_concat (trampoline, bytecode);
+ seg_align (trampoline, MACHINE_SEG_ALIGN);
+ sprintf (ptrconsts_label, "*LP%d", nlab++);
+ seg_defsym (trampoline, ptrconsts_label);
+ seg_concat (trampoline, ptrconsts);
+ seg_concat (bc_text_seg, trampoline);
+
+ labels = 0;
+ labelrefs = 0;
+ trampoline = 0;
+ bytecode = 0;
+ ptrconsts = 0;
+
+ return sym_lookup (ptrconsts_label)->name;
+}
+
+/* Force alignment in const data. */
+void
+bc_align_const (align)
+ int align;
+{
+ seg_align (bc_text_seg, align);
+}
+
+/* Emit const data. */
+void
+bc_emit_const (data, size)
+ char *data;
+ unsigned int size;
+{
+ seg_data (bc_text_seg, data, size);
+}
+
+/* Emit a zero-filled constant skip. */
+void
+bc_emit_const_skip (size)
+ unsigned int size;
+{
+ seg_skip (bc_text_seg, size);
+}
+
+/* Emit a label definition in const data. */
+int
+bc_emit_const_labeldef (name)
+ char *name;
+{
+ return seg_defsym (bc_text_seg, name);
+}
+
+/* Emit a label reference in const data. */
+void
+bc_emit_const_labelref (name, offset)
+ char *name;
+ int offset;
+{
+ seg_refsym (bc_text_seg, name, offset);
+}
+
+/* Force alignment in data. */
+void
+bc_align_data (align)
+ int align;
+{
+ seg_align (bc_data_seg, align);
+}
+
+/* Emit data. */
+void
+bc_emit_data (data, size)
+ char *data;
+ unsigned int size;
+{
+ seg_data (bc_data_seg, data, size);
+}
+
+/* Emit a zero-filled data skip. */
+void
+bc_emit_data_skip (size)
+ unsigned int size;
+{
+ seg_skip (bc_data_seg, size);
+}
+
+/* Emit label definition in data. */
+int
+bc_emit_data_labeldef (name)
+ char *name;
+{
+ return seg_defsym (bc_data_seg, name);
+}
+
+/* Emit label reference in data. */
+void
+bc_emit_data_labelref (name, offset)
+ char *name;
+ int offset;
+{
+ seg_refsym (bc_data_seg, name, offset);
+}
+
+/* Emit a common block of the given name and size. Note that
+ when the .o file is actually written non-global "common"
+ blocks will have to be turned into space in the data section. */
+int
+bc_emit_common (name, size)
+ char *name;
+ unsigned int size;
+{
+ struct bc_sym *sym;
+
+ sym = sym_lookup (name);
+ if (sym->defined)
+ return 0;
+
+ sym->defined = 1;
+ sym->common = 1;
+ sym->val = size;
+ return 1;
+}
+
+/* Globalize the given label. */
+void
+bc_globalize_label (name)
+ char *name;
+{
+ struct bc_sym *sym;
+
+ sym = sym_lookup (name);
+ sym->global = 1;
+}
+
+static enum { in_text, in_data } section = in_text;
+
+void
+bc_text ()
+{
+ section = in_text;
+}
+
+void
+bc_data ()
+{
+ section = in_data;
+}
+
+void
+bc_align (align)
+ int align;
+{
+ if (section == in_text)
+ bc_align_const (align);
+ else
+ bc_align_data (align);
+}
+
+void
+bc_emit (data, size)
+ char *data;
+ unsigned int size;
+{
+ if (section == in_text)
+ bc_emit_const (data, size);
+ else
+ bc_emit_data (data, size);
+}
+
+void
+bc_emit_skip (size)
+ unsigned int size;
+{
+ if (section == in_text)
+ bc_emit_const_skip (size);
+ else
+ bc_emit_data_skip (size);
+}
+
+int
+bc_emit_labeldef (name)
+ char *name;
+{
+ if (section == in_text)
+ return bc_emit_const_labeldef (name);
+ else
+ return bc_emit_data_labeldef (name);
+}
+
+void
+bc_emit_labelref (name, offset)
+ char *name;
+ int offset;
+{
+ if (section == in_text)
+ bc_emit_const_labelref (name, offset);
+ else
+ bc_emit_data_labelref (name, offset);
+}
+
+void
+bc_write_file (file)
+ FILE *file;
+{
+ BC_WRITE_FILE (file);
+}
+
+
+/* Allocate a new bytecode rtx.
+ If you supply a null BC_LABEL, we generate one. */
+
+rtx
+bc_gen_rtx (label, offset, bc_label)
+ char *label;
+ int offset;
+ struct bc_label *bc_label;
+{
+ rtx r;
+
+ if (bc_label == 0)
+ bc_label = (struct bc_label *) xmalloc (sizeof (struct bc_label));
+
+ r = gen_rtx (CODE_LABEL, VOIDmode, label, bc_label);
+ bc_label->offset = offset;
+
+ return r;
+}
+
+
+/* Print bytecode rtx */
+void
+bc_print_rtl (fp, r)
+ FILE *fp;
+ rtx r;
+{
+#if 0 /* This needs to get fixed to really work again. */
+ /* BC_WRITE_RTL has a definition
+ that doesn't even make sense for this use. */
+ BC_WRITE_RTL (r, fp);
+#endif
+}
+
+
+/* Emit a bytecode, keeping a running tally of the stack depth. */
+void
+bc_emit_bytecode (bytecode)
+ enum bytecode_opcode bytecode;
+{
+ char byte;
+ static int prev_lineno = -1;
+
+ byte = bytecode;
+
+#ifdef BCDEBUG_PRINT_CODE
+ if (lineno != prev_lineno)
+ {
+ fprintf (stderr, "<line %d>\n", lineno);
+ prev_lineno = lineno;
+ }
+
+ fputs (opcode_name[(unsigned int) bytecode], stderr);
+#endif
+
+ /* Due to errors we are often requested to output bytecodes that
+ will cause an interpreter stack undeflow when executed. Instead of
+ dumping core on such occasions, we omit the bytecode. Erroneous code
+ should not be executed, regardless. This makes life much easier, since
+ we don't have to deceive ourselves about the known stack depth. */
+
+ bc_emit_bytecode_const (&byte, 1);
+
+ if ((stack_depth -= arityvec[(int) bytecode].ninputs) >= 0)
+ {
+ if ((stack_depth += arityvec[(int) bytecode].noutputs) > max_stack_depth)
+ max_stack_depth = stack_depth;
+ }
+
+#ifdef VALIDATE_STACK_FOR_BC
+ VALIDATE_STACK_FOR_BC ();
+#endif
+}
+
+
+#ifdef BCDEBUG_PRINT_CODE
+#define PRLIT(TYPE, PTR) fprintf (stderr, " [%x]", *(TYPE *) PTR)
+#else
+#define PRLIT(X,Y)
+#endif
+
+/* Emit a complete bytecode instruction, expecting the correct number
+ of literal values in the call. First argument is the instruction, the
+ remaining arguments are literals of size HOST_WIDE_INT or smaller. */
+void
+bc_emit_instruction VPROTO((enum bytecode_opcode opcode, ...))
+{
+#ifndef __STDC__
+ enum bytecode_opcode opcode;
+#endif
+ va_list arguments;
+ int nliteral, instruction;
+
+ VA_START (arguments, opcode);
+
+#ifndef __STDC__
+ opcode = va_arg (arguments, enum bytecode_opcode);
+#endif
+
+ /* Emit instruction bytecode */
+ bc_emit_bytecode (opcode);
+ instruction = (int) opcode;
+
+ /* Loop literals and emit as bytecode constants */
+ for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++)
+ {
+ switch (arityvec[instruction].literals[nliteral])
+ {
+/* This conditional is a kludge, but it's necessary
+ because TYPE might be long long. */
+#ifdef __GNUC__
+ /* Expand definitions into case statements */
+#define DEFTYPECODE(CODE, NAME, MODE, TYPE) \
+ case CODE: \
+ { \
+ TYPE temp = va_arg (arguments, TYPE); \
+ bc_emit_bytecode_const ((void *) &temp, sizeof temp); \
+ PRLIT (TYPE, &temp); } \
+ break;
+
+#include "bc-typecd.def"
+
+#undef DEFTYPECODE
+#endif /* __GNUC__ */
+
+ default:
+ abort ();
+ }
+ }
+
+#ifdef BCDEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+/* Emit the machine-code interface trampoline at the beginning of a byte
+ coded function. The argument is a label name of the interpreter
+ bytecode callinfo structure; the return value is a label name for
+ the beginning of the actual bytecode. */
+char *
+bc_emit_trampoline (callinfo)
+ char *callinfo;
+{
+ char mylab[20];
+ static int n;
+
+ sprintf (mylab, "*LB%d", n++);
+
+ BC_EMIT_TRAMPOLINE (trampoline, callinfo);
+
+ seg_defsym (bytecode, mylab);
+ return sym_lookup (mylab)->name;
+}
+
+
+/* Simple strdup */
+char *
+bc_xstrdup (str)
+ char *str;
+{
+ char *tmp = xmalloc (strlen (str) + 1);
+
+ strcpy (tmp, str);
+ return tmp;
+}
OpenPOWER on IntegriCloud