aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Brittenson <bson@gnu.org>1993-09-21 14:25:24 -0700
committerJan Brittenson <bson@gnu.org>1993-09-21 14:25:24 -0700
commitca695ac93dca6da6f9bcb2916cd3798f016084b2 (patch)
tree9955b06ba9da7010dd96c146915e52676d09d15f
parent86d7f2db057abae09db4208bf0578f6e9a0da17b (diff)
downloadgcc-ca695ac93dca6da6f9bcb2916cd3798f016084b2.zip
gcc-ca695ac93dca6da6f9bcb2916cd3798f016084b2.tar.gz
gcc-ca695ac93dca6da6f9bcb2916cd3798f016084b2.tar.bz2
bytecode
From-SVN: r5379
-rw-r--r--gcc/Makefile.in83
-rw-r--r--gcc/c-pragma.c36
-rw-r--r--gcc/emit-rtl.c41
-rw-r--r--gcc/expr.c1308
-rw-r--r--gcc/integrate.c10
-rw-r--r--gcc/regclass.c8
-rw-r--r--gcc/rtl.h17
-rw-r--r--gcc/stmt.c930
-rw-r--r--gcc/toplev.c153
-rw-r--r--gcc/varasm.c554
10 files changed, 2939 insertions, 201 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e9993c9..2c044ee 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -399,6 +399,9 @@ CPLUS_OBJS = cp-parse.o cp-decl.o cp-decl2.o \
cp-expr.o cp-pt.o cp-edsel.o cp-xref.o \
$(CPLUS_INPUT) cp-spew.o c-common.o
+# Files specific to the C interpreter bytecode compiler(s).
+BC_OBJS = bc-emit.o bc-optab.o
+
# Language-independent object files.
OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
function.o stmt.o expr.o calls.o expmed.o explow.o optabs.o varasm.o \
@@ -461,6 +464,7 @@ CONFIG_H =
RTL_H = rtl.h rtl.def machmode.h machmode.def
TREE_H = tree.h real.h tree.def machmode.h machmode.def
CPLUS_TREE_H = $(TREE_H) cp-tree.h cp-tree.def
+BYTECODE_H = bytecode.h bc-emit.h bc-optab.h
# Avoid a lot of time thinking about remaking Makefile.in and *.def.
.SUFFIXES: .in .def
@@ -484,7 +488,7 @@ for-bootstrap: start.encap $(LIBGCC)
rest.encap: $(LIBGCC) stmp-headers $(STMP_FIXPROTO) $(EXTRA_PARTS)
# This is what is made with the host's compiler
# whether making a cross compiler or not.
-native: config.status cpp $(LANGUAGES) $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
+native: bytecode config.status cpp $(LANGUAGES) $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
# Define the names for selecting languages in LANGUAGES.
C c: cc1
@@ -545,14 +549,14 @@ g++-cross: $(srcdir)/g++.c
$(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o g++-cross \
-DGCC_NAME=\"$(target)-gcc\" $(srcdir)/g++.c version.o $(LIBS)
-cc1:$(P) $(C_OBJS) $(OBJS) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(LIBS)
+cc1:$(P) $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
-cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(OBJS) $(LIBS)
+cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(BC_OBJS) $(OBJS) $(LIBS)
-cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(LIBS)
+cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
# Copy float.h from its source.
gfloat.h: $(FLOAT_H)
@@ -1247,6 +1251,63 @@ $(HOST_PREFIX_1)malloc.o: malloc.c
$(HOST_PREFIX_1):
touch $(HOST_PREFIX_1)
+# Remake bytecode files.
+# BI_ALL=bi-run.o
+BI_ALL=
+BC_ALL=bc-opname.h bc-opcode.h bc-arity.h
+BI_OBJ=bi-parser.o bi-lexer.o bi-reverse.o
+
+
+bc-emit.o : bc-emit.c $(CONFIG_H) $(BYTECODE_H)
+bc-optab.o : bc-optab.c bc-typecd.def $(CONFIG_H) $(BYTECODE_H)
+
+
+bytecode: $(BI_ALL) $(BC_ALL)
+
+bi-arity: bi-arity.o
+bi-opcode: bi-opcode.o
+bi-opname: bi-opname.o
+bi-unparse: bi-unparse.o
+bi-lexer: bi-lexer.o
+
+bi-arity bi-opcode bi-opname bi-unparse bi-lexer: $(BI_OBJ)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $^ $(LEXLIB)
+
+bi-run.o: $(srcdir)/bi-run.c $(srcdir)/bi-run.h $(srcdir)/bc-typecd.h bc-opname.h bc-arity.h bc-opcode.h
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
+
+bi-parser.c: $(srcdir)/bi-parser.y $(srcdir)/bi-parser.h
+
+bi-parser.o: $(srcdir)/bi-parser.c $(srcdir)/bi-defs.h
+ $(CC) $(CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
+
+bi-lexer.c: $(srcdir)/bi-lexer.l $(srcdir)/bi-parser.h
+
+bi-lexer.o: bi-lexer.c bi-parser.h
+ $(CC) $(CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
+
+bc-arity.h: $(srcdir)/bytecode.def bi-arity
+ -rm -f $@
+ bi-arity <$< >$@
+
+bc-opcode.h: $(srcdir)/bytecode.def bi-opcode
+ -rm -f $@
+ bi-opcode <$< >$@
+
+bc-opname.h: $(srcdir)/bytecode.def bi-opname
+ -rm -f $@
+ bi-opname <$< >$@
+
+bytecode.mostlyclean:
+ -rm -f bc-arity.h bc-opcode.h bc-opname.h
+
+bytecode.distclean bytecode.clean: bytecode.mostlyclean
+ -rm -f bi-arity bi-opcode bi-opname bi-unparse bi-lexer
+
+bytecode.realclean: bytecode.clean
+ -rm -f bi-parser.c bi-lexer.c bi-parser.h
+
+
# Remake cpp and protoize.
# Making the preprocessor
@@ -1507,7 +1568,7 @@ $(srcdir)/INSTALL: install1.texi install.texi
# `realclean' also deletes everything that could be regenerated automatically.
-mostlyclean:
+mostlyclean: bytecode.mostlyclean
-rm -f $(STAGESTUFF)
# Clean the objc subdir if we created one.
if [ -d objc ]; then \
@@ -1545,7 +1606,7 @@ mostlyclean:
# Delete all files made by compilation
# that don't exist in the distribution.
-clean: mostlyclean
+clean: mostlyclean bytecode.clean
# It may not be quite desirable to delete unprotoize.c here,
# but the spec for `make clean' requires it.
# Using unprotoize.c is not quite right in the first place,
@@ -1557,7 +1618,7 @@ clean: mostlyclean
# Delete all files that users would normally create
# while building and installing GCC.
-distclean: clean
+distclean: clean bytecode.distclean
-rm -f tm.h aux-output.c config.h md config.status tconfig.h hconfig.h
-rm -f Makefile *.oaux
-rm -fr stage1 stage2 stage3 stage4
@@ -1581,7 +1642,7 @@ extraclean: distclean
# Get rid of every file that's generated from some other file.
# Most of these files ARE PRESENT in the GCC distribution.
-realclean: distclean
+realclean: distclean bytecode.realclean
-rm -f c-parse.y objc-parse.y
-rm -f cp-parse.c cp-parse.h cp-parse.output
-rm -f objc-parse.c objc-parse.output
diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c
index 9bb9266..002c094 100644
--- a/gcc/c-pragma.c
+++ b/gcc/c-pragma.c
@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "config.h"
#include "tree.h"
+#include "function.h"
#ifdef HANDLE_SYSV_PRAGMA
@@ -45,20 +46,7 @@ handle_pragma_token (string, token)
char *string;
tree token;
{
- static enum pragma_state
- {
- ps_start,
- ps_done,
- ps_bad,
- ps_weak,
- ps_name,
- ps_equals,
- ps_value,
- ps_pack,
- ps_left,
- ps_align,
- ps_right
- } state = ps_start, type;
+ static enum pragma_state state = ps_start, type;
static char *name;
static char *value;
static int align;
@@ -76,24 +64,8 @@ handle_pragma_token (string, token)
{
#ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK)
- {
- if (state == ps_name || state == ps_value)
- {
- fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
- ASM_OUTPUT_LABELREF (asm_out_file, name);
- fputc ('\n', asm_out_file);
- if (state == ps_value)
- {
- fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
- ASM_OUTPUT_LABELREF (asm_out_file, name);
- fputc (',', asm_out_file);
- ASM_OUTPUT_LABELREF (asm_out_file, value);
- fputc ('\n', asm_out_file);
- }
- }
- else if (! (state == ps_done || state == ps_start))
- warning ("malformed `#pragma weak'");
- }
+ handle_pragma_weak (state, asm_out_file, name, value);
+
#endif /* HANDLE_PRAMA_WEAK */
}
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 04b9069..a927fd0 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -42,8 +42,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h"
#include "insn-config.h"
#include "real.h"
+#include "obstack.h"
+
+#include "bytecode.h"
+#include "machmode.h"
+#include "bc-opcode.h"
+#include "bc-typecd.h"
+#include "bc-optab.h"
+#include "bc-emit.h"
+
#include <stdio.h>
+
+/* Opcode names */
+#ifdef BCDEBUG_PRINT_CODE
+char *opcode_name[] =
+{
+#include "bc-opname.h"
+
+"***END***"
+};
+#endif
+
+
/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
After rtl generation, it is 1 plus the largest register number used. */
@@ -203,6 +224,11 @@ extern int emit_lineno;
rtx change_address ();
void init_emit ();
+extern struct obstack *rtl_obstack;
+
+extern int stack_depth;
+extern int max_stack_depth;
+
/* rtx gen_rtx (code, mode, [element1, ..., elementn])
**
** This routine generates an RTX of the size specified by
@@ -1216,8 +1242,12 @@ change_address (memref, mode, addr)
rtx
gen_label_rtx ()
{
- register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0,
- label_num++, NULL_PTR);
+ register rtx label;
+
+ label = output_bytecode
+ ? bc_gen_rtx (0, 0, bc_get_bytecode_label ())
+ : gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR);
+
LABEL_NUSES (label) = 0;
return label;
}
@@ -2559,6 +2589,13 @@ emit_line_note (file, line)
char *file;
int line;
{
+ if (output_bytecode)
+ {
+ /* FIXME: for now we do nothing, but eventually we will have to deal with
+ debugging information. */
+ return 0;
+ }
+
emit_filename = file;
emit_lineno = line;
diff --git a/gcc/expr.c b/gcc/expr.c
index 33dccf4..33f1bae 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -19,8 +19,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
+#include "machmode.h"
#include "rtl.h"
#include "tree.h"
+#include "obstack.h"
#include "flags.h"
#include "function.h"
#include "insn-flags.h"
@@ -31,6 +33,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "output.h"
#include "typeclass.h"
+#include "bytecode.h"
+#include "bc-opcode.h"
+#include "bc-typecd.h"
+#include "bc-optab.h"
+#include "bc-emit.h"
+
+
#define CEIL(x,y) (((x) + (y) - 1) / (y))
/* Decide whether a function's arguments should be processed
@@ -137,6 +146,20 @@ static rtx expand_builtin_apply_args PROTO((void));
static rtx expand_builtin_apply PROTO((rtx, rtx, rtx));
static void expand_builtin_return PROTO((rtx));
static rtx expand_increment PROTO((tree, int));
+rtx bc_expand_increment PROTO((struct increment_operator *, tree));
+tree bc_runtime_type_code PROTO((tree));
+rtx bc_allocate_local PROTO((int, int));
+void bc_store_memory PROTO((tree, tree));
+tree bc_expand_component_address PROTO((tree));
+tree bc_expand_address PROTO((tree));
+void bc_expand_constructor PROTO((tree));
+void bc_adjust_stack PROTO((int));
+tree bc_canonicalize_array_ref PROTO((tree));
+void bc_load_memory PROTO((tree, tree));
+void bc_load_externaddr PROTO((rtx));
+void bc_load_externaddr_id PROTO((tree, int));
+void bc_load_localaddr PROTO((rtx));
+void bc_load_parmaddr PROTO((rtx));
static void preexpand_calls PROTO((tree));
static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
static void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
@@ -183,6 +206,32 @@ enum insn_code movstr_optab[NUM_MACHINE_MODES];
#define OUTGOING_REGNO(IN) (IN)
#endif
+/* Maps used to convert modes to const, load, and store bytecodes. */
+enum bytecode_opcode mode_to_const_map[MAX_MACHINE_MODE];
+enum bytecode_opcode mode_to_load_map[MAX_MACHINE_MODE];
+enum bytecode_opcode mode_to_store_map[MAX_MACHINE_MODE];
+
+/* Initialize maps used to convert modes to const, load, and store
+ bytecodes. */
+void
+bc_init_mode_to_opcode_maps ()
+{
+ int mode;
+
+ for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
+ mode_to_const_map[mode] =
+ mode_to_load_map[mode] =
+ mode_to_store_map[mode] = neverneverland;
+
+#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
+ mode_to_const_map[(enum machine_mode) SYM] = CONST; \
+ mode_to_load_map[(enum machine_mode) SYM] = LOAD; \
+ mode_to_store_map[(enum machine_mode) SYM] = STORE;
+
+#include "modemap.def"
+#undef DEF_MODEMAP
+}
+
/* This is run once per compilation to set up which modes can be used
directly in memory and to initialize the block move optab. */
@@ -2224,6 +2273,22 @@ expand_assignment (to, from, want_value, suggest_reg)
return want_value ? result : NULL_RTX;
}
+ if (output_bytecode)
+ {
+ tree dest_innermost;
+
+ bc_expand_expr (from);
+ bc_emit_instruction (dup);
+
+ dest_innermost = bc_expand_address (to);
+
+ /* Can't deduce from TYPE that we're dealing with a bitfield, so
+ take care of it here. */
+
+ bc_store_memory (TREE_TYPE (to), dest_innermost);
+ return NULL;
+ }
+
/* Assignment of a structure component needs special treatment
if the structure component's rtx is not simply a MEM.
Assignment of an array element at a constant index
@@ -3428,6 +3493,7 @@ expand_expr (exp, target, tmode, modifier)
/* Use subtarget as the target for operand 0 of a binary operation. */
rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
rtx original_target = target;
+ /* Maybe defer this until sure not doing bytecode? */
int ignore = (target == const0_rtx
|| ((code == NON_LVALUE_EXPR || code == NOP_EXPR
|| code == CONVERT_EXPR || code == REFERENCE_EXPR
@@ -3435,6 +3501,13 @@ expand_expr (exp, target, tmode, modifier)
&& TREE_CODE (type) == VOID_TYPE));
tree context;
+
+ if (output_bytecode)
+ {
+ bc_expand_expr (exp);
+ return NULL;
+ }
+
/* Don't use hard regs as subtargets, because the combiner
can only handle pseudo regs. */
if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER)
@@ -5615,6 +5688,510 @@ expand_expr (exp, target, tmode, modifier)
abort ();
return temp;
}
+
+
+/* Emit bytecode to evaluate the given expression EXP to the stack. */
+void
+bc_expand_expr (exp)
+ tree exp;
+{
+ enum tree_code code;
+ tree type, arg0;
+ rtx r;
+ struct binary_operator *binoptab;
+ struct unary_operator *unoptab;
+ struct increment_operator *incroptab;
+ struct bc_label *lab, *lab1;
+ enum bytecode_opcode opcode;
+
+
+ code = TREE_CODE (exp);
+
+ switch (code)
+ {
+ case PARM_DECL:
+
+ if (DECL_RTL (exp) == 0)
+ {
+ error_with_decl (exp, "prior parameter's size depends on `%s'");
+ return;
+ }
+
+ bc_load_parmaddr (DECL_RTL (exp));
+ bc_load_memory (TREE_TYPE (exp), exp);
+
+ return;
+
+ case VAR_DECL:
+
+ if (DECL_RTL (exp) == 0)
+ abort ();
+
+#if 0
+ if (DECL_RTL (exp)->label)
+ bc_load_externaddr (DECL_RTL (exp));
+ else
+ bc_load_localaddr (DECL_RTL (exp));
+#endif
+ if (TREE_PUBLIC (exp))
+ bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), DECL_RTL (exp)->offset);
+ else
+ bc_load_localaddr (DECL_RTL (exp));
+
+ bc_load_memory (TREE_TYPE (exp), exp);
+ return;
+
+ case INTEGER_CST:
+
+#ifdef DEBUG_PRINT_CODE
+ fprintf (stderr, " [%x]\n", TREE_INT_CST_LOW (exp));
+#endif
+ bc_emit_instruction (mode_to_const_map[DECL_BIT_FIELD (exp)
+ ? SImode
+ : TYPE_MODE (TREE_TYPE (exp))],
+ (HOST_WIDE_INT) TREE_INT_CST_LOW (exp));
+ return;
+
+ case REAL_CST:
+
+#ifdef DEBUG_PRINT_CODE
+ fprintf (stderr, " [%g]\n", (double) TREE_INT_CST_LOW (exp));
+#endif
+ bc_emit_instruction (mode_to_const_map[TYPE_MODE (TREE_TYPE (exp))],
+ (double) TREE_REAL_CST (exp));
+ return;
+
+ case CALL_EXPR:
+
+ /* We build a call description vector describing the type of
+ the return value and of the arguments; this call vector,
+ together with a pointer to a location for the return value
+ and the base of the argument list, is passed to the low
+ level machine dependent call subroutine, which is responsible
+ for putting the arguments wherever real functions expect
+ them, as well as getting the return value back. */
+ {
+ tree calldesc = 0, arg;
+ int nargs = 0, i;
+ rtx retval;
+
+ /* Push the evaluated args on the evaluation stack in reverse
+ order. Also make an entry for each arg in the calldesc
+ vector while we're at it. */
+
+ TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
+
+ for (arg = TREE_OPERAND (exp, 1); arg; arg = TREE_CHAIN (arg))
+ {
+ ++nargs;
+ bc_expand_expr (TREE_VALUE (arg));
+
+ calldesc = tree_cons ((tree) 0,
+ size_in_bytes (TREE_TYPE (TREE_VALUE (arg))),
+ calldesc);
+ calldesc = tree_cons ((tree) 0,
+ bc_runtime_type_code (TREE_TYPE (TREE_VALUE (arg))),
+ calldesc);
+ }
+
+ TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
+
+ /* Allocate a location for the return value and push its
+ address on the evaluation stack. Also make an entry
+ at the front of the calldesc for the return value type. */
+
+ type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type));
+ bc_load_localaddr (retval);
+
+ calldesc = tree_cons ((tree) 0, size_in_bytes (type), calldesc);
+ calldesc = tree_cons ((tree) 0, bc_runtime_type_code (type), calldesc);
+
+ /* Prepend the argument count. */
+ calldesc = tree_cons ((tree) 0,
+ build_int_2 (nargs, 0),
+ calldesc);
+
+ /* Push the address of the call description vector on the stack. */
+ calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
+ TREE_TYPE (calldesc) = build_array_type (integer_type_node,
+ build_index_type (build_int_2 (nargs * 2, 0)));
+ r = output_constant_def (calldesc);
+ bc_load_externaddr (r);
+
+ /* Push the address of the function to be called. */
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+
+ /* Call the function, popping its address and the calldesc vector
+ address off the evaluation stack in the process. */
+ bc_emit_instruction (call);
+
+ /* Pop the arguments off the stack. */
+ bc_adjust_stack (nargs);
+
+ /* Load the return value onto the stack. */
+ bc_load_localaddr (retval);
+ bc_load_memory (type, TREE_OPERAND (exp, 0));
+ }
+ return;
+
+ case SAVE_EXPR:
+
+ if (!SAVE_EXPR_RTL (exp))
+ {
+ /* First time around: copy to local variable */
+ SAVE_EXPR_RTL (exp) = bc_allocate_local (int_size_in_bytes (TREE_TYPE (exp)),
+ TYPE_ALIGN (TREE_TYPE(exp)));
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_emit_instruction (dup);
+
+ bc_load_localaddr (SAVE_EXPR_RTL (exp));
+ bc_store_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
+ }
+ else
+ {
+ /* Consecutive reference: use saved copy */
+ bc_load_localaddr (SAVE_EXPR_RTL (exp));
+ bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
+ }
+ return;
+
+#if 0
+ /* FIXME: the XXXX_STMT codes have been removed in GCC2, but
+ how are they handled instead? */
+ case LET_STMT:
+
+ TREE_USED (exp) = 1;
+ bc_expand_expr (STMT_BODY (exp));
+ return;
+#endif
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)), TREE_TYPE (exp));
+ return;
+
+ case MODIFY_EXPR:
+
+ expand_assignment (TREE_TYPE (exp), TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1));
+ return;
+
+ case ADDR_EXPR:
+
+ bc_expand_address (TREE_OPERAND (exp, 0));
+ return;
+
+ case INDIRECT_REF:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
+ return;
+
+ case ARRAY_REF:
+
+ bc_expand_expr (bc_canonicalize_array_ref (exp));
+ return;
+
+ case COMPONENT_REF:
+
+ bc_expand_component_address (exp);
+
+ /* If we have a bitfield, generate a proper load */
+ bc_load_memory (TREE_TYPE (TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1));
+ return;
+
+ case COMPOUND_EXPR:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_emit_instruction (drop);
+ bc_expand_expr (TREE_OPERAND (exp, 1));
+ return;
+
+ case COND_EXPR:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ lab = bc_get_bytecode_label ();
+ bc_emit_bytecode (jumpifnot);
+ bc_emit_bytecode_labelref (lab);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+ bc_expand_expr (TREE_OPERAND (exp, 1));
+ lab1 = bc_get_bytecode_label ();
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (lab1);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ bc_emit_bytecode_labeldef (lab);
+ bc_expand_expr (TREE_OPERAND (exp, 2));
+ bc_emit_bytecode_labeldef (lab1);
+ return;
+
+ case TRUTH_ANDIF_EXPR:
+
+ opcode = jumpifnot;
+ goto andorif;
+
+ case TRUTH_ORIF_EXPR:
+
+ opcode = jumpif;
+ goto andorif;
+
+ case PLUS_EXPR:
+
+ binoptab = optab_plus_expr;
+ goto binop;
+
+ case MINUS_EXPR:
+
+ binoptab = optab_minus_expr;
+ goto binop;
+
+ case MULT_EXPR:
+
+ binoptab = optab_mult_expr;
+ goto binop;
+
+ case TRUNC_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+
+ binoptab = optab_trunc_div_expr;
+ goto binop;
+
+ case TRUNC_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+
+ binoptab = optab_trunc_mod_expr;
+ goto binop;
+
+ case FIX_ROUND_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_CEIL_EXPR:
+ abort (); /* Not used for C. */
+
+ case FIX_TRUNC_EXPR:
+ case FLOAT_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case FFS_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ abort (); /* FIXME */
+
+ case RDIV_EXPR:
+
+ binoptab = optab_rdiv_expr;
+ goto binop;
+
+ case BIT_AND_EXPR:
+
+ binoptab = optab_bit_and_expr;
+ goto binop;
+
+ case BIT_IOR_EXPR:
+
+ binoptab = optab_bit_ior_expr;
+ goto binop;
+
+ case BIT_XOR_EXPR:
+
+ binoptab = optab_bit_xor_expr;
+ goto binop;
+
+ case LSHIFT_EXPR:
+
+ binoptab = optab_lshift_expr;
+ goto binop;
+
+ case RSHIFT_EXPR:
+
+ binoptab = optab_rshift_expr;
+ goto binop;
+
+ case TRUTH_AND_EXPR:
+
+ binoptab = optab_truth_and_expr;
+ goto binop;
+
+ case TRUTH_OR_EXPR:
+
+ binoptab = optab_truth_or_expr;
+ goto binop;
+
+ case LT_EXPR:
+
+ binoptab = optab_lt_expr;
+ goto binop;
+
+ case LE_EXPR:
+
+ binoptab = optab_le_expr;
+ goto binop;
+
+ case GE_EXPR:
+
+ binoptab = optab_ge_expr;
+ goto binop;
+
+ case GT_EXPR:
+
+ binoptab = optab_gt_expr;
+ goto binop;
+
+ case EQ_EXPR:
+
+ binoptab = optab_eq_expr;
+ goto binop;
+
+ case NE_EXPR:
+
+ binoptab = optab_ne_expr;
+ goto binop;
+
+ case NEGATE_EXPR:
+
+ unoptab = optab_negate_expr;
+ goto unop;
+
+ case BIT_NOT_EXPR:
+
+ unoptab = optab_bit_not_expr;
+ goto unop;
+
+ case TRUTH_NOT_EXPR:
+
+ unoptab = optab_truth_not_expr;
+ goto unop;
+
+ case PREDECREMENT_EXPR:
+
+ incroptab = optab_predecrement_expr;
+ goto increment;
+
+ case PREINCREMENT_EXPR:
+
+ incroptab = optab_preincrement_expr;
+ goto increment;
+
+ case POSTDECREMENT_EXPR:
+
+ incroptab = optab_postdecrement_expr;
+ goto increment;
+
+ case POSTINCREMENT_EXPR:
+
+ incroptab = optab_postincrement_expr;
+ goto increment;
+
+ case CONSTRUCTOR:
+
+ bc_expand_constructor (exp);
+ return;
+
+ case ERROR_MARK:
+ case RTL_EXPR:
+
+ return;
+
+ case BIND_EXPR:
+ {
+ tree vars = TREE_OPERAND (exp, 0);
+ int vars_need_expansion = 0;
+
+ /* Need to open a binding contour here because
+ if there are any cleanups they most be contained here. */
+ expand_start_bindings (0);
+
+ /* Mark the corresponding BLOCK for output. */
+ if (TREE_OPERAND (exp, 2) != 0)
+ TREE_USED (TREE_OPERAND (exp, 2)) = 1;
+
+ /* If VARS have not yet been expanded, expand them now. */
+ while (vars)
+ {
+ if (DECL_RTL (vars) == 0)
+ {
+ vars_need_expansion = 1;
+ bc_expand_decl (vars, 0);
+ }
+ bc_expand_decl_init (vars);
+ vars = TREE_CHAIN (vars);
+ }
+
+ bc_expand_expr (TREE_OPERAND (exp, 1));
+
+ expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
+
+ return;
+ }
+ }
+
+ abort ();
+
+ binop:
+
+ bc_expand_binary_operation (binoptab, TREE_TYPE (exp),
+ TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1));
+ return;
+
+
+ unop:
+
+ bc_expand_unary_operation (unoptab, TREE_TYPE (exp), TREE_OPERAND (exp, 0));
+ return;
+
+
+ andorif:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+ bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ lab = bc_get_bytecode_label ();
+
+ bc_emit_instruction (dup);
+ bc_emit_bytecode (opcode);
+ bc_emit_bytecode_labelref (lab);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ bc_emit_instruction (drop);
+
+ bc_expand_expr (TREE_OPERAND (exp, 1));
+ bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)));
+ bc_emit_bytecode_labeldef (lab);
+ return;
+
+
+ increment:
+
+ type = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+ /* Push the quantum. */
+ bc_expand_expr (TREE_OPERAND (exp, 1));
+
+ /* Convert it to the lvalue's type. */
+ bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)), type);
+
+ /* Push the address of the lvalue */
+ expand_expr (build1 (ADDR_EXPR, TYPE_POINTER_TO (type), TREE_OPERAND (exp, 0)));
+
+ /* Perform actual increment */
+ expand_increment (incroptab, type);
+ return;
+}
/* Return the alignment in bits of EXP, a pointer valued expression.
But don't return more than MAX_ALIGN no matter what.
@@ -7056,6 +7633,9 @@ expand_increment (exp, post)
int op0_is_copy = 0;
int single_insn = 0;
+ if (output_bytecode)
+ return bc_expand_increment (exp, post);
+
/* Stabilize any component ref that might need to be
evaluated more than once below. */
if (!post
@@ -8340,3 +8920,731 @@ do_tablejump (index, mode, range, table_label, default_label)
}
#endif /* HAVE_tablejump */
+
+
+/* Emit a suitable bytecode to load a value from memory, assuming a pointer
+ to that value is on the top of the stack. The resulting type is TYPE, and
+ the source declaration is DECL. */
+
+void
+bc_load_memory (type, decl)
+ tree type, decl;
+{
+ enum bytecode_opcode opcode;
+
+
+ /* Bit fields are special. We only know about signed and
+ unsigned ints, and enums. The latter are treated as
+ signed integers. */
+
+ if (DECL_BIT_FIELD (decl))
+ if (TREE_CODE (type) == ENUMERAL_TYPE
+ || TREE_CODE (type) == INTEGER_TYPE)
+ opcode = TREE_UNSIGNED (type) ? zxloadBI : sxloadBI;
+ else
+ abort ();
+ else
+ /* See corresponding comment in bc_store_memory(). */
+ if (TYPE_MODE (type) == BLKmode
+ || TYPE_MODE (type) == VOIDmode)
+ return;
+ else
+ opcode = mode_to_load_map [TYPE_MODE (type)];
+
+ if (opcode == neverneverland)
+ abort ();
+
+ bc_emit_bytecode (opcode);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
+/* Store the contents of the second stack slot to the address in the
+ top stack slot. DECL is the declaration of the destination and is used
+ to determine whether we're dealing with a bitfield. */
+
+void
+bc_store_memory (type, decl)
+ tree type, decl;
+{
+ enum bytecode_opcode opcode;
+
+
+ if (DECL_BIT_FIELD (decl))
+ {
+ if (TREE_CODE (type) == ENUMERAL_TYPE
+ || TREE_CODE (type) == INTEGER_TYPE)
+ opcode = sstoreBI;
+ else
+ abort ();
+ }
+ else
+ if (TYPE_MODE (type) == BLKmode)
+ {
+ /* Copy structure. This expands to a block copy instruction, storeBLK.
+ In addition to the arguments expected by the other store instructions,
+ it also expects a type size (SImode) on top of the stack, which is the
+ structure size in size units (usually bytes). The two first arguments
+ are already on the stack; so we just put the size on level 1. For some
+ other languages, the size may be variable, this is why we don't encode
+ it as a storeBLK literal, but rather treat it as a full-fledged expression. */
+
+ bc_expand_expr (TYPE_SIZE (type));
+ opcode = storeBLK;
+ }
+ else
+ opcode = mode_to_store_map [TYPE_MODE (type)];
+
+ if (opcode == neverneverland)
+ abort ();
+
+ bc_emit_bytecode (opcode);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
+/* Allocate local stack space sufficient to hold a value of the given
+ SIZE at alignment boundary ALIGNMENT bits. ALIGNMENT must be an
+ integral power of 2. A special case is locals of type VOID, which
+ have size 0 and alignment 1 - any "voidish" SIZE or ALIGNMENT is
+ remapped into the corresponding attribute of SI. */
+
+rtx
+bc_allocate_local (size, alignment)
+ int size, alignment;
+{
+ rtx retval;
+ int byte_alignment;
+
+ if (size < 0)
+ abort ();
+
+ /* Normalize size and alignment */
+ if (!size)
+ size = UNITS_PER_WORD;
+
+ if (alignment < BITS_PER_UNIT)
+ byte_alignment = 1 << (INT_ALIGN - 1);
+ else
+ /* Align */
+ byte_alignment = alignment / BITS_PER_UNIT;
+
+ if (local_vars_size & (byte_alignment - 1))
+ local_vars_size += byte_alignment - (local_vars_size & (byte_alignment - 1));
+
+ retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
+ local_vars_size += size;
+
+ return retval;
+}
+
+
+/* Allocate variable-sized local array. Variable-sized arrays are
+ actually pointers to the address in memory where they are stored. */
+
+rtx
+bc_allocate_variable_array (size)
+ tree size;
+{
+ rtx retval;
+ const int ptralign = (1 << (PTR_ALIGN - 1));
+
+ /* Align pointer */
+ if (local_vars_size & ptralign)
+ local_vars_size += ptralign - (local_vars_size & ptralign);
+
+ /* Note down local space needed: pointer to block; also return
+ dummy rtx */
+
+ retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
+ local_vars_size += POINTER_SIZE / BITS_PER_UNIT;
+ return retval;
+}
+
+
+/* Push the machine address for the given external variable offset. */
+void
+bc_load_externaddr (externaddr)
+ rtx externaddr;
+{
+ bc_emit_bytecode (constP);
+ bc_emit_code_labelref (externaddr->label, externaddr->offset);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
+static char *
+bc_strdup (s)
+ char *s;
+{
+ return strcpy (xmalloc ((strlen (s) + 1) * sizeof *s), s);
+}
+
+
+/* Like above, but expects an IDENTIFIER. */
+void
+bc_load_externaddr_id (id, offset)
+ tree id;
+ int offset;
+{
+ if (!IDENTIFIER_POINTER (id))
+ abort ();
+
+ bc_emit_bytecode (constP);
+ bc_emit_code_labelref (bc_xstrdup (IDENTIFIER_POINTER (id)), offset);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
+/* Push the machine address for the given local variable offset. */
+void
+bc_load_localaddr (localaddr)
+ rtx localaddr;
+{
+ bc_emit_instruction (localP, (HOST_WIDE_INT) localaddr->offset);
+}
+
+
+/* Push the machine address for the given parameter offset.
+ NOTE: offset is in bits. */
+void
+bc_load_parmaddr (parmaddr)
+ rtx parmaddr;
+{
+ bc_emit_instruction (argP, (HOST_WIDE_INT) parmaddr->offset / BITS_PER_UNIT);
+}
+
+
+/* Convert a[i] into *(a + i). */
+tree
+bc_canonicalize_array_ref (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+ tree array_adr = build1 (ADDR_EXPR, TYPE_POINTER_TO (type),
+ TREE_OPERAND (exp, 0));
+ tree index = TREE_OPERAND (exp, 1);
+
+
+ /* Convert the integer argument to a type the same size as a pointer
+ so the multiply won't overflow spuriously. */
+
+ if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE)
+ index = convert (type_for_size (POINTER_SIZE, 0), index);
+
+ /* The array address isn't volatile even if the array is.
+ (Of course this isn't terribly relevant since the bytecode
+ translator treats nearly everything as volatile anyway.) */
+ TREE_THIS_VOLATILE (array_adr) = 0;
+
+ return build1 (INDIRECT_REF, type,
+ fold (build (PLUS_EXPR,
+ TYPE_POINTER_TO (type),
+ array_adr,
+ fold (build (MULT_EXPR,
+ TYPE_POINTER_TO (type),
+ index,
+ size_in_bytes (type))))));
+}
+
+
+/* Load the address of the component referenced by the given
+ COMPONENT_REF expression.
+
+ Returns innermost lvalue. */
+
+tree
+bc_expand_component_address (exp)
+ tree exp;
+{
+ tree tem, chain;
+ enum machine_mode mode;
+ int bitpos = 0;
+ HOST_WIDE_INT SIval;
+
+
+ tem = TREE_OPERAND (exp, 1);
+ mode = DECL_MODE (tem);
+
+
+ /* Compute cumulative bit offset for nested component refs
+ and array refs, and find the ultimate containing object. */
+
+ for (tem = exp;; tem = TREE_OPERAND (tem, 0))
+ {
+ if (TREE_CODE (tem) == COMPONENT_REF)
+ bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (tem, 1)));
+ else
+ if (TREE_CODE (tem) == ARRAY_REF
+ && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)
+
+ bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))
+ * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))
+ /* * TYPE_SIZE_UNIT (TREE_TYPE (tem)) */);
+ else
+ break;
+ }
+
+ expand_expr (tem);
+
+
+ /* For bitfields also push their offset and size */
+ if (DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
+ bc_push_offset_and_size (bitpos, /* DECL_SIZE_UNIT */ (TREE_OPERAND (exp, 1)));
+ else
+ if (SIval = bitpos / BITS_PER_UNIT)
+ bc_emit_instruction (addconstPSI, SIval);
+
+ return (TREE_OPERAND (exp, 1));
+}
+
+
+/* Emit code to push two SI constants */
+void
+bc_push_offset_and_size (offset, size)
+ HOST_WIDE_INT offset, size;
+{
+ bc_emit_instruction (constSI, offset);
+ bc_emit_instruction (constSI, size);
+}
+
+
+/* Emit byte code to push the address of the given lvalue expression to
+ the stack. If it's a bit field, we also push offset and size info.
+
+ Returns innermost component, which allows us to determine not only
+ its type, but also whether it's a bitfield. */
+
+tree
+bc_expand_address (exp)
+ tree exp;
+{
+ /* Safeguard */
+ if (!exp || TREE_CODE (exp) == ERROR_MARK)
+ return (exp);
+
+
+ switch (TREE_CODE (exp))
+ {
+ case ARRAY_REF:
+
+ return (bc_expand_address (bc_canonicalize_array_ref (exp)));
+
+ case COMPONENT_REF:
+
+ return (bc_expand_component_address (exp));
+
+ case INDIRECT_REF:
+
+ bc_expand_expr (TREE_OPERAND (exp, 0));
+
+ /* For variable-sized types: retrieve pointer. Sometimes the
+ TYPE_SIZE tree is NULL. Is this a bug or a feature? Let's
+ also make sure we have an operand, just in case... */
+
+ if (TREE_OPERAND (exp, 0)
+ && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))) != INTEGER_CST)
+ bc_emit_instruction (loadP);
+
+ /* If packed, also return offset and size */
+ if (DECL_BIT_FIELD (TREE_OPERAND (exp, 0)))
+
+ bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (exp, 0))),
+ TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (exp, 0))));
+
+ return (TREE_OPERAND (exp, 0));
+
+ case FUNCTION_DECL:
+
+ bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), DECL_RTL (exp)->offset);
+ break;
+
+ case PARM_DECL:
+
+ bc_load_parmaddr (DECL_RTL (exp));
+
+ /* For variable-sized types: retrieve pointer */
+ if (TYPE_SIZE (TREE_TYPE (exp))
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
+ bc_emit_instruction (loadP);
+
+ /* If packed, also return offset and size */
+ if (DECL_BIT_FIELD (exp))
+ bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
+ TREE_INT_CST_LOW (DECL_SIZE (exp)));
+
+ break;
+
+ case RESULT_DECL:
+
+ bc_emit_instruction (returnP);
+ break;
+
+ case VAR_DECL:
+
+#if 0
+ if (DECL_RTL (exp)->label)
+ bc_load_externaddr (DECL_RTL (exp));
+#endif
+
+ if (DECL_EXTERNAL (exp))
+ bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), DECL_RTL (exp)->offset);
+ else
+ bc_load_localaddr (DECL_RTL (exp));
+
+ /* For variable-sized types: retrieve pointer */
+ if (TYPE_SIZE (TREE_TYPE (exp))
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
+ bc_emit_instruction (loadP);
+
+ /* If packed, also return offset and size */
+ if (DECL_BIT_FIELD (exp))
+ bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
+ TREE_INT_CST_LOW (DECL_SIZE (exp)));
+
+ break;
+
+ case STRING_CST:
+ {
+ rtx r;
+
+ bc_emit_bytecode (constP);
+ r = output_constant_def (exp);
+ bc_emit_code_labelref (r->label, r->offset);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+ }
+ break;
+
+ default:
+
+ abort();
+ break;
+ }
+
+ /* Most lvalues don't have components. */
+ return (exp);
+}
+
+
+/* Emit a type code to be used by the runtime support in handling
+ parameter passing. The type code consists of the machine mode
+ plus the minimal alignment shifted left 8 bits. */
+
+tree
+bc_runtime_type_code (type)
+ tree type;
+{
+ int val;
+
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case ENUMERAL_TYPE:
+ case POINTER_TYPE:
+ case RECORD_TYPE:
+
+ val = TYPE_MODE (type) | TYPE_ALIGN (type) << 8;
+ break;
+
+ case ERROR_MARK:
+
+ val = 0;
+ break;
+
+ default:
+
+ abort ();
+ }
+ return build_int_2 (val, 0);
+}
+
+
+/* Generate constructor label */
+char *
+bc_gen_constr_label ()
+{
+ static int label_counter;
+ static char label[20];
+
+ sprintf (label, "*LR%d", label_counter++);
+
+ return (obstack_copy0 (&permanent_obstack, label, strlen (label)));
+}
+
+
+/* Evaluate constructor CONSTR and return pointer to it on level one. We
+ expand the constructor data as static data, and push a pointer to it.
+ The pointer is put in the pointer table and is retrieved by a constP
+ bytecode instruction. We then loop and store each constructor member in
+ the corresponding component. Finally, we return the original pointer on
+ the stack. */
+
+void
+bc_expand_constructor (constr)
+ tree constr;
+{
+ char *l;
+ HOST_WIDE_INT ptroffs;
+ rtx constr_rtx;
+
+
+ /* Literal constructors are handled as constants, whereas
+ non-literals are evaluated and stored element by element
+ into the data segment. */
+
+ /* Allocate space in proper segment and push pointer to space on stack.
+ */
+
+ l = bc_gen_constr_label ();
+
+ if (TREE_CONSTANT (constr))
+ {
+ text_section ();
+
+ bc_emit_const_labeldef (l);
+ bc_output_constructor (constr, int_size_in_bytes (TREE_TYPE (constr)));
+ }
+ else
+ {
+ data_section ();
+
+ bc_emit_data_labeldef (l);
+ bc_output_data_constructor (constr);
+ }
+
+
+ /* Add reference to pointer table and recall pointer to stack;
+ this code is common for both types of constructors: literals
+ and non-literals. */
+
+ bc_emit_instruction (constP, (HOST_WIDE_INT) ptroffs = bc_define_pointer (l));
+
+ /* This is all that has to be done if it's a literal. */
+ if (TREE_CONSTANT (constr))
+ return;
+
+
+ /* At this point, we have the pointer to the structure on top of the stack.
+ Generate sequences of store_memory calls for the constructor. */
+
+ /* constructor type is structure */
+ if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE)
+ {
+ register tree elt;
+
+ /* If the constructor has fewer fields than the structure,
+ clear the whole structure first. */
+
+ if (list_length (CONSTRUCTOR_ELTS (constr))
+ != list_length (TYPE_FIELDS (TREE_TYPE (constr))))
+ {
+ bc_emit_instruction (dup);
+ bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
+ bc_emit_instruction (clearBLK);
+ }
+
+ /* Store each element of the constructor into the corresponding
+ field of TARGET. */
+
+ for (elt = CONSTRUCTOR_ELTS (constr); elt; elt = TREE_CHAIN (elt))
+ {
+ register tree field = TREE_PURPOSE (elt);
+ register enum machine_mode mode;
+ int bitsize;
+ int bitpos;
+ int unsignedp;
+
+ bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) /* * DECL_SIZE_UNIT (field) */;
+ mode = DECL_MODE (field);
+ unsignedp = TREE_UNSIGNED (field);
+
+ bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+
+ bc_store_field (elt, bitsize, bitpos, mode, TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
+ /* The alignment of TARGET is
+ at least what its type requires. */
+ VOIDmode, 0,
+ TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
+ int_size_in_bytes (TREE_TYPE (constr)));
+ }
+ }
+ else
+
+ /* Constructor type is array */
+ if (TREE_CODE (TREE_TYPE (constr)) == ARRAY_TYPE)
+ {
+ register tree elt;
+ register int i;
+ tree domain = TYPE_DOMAIN (TREE_TYPE (constr));
+ int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
+ int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
+ tree elttype = TREE_TYPE (TREE_TYPE (constr));
+
+ /* If the constructor has fewer fields than the structure,
+ clear the whole structure first. */
+
+ if (list_length (CONSTRUCTOR_ELTS (constr)) < maxelt - minelt + 1)
+ {
+ bc_emit_instruction (dup);
+ bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
+ bc_emit_instruction (clearBLK);
+ }
+
+
+ /* Store each element of the constructor into the corresponding
+ element of TARGET, determined by counting the elements. */
+
+ for (elt = CONSTRUCTOR_ELTS (constr), i = 0;
+ elt;
+ elt = TREE_CHAIN (elt), i++)
+ {
+ register enum machine_mode mode;
+ int bitsize;
+ int bitpos;
+ int unsignedp;
+
+ mode = TYPE_MODE (elttype);
+ bitsize = GET_MODE_BITSIZE (mode);
+ unsignedp = TREE_UNSIGNED (elttype);
+
+ bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))
+ /* * TYPE_SIZE_UNIT (elttype) */ );
+
+ bc_store_field (elt, bitsize, bitpos, mode,
+ TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
+ /* The alignment of TARGET is
+ at least what its type requires. */
+ VOIDmode, 0,
+ TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
+ int_size_in_bytes (TREE_TYPE (constr)));
+ }
+
+ }
+}
+
+
+/* Store the value of EXP (an expression tree) into member FIELD of
+ structure at address on stack, which has type TYPE, mode MODE and
+ occupies BITSIZE bits, starting BITPOS bits from the beginning of the
+ structure.
+
+ ALIGN is the alignment that TARGET is known to have, measured in bytes.
+ TOTAL_SIZE is its size in bytes, or -1 if variable. */
+
+void
+bc_store_field (field, bitsize, bitpos, mode, exp, type,
+ value_mode, unsignedp, align, total_size)
+ int bitsize, bitpos;
+ enum machine_mode mode;
+ tree field, exp, type;
+ enum machine_mode value_mode;
+ int unsignedp;
+ int align;
+ int total_size;
+{
+
+ /* Expand expression and copy pointer */
+ bc_expand_expr (exp);
+ bc_emit_instruction (over);
+
+
+ /* If the component is a bit field, we cannot use addressing to access
+ it. Use bit-field techniques to store in it. */
+
+ if (DECL_BIT_FIELD (field))
+ {
+ bc_store_bit_field (bitpos, bitsize, unsignedp);
+ return;
+ }
+ else
+ /* Not bit field */
+ {
+ HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
+
+ /* Advance pointer to the desired member */
+ if (offset)
+ bc_emit_instruction (addconstPSI, offset);
+
+ /* Store */
+ bc_store_memory (type, field);
+ }
+}
+
+
+/* Store SI/SU in bitfield */
+void
+bc_store_bit_field (offset, size, unsignedp)
+ int offset, size, unsignedp;
+{
+ /* Push bitfield offset and size */
+ bc_push_offset_and_size (offset, size);
+
+ /* Store */
+ bc_emit_instruction (sstoreBI);
+}
+
+
+/* Load SI/SU from bitfield */
+void
+bc_load_bit_field (offset, size, unsignedp)
+ int offset, size, unsignedp;
+{
+ /* Push bitfield offset and size */
+ bc_push_offset_and_size (offset, size);
+
+ /* Load: sign-extend if signed, else zero-extend */
+ bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
+}
+
+
+/* Adjust interpreter stack by NLEVELS. Positive means drop NLEVELS
+ (adjust stack pointer upwards), negative means add that number of
+ levels (adjust the stack pointer downwards). Only positive values
+ normally make sense. */
+
+void
+bc_adjust_stack (nlevels)
+ int nlevels;
+{
+ switch (nlevels)
+ {
+ case 0:
+ break;
+
+ case 2:
+ bc_emit_instruction (drop);
+
+ case 1:
+ bc_emit_instruction (drop);
+ break;
+
+ default:
+
+ bc_emit_instruction (adjstackSI, (HOST_WIDE_INT) nlevels);
+ stack_depth -= nlevels;
+ }
+
+#if defined (VALIDATE_STACK)
+ VALIDATE_STACK ();
+#endif
+}
diff --git a/gcc/integrate.c b/gcc/integrate.c
index a41e9b6..c5e0494 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "integrate.h"
#include "real.h"
#include "function.h"
+#include "bytecode.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
@@ -2850,9 +2851,16 @@ void
output_inline_function (fndecl)
tree fndecl;
{
- rtx head = DECL_SAVED_INSNS (fndecl);
+ rtx head;
rtx last;
+ if (output_bytecode)
+ {
+ warning ("`inline' ignored for bytecode output");
+ return;
+ }
+
+ head = DECL_SAVED_INSNS (fndecl);
current_function_decl = fndecl;
/* This call is only used to initialize global variables. */
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 1960355..47da72f 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "recog.h"
#include "reload.h"
#include "real.h"
+#include "bytecode.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
@@ -413,6 +414,13 @@ fix_register (name, fixed, call_used)
{
int i;
+ if (output_bytecode)
+ {
+ warning ("request to mark `%s' as %s ignored by bytecode compiler",
+ name, call_used ? "call-used" : "fixed");
+ return;
+ }
+
/* Decode the name and update the primary form of
the register info. */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index d6bfac8..945fbc8 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -139,6 +139,22 @@ typedef struct rtx_def
The number of operands and their types are controlled
by the `code' field, according to rtl.def. */
rtunion fld[1];
+
+ /* The rest is used instead of the above if bytecode is being output */
+
+ /* For static or external objects. */
+ char *label;
+
+ /* From the named label, or the local variable pointer or the
+ argument pointer, depending on context. */
+
+ int offset;
+
+ /* For goto labels inside bytecode functions. */
+ struct bc_label *bc_label;
+
+ /* A unique identifier */
+ int uid;
} *rtx;
/* Add prototype support. */
@@ -640,6 +656,7 @@ extern rtx gen_rtx PROTO((enum rtx_code, enum machine_mode, ...));
extern rtvec gen_rtvec PROTO((int, ...));
#else
+extern rtx bc_gen_rtx ();
extern rtx gen_rtx ();
extern rtvec gen_rtvec ();
#endif
diff --git a/gcc/stmt.c b/gcc/stmt.c
index c4e34c9..2b9ff91 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -49,6 +49,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h"
#include "loop.h"
#include "recog.h"
+#include "machmode.h"
+
+#include "bytecode.h"
+#include "bc-typecd.h"
+#include "bc-opcode.h"
+#include "bc-optab.h"
+#include "bc-emit.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -181,13 +188,28 @@ static void emit_jump_if_reachable ();
static int warn_if_unused_value ();
static void expand_goto_internal ();
+static void bc_expand_goto_internal ();
static int expand_fixup ();
+static void bc_expand_fixup ();
void fixup_gotos ();
+static void bc_fixup_gotos ();
void free_temp_slots ();
static void expand_cleanups ();
static void expand_null_return_1 ();
static int tail_recursion_args ();
static void do_jump_if_equal ();
+int bc_expand_exit_loop_if_false ();
+void bc_expand_start_cond ();
+void bc_expand_end_cond ();
+void bc_expand_start_else ();
+void bc_expand_end_bindings ();
+void bc_expand_start_case ();
+void bc_check_for_full_enumeration_handling ();
+void bc_expand_end_case ();
+void bc_expand_decl ();
+
+extern rtx bc_allocate_local ();
+extern rtx bc_allocate_variable_array ();
/* Stack of control and binding constructs we are currently inside.
@@ -250,7 +272,8 @@ struct nesting
/* Sequence number of this binding contour within the function,
in order of entry. */
int block_start_count;
- /* Nonzero => value to restore stack to on exit. */
+ /* Nonzero => value to restore stack to on exit. Complemented by
+ bc_stack_level (see below) when generating bytecodes. */
rtx stack_level;
/* The NOTE that starts this contour.
Used by expand_goto to check whether the destination
@@ -277,6 +300,8 @@ struct nesting
struct label_chain *label_chain;
/* Number of function calls seen, as of start of this block. */
int function_call_count;
+ /* Bytecode specific: stack level to restore stack to on exit. */
+ int bc_stack_level;
} block;
/* For switch (C) or case (Pascal) statements,
and also for dummies (see `expand_start_case_dummy'). */
@@ -285,6 +310,10 @@ struct nesting
/* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */
rtx start;
+ /* For bytecodes, the case table is in-lined right in the code.
+ A label is needed for skipping over this block. It is only
+ used when generating bytecodes. */
+ rtx skip_label;
/* A list of case labels, kept in ascending order by value
as the list is built.
During expand_end_case, this list may be rearranged into a
@@ -425,6 +454,21 @@ struct goto_fixup
time this goto was seen.
The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
tree cleanup_list_list;
+
+ /* Bytecode specific members follow */
+
+ /* The label that this jump is jumping to, or 0 for break, continue
+ or return. */
+ struct bc_label *bc_target;
+
+ /* The label we use for the fixup patch */
+ struct bc_label *label;
+
+ /* True (non-0) if fixup has been handled */
+ int bc_handled:1;
+
+ /* Like stack_level above, except refers to the interpreter stack */
+ int bc_stack_level;
};
static struct goto_fixup *goto_fixup_chain;
@@ -514,11 +558,16 @@ restore_stmt_status (p)
void
emit_nop ()
{
- rtx last_insn = get_last_insn ();
- if (!optimize
- && (GET_CODE (last_insn) == CODE_LABEL
- || prev_real_insn (last_insn) == 0))
- emit_insn (gen_nop ());
+ rtx last_insn;
+
+ if (!output_bytecode)
+ {
+ last_insn = get_last_insn ();
+ if (!optimize
+ && (GET_CODE (last_insn) == CODE_LABEL
+ || prev_real_insn (last_insn) == 0))
+ emit_insn (gen_nop ());
+ }
}
/* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -555,9 +604,17 @@ void
expand_computed_goto (exp)
tree exp;
{
- rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
- emit_queue ();
- emit_indirect_jump (x);
+ if (output_bytecode)
+ {
+ bc_expand_expr (exp);
+ bc_emit_instruction (jumpP);
+ }
+ else
+ {
+ rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ emit_queue ();
+ emit_indirect_jump (x);
+ }
}
/* Handle goto statements and the labels that they can go to. */
@@ -579,6 +636,15 @@ expand_label (label)
{
struct label_chain *p;
+ if (output_bytecode)
+ {
+ if (! DECL_RTL (label))
+ DECL_RTL (label) = bc_gen_rtx ((char *) 0, 0, bc_get_bytecode_label ());
+ if (! bc_emit_bytecode_labeldef (DECL_RTL (label)->bc_label))
+ error ("multiply defined label");
+ return;
+ }
+
do_pending_stack_adjust ();
emit_label (label_rtx (label));
if (DECL_NAME (label))
@@ -620,8 +686,16 @@ void
expand_goto (label)
tree label;
{
+ tree context;
+
+ if (output_bytecode)
+ {
+ expand_goto_internal (label, label_rtx (label), NULL_RTX);
+ return;
+ }
+
/* Check for a nonlocal goto to a containing function. */
- tree context = decl_function_context (label);
+ context = decl_function_context (label);
if (context != 0 && context != current_function_decl)
{
struct function *p = find_function_data (context);
@@ -701,6 +775,16 @@ expand_goto_internal (body, label, last_insn)
struct nesting *block;
rtx stack_level = 0;
+ /* NOTICE! If a bytecode instruction other than `jump' is needed,
+ then the caller has to call bc_expand_goto_internal()
+ directly. This is rather an exceptional case, and there aren't
+ that many places where this is necessary. */
+ if (output_bytecode)
+ {
+ expand_goto_internal (body, label, last_insn);
+ return;
+ }
+
if (GET_CODE (label) != CODE_LABEL)
abort ();
@@ -753,6 +837,77 @@ expand_goto_internal (body, label, last_insn)
emit_jump (label);
}
+/* Generate a jump with OPCODE to the given bytecode LABEL which is
+ found within BODY. */
+static void
+bc_expand_goto_internal (opcode, label, body)
+ enum bytecode_opcode opcode;
+ struct bc_label *label;
+ tree body;
+{
+ struct nesting *block;
+ int stack_level = -1;
+
+ /* If the label is defined, adjust the stack as necessary.
+ If it's not defined, we have to push the reference on the
+ fixup list. */
+
+ if (label->defined)
+ {
+
+ /* Find the innermost pending block that contains the label.
+ (Check containment by comparing bytecode uids.) Then restore the
+ outermost stack level within that block. */
+
+ for (block = block_stack; block; block = block->next)
+ {
+ if (block->data.block.first_insn->uid < label->uid)
+ break;
+ if (block->data.block.bc_stack_level)
+ stack_level = block->data.block.bc_stack_level;
+
+ /* Execute the cleanups for blocks we are exiting. */
+ if (block->data.block.cleanups != 0)
+ {
+ expand_cleanups (block->data.block.cleanups, NULL_TREE);
+ do_pending_stack_adjust ();
+ }
+ }
+
+ /* Restore the stack level. If we need to adjust the stack, we
+ must do so after the jump, since the jump may depend on
+ what's on the stack. Thus, any stack-modifying conditional
+ jumps (these are the only ones that rely on what's on the
+ stack) go into the fixup list. */
+
+ if (stack_level >= 0
+ && stack_depth != stack_level
+ && opcode != jump)
+
+ bc_expand_fixup (opcode, label, stack_level);
+ else
+ {
+ if (stack_level >= 0)
+ bc_adjust_stack (stack_depth - stack_level);
+
+ if (body && DECL_BIT_FIELD (body))
+ error ("jump to `%s' invalidly jumps into binding contour",
+ IDENTIFIER_POINTER (DECL_NAME (body)));
+
+ /* Emit immediate jump */
+ bc_emit_bytecode (opcode);
+ bc_emit_bytecode_labelref (label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+ }
+ }
+ else
+ /* Put goto in the fixup list */
+ bc_expand_fixup (opcode, label, stack_level);
+}
+
/* Generate if necessary a fixup for a goto
whose target label in tree structure (if any) is TREE_LABEL
and whose target in rtl is RTL_LABEL.
@@ -884,6 +1039,37 @@ expand_fixup (tree_label, rtl_label, last_insn)
return block != 0;
}
+
+/* Generate bytecode jump with OPCODE to a fixup routine that links to LABEL.
+ Make the fixup restore the stack level to STACK_LEVEL. */
+
+static void
+bc_expand_fixup (opcode, label, stack_level)
+ enum bytecode_opcode opcode;
+ struct bc_label *label;
+ int stack_level;
+{
+ struct goto_fixup *fixup
+ = (struct goto_fixup *) oballoc (sizeof (struct goto_fixup));
+
+ fixup->label = bc_get_bytecode_label ();
+ fixup->bc_target = label;
+ fixup->bc_stack_level = stack_level;
+ fixup->bc_handled = FALSE;
+
+ fixup->next = goto_fixup_chain;
+ goto_fixup_chain = fixup;
+
+ /* Insert a jump to the fixup code */
+ bc_emit_bytecode (opcode);
+ bc_emit_bytecode_labelref (fixup->label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
/* When exiting a binding contour, process all pending gotos requiring fixups.
THISBLOCK is the structure that describes the block being exited.
STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
@@ -907,6 +1093,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
{
register struct goto_fixup *f, *prev;
+ if (output_bytecode)
+ {
+ bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in);
+ return;
+ }
+
/* F is the fixup we are considering; PREV is the previous one. */
/* We run this loop in two passes so that cleanups of exited blocks
are run first, and blocks that are exited are marked so
@@ -1039,6 +1231,72 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
f->stack_level = stack_level;
}
}
+
+
+/* When exiting a binding contour, process all pending gotos requiring fixups.
+ Note: STACK_DEPTH is not altered.
+
+ The arguments are currently not used in the bytecode compiler, but we may need
+ them one day for languages other than C.
+
+ THISBLOCK is the structure that describes the block being exited.
+ STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
+ CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
+ FIRST_INSN is the insn that began this contour.
+
+ Gotos that jump out of this contour must restore the
+ stack level and do the cleanups before actually jumping.
+
+ DONT_JUMP_IN nonzero means report error there is a jump into this
+ contour from before the beginning of the contour.
+ This is also done if STACK_LEVEL is nonzero. */
+
+static void
+bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
+ struct nesting *thisblock;
+ int stack_level;
+ tree cleanup_list;
+ rtx first_insn;
+ int dont_jump_in;
+{
+ register struct goto_fixup *f, *prev;
+ int saved_stack_depth;
+
+ /* F is the fixup we are considering; PREV is the previous one. */
+
+ for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
+ {
+ /* Test for a fixup that is inactive because it is already handled. */
+ if (f->before_jump == 0)
+ {
+ /* Delete inactive fixup from the chain, if that is easy to do. */
+ if (prev)
+ prev->next = f->next;
+ }
+
+ /* Emit code to restore the stack and continue */
+ bc_emit_bytecode_labeldef (f->label);
+
+ /* Save stack_depth across call, since bc_adjust_stack () will alter
+ the perceived stack depth via the instructions generated. */
+
+ if (f->bc_stack_level >= 0)
+ {
+ saved_stack_depth = stack_depth;
+ bc_adjust_stack (stack_depth - f->bc_stack_level);
+ stack_depth = saved_stack_depth;
+ }
+
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (f->bc_target);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+ }
+
+ goto_fixup_chain = NULL;
+}
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
@@ -1048,6 +1306,12 @@ void
expand_asm (body)
tree body;
{
+ if (output_bytecode)
+ {
+ error ("`asm' is illegal when generating bytecode");
+ return;
+ }
+
if (TREE_CODE (body) == ADDR_EXPR)
body = TREE_OPERAND (body, 0);
@@ -1090,6 +1354,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* The insn we have emitted. */
rtx insn;
+ if (output_bytecode)
+ {
+ error ("`asm' is illegal when generating bytecode");
+ return;
+ }
+
/* Count the number of meaningful clobbered registers, ignoring what
we would ignore later. */
nclobbers = 0;
@@ -1310,6 +1580,22 @@ void
expand_expr_stmt (exp)
tree exp;
{
+ if (output_bytecode)
+ {
+ int org_stack_depth = stack_depth;
+
+ bc_expand_expr (exp);
+
+ /* Restore stack depth */
+ if (stack_depth < org_stack_depth)
+ abort ();
+
+ bc_emit_instruction (drop);
+
+ last_expr_type = TREE_TYPE (exp);
+ return;
+ }
+
/* If -W, warn about statements with no side effects,
except for an explicit cast to void (e.g. for assert()), and
except inside a ({...}) where they may be useful. */
@@ -1459,10 +1745,17 @@ clear_last_expr ()
tree
expand_start_stmt_expr ()
{
+ int momentary;
+ tree t;
+
+ /* When generating bytecode just note down the stack depth */
+ if (output_bytecode)
+ return (build_int_2 (stack_depth, 0));
+
/* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */
- int momentary = suspend_momentary ();
- tree t = make_node (RTL_EXPR);
+ momentary = suspend_momentary ();
+ t = make_node (RTL_EXPR);
resume_momentary (momentary);
start_sequence ();
NO_DEFER_POP;
@@ -1486,6 +1779,38 @@ tree
expand_end_stmt_expr (t)
tree t;
{
+ if (output_bytecode)
+ {
+ int i;
+ tree t;
+
+
+ /* At this point, all expressions have been evaluated in order.
+ However, all expression values have been popped when evaluated,
+ which means we have to recover the last expression value. This is
+ the last value removed by means of a `drop' instruction. Instead
+ of adding code to inhibit dropping the last expression value, it
+ is here recovered by undoing the `drop'. Since `drop' is
+ equivalent to `adjustackSI [1]', it can be undone with `adjstackSI
+ [-1]'. */
+
+ bc_adjust_stack (-1);
+
+ if (!last_expr_type)
+ last_expr_type = void_type_node;
+
+ t = make_node (RTL_EXPR);
+ TREE_TYPE (t) = last_expr_type;
+ RTL_EXPR_RTL (t) = NULL;
+ RTL_EXPR_SEQUENCE (t) = NULL;
+
+ /* Don't consider deleting this expr or containing exprs at tree level. */
+ TREE_THIS_VOLATILE (t) = 1;
+
+ last_expr_type = 0;
+ return t;
+ }
+
OK_DEFER_POP;
if (last_expr_type == 0)
@@ -1849,7 +2174,10 @@ expand_start_cond (cond, exitflag)
cond_stack = thiscond;
nesting_stack = thiscond;
- do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
+ if (output_bytecode)
+ bc_expand_start_cond (cond, exitflag);
+ else
+ do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
}
/* Generate RTL between then-clause and the elseif-clause
@@ -1875,6 +2203,13 @@ expand_start_else ()
{
if (cond_stack->data.cond.endif_label == 0)
cond_stack->data.cond.endif_label = gen_label_rtx ();
+
+ if (output_bytecode)
+ {
+ bc_expand_start_else ();
+ return;
+ }
+
emit_jump (cond_stack->data.cond.endif_label);
emit_label (cond_stack->data.cond.next_label);
cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
@@ -1888,15 +2223,71 @@ expand_end_cond ()
{
struct nesting *thiscond = cond_stack;
- do_pending_stack_adjust ();
- if (thiscond->data.cond.next_label)
- emit_label (thiscond->data.cond.next_label);
- if (thiscond->data.cond.endif_label)
- emit_label (thiscond->data.cond.endif_label);
+ if (output_bytecode)
+ bc_expand_end_cond ();
+ else
+ {
+ do_pending_stack_adjust ();
+ if (thiscond->data.cond.next_label)
+ emit_label (thiscond->data.cond.next_label);
+ if (thiscond->data.cond.endif_label)
+ emit_label (thiscond->data.cond.endif_label);
+ }
POPSTACK (cond_stack);
last_expr_type = 0;
}
+
+
+/* Generate code for the start of an if-then. COND is the expression
+ whose truth is to be tested; if EXITFLAG is nonzero this conditional
+ is to be visible to exit_something. It is assumed that the caller
+ has pushed the previous context on the cond stack. */
+void
+bc_expand_start_cond (cond, exitflag)
+ tree cond;
+ int exitflag;
+{
+ struct nesting *thiscond = cond_stack;
+
+ thiscond->data.case_stmt.nominal_type = cond;
+ bc_expand_expr (cond);
+ bc_emit_bytecode (jumpifnot);
+ bc_emit_bytecode_labelref (thiscond->exit_label->bc_label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+/* Generate the label for the end of an if with
+ no else- clause. */
+void
+bc_expand_end_cond ()
+{
+ struct nesting *thiscond = cond_stack;
+
+ bc_emit_bytecode_labeldef (thiscond->exit_label->bc_label);
+}
+
+/* Generate code for the start of the else- clause of
+ an if-then-else. */
+void
+bc_expand_start_else ()
+{
+ struct nesting *thiscond = cond_stack;
+
+ thiscond->data.cond.endif_label = thiscond->exit_label;
+ thiscond->exit_label = gen_label_rtx ();
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (thiscond->exit_label->bc_label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ bc_emit_bytecode_labeldef (thiscond->data.cond.endif_label->bc_label);
+}
/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
loop should be exited by `exit_something'. This is a loop for which
@@ -1923,6 +2314,12 @@ expand_start_loop (exit_flag)
loop_stack = thisloop;
nesting_stack = thisloop;
+ if (output_bytecode)
+ {
+ bc_emit_bytecode_labeldef (thisloop->data.loop.start_label->bc_label);
+ return thisloop;
+ }
+
do_pending_stack_adjust ();
emit_queue ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
@@ -1951,21 +2348,54 @@ expand_start_loop_continue_elsewhere (exit_flag)
void
expand_loop_continue_here ()
{
+ if (output_bytecode)
+ {
+ bc_emit_bytecode_labeldef (loop_stack->data.loop.continue_label->bc_label);
+ return;
+ }
do_pending_stack_adjust ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
emit_label (loop_stack->data.loop.continue_label);
}
+/* End a loop. */
+static void
+bc_expand_end_loop ()
+{
+ struct nesting *thisloop = loop_stack;
+
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (thisloop->data.loop.start_label->bc_label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ bc_emit_bytecode_labeldef (thisloop->exit_label->bc_label);
+ POPSTACK (loop_stack);
+ last_expr_type = 0;
+}
+
+
/* Finish a loop. Generate a jump back to the top and the loop-exit label.
Pop the block off of loop_stack. */
void
expand_end_loop ()
{
- register rtx insn = get_last_insn ();
- register rtx start_label = loop_stack->data.loop.start_label;
+ register rtx insn;
+ register rtx start_label;
rtx last_test_insn = 0;
int num_insns = 0;
+
+ if (output_bytecode)
+ {
+ bc_expand_end_loop ();
+ return;
+ }
+
+ insn = get_last_insn ();
+ start_label = loop_stack->data.loop.start_label;
/* Mark the continue-point at the top of the loop if none elsewhere. */
if (start_label == loop_stack->data.loop.continue_label)
@@ -2113,7 +2543,15 @@ expand_exit_loop_if_false (whichloop, cond)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
- do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
+ if (output_bytecode)
+ {
+ bc_expand_expr (cond);
+ bc_expand_goto_internal (jumpifnot,
+ whichloop->exit_label->bc_label, NULL_RTX);
+ }
+ else
+ do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
+
return 1;
}
@@ -2176,6 +2614,12 @@ expand_null_return ()
struct nesting *block = block_stack;
rtx last_insn = 0;
+ if (output_bytecode)
+ {
+ bc_emit_instruction (ret);
+ return;
+ }
+
/* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0)
@@ -2298,6 +2742,15 @@ expand_return (retval)
int cleanups;
struct nesting *block;
+ /* Bytecode returns are quite simple, just leave the result on the
+ arithmetic stack. */
+ if (output_bytecode)
+ {
+ bc_expand_expr (retval);
+ bc_emit_instruction (ret);
+ return;
+ }
+
/* If function wants no value, give it none. */
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{
@@ -2536,8 +2989,10 @@ expand_start_bindings (exit_flag)
int exit_flag;
{
struct nesting *thisblock = ALLOC_NESTING ();
+ rtx note;
- rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ if (!output_bytecode)
+ note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
/* Make an entry on block_stack for the block we are entering. */
@@ -2580,8 +3035,11 @@ expand_start_bindings (exit_flag)
block_stack = thisblock;
nesting_stack = thisblock;
- /* Make a new level for allocating stack slots. */
- push_temp_slots ();
+ if (!output_bytecode)
+ {
+ /* Make a new level for allocating stack slots. */
+ push_temp_slots ();
+ }
}
/* Given a pointer to a BLOCK node, save a pointer to the most recently
@@ -2614,6 +3072,12 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
register struct nesting *thisblock = block_stack;
register tree decl;
+ if (output_bytecode)
+ {
+ bc_expand_end_bindings (vars, mark_ends, dont_jump_in);
+ return;
+ }
+
if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
@@ -2830,6 +3294,35 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
/* Pop the stack slot nesting and free any slots at this level. */
pop_temp_slots ();
}
+
+
+/* End a binding contour.
+ VARS is the chain of VAR_DECL nodes for the variables bound
+ in this contour. MARK_ENDS is nonzer if we should put a note
+ at the beginning and end of this binding contour.
+ DONT_JUMP_IN is nonzero if it is not valid to jump into this
+ contour. */
+
+void
+bc_expand_end_bindings (vars, mark_ends, dont_jump_in)
+ tree vars;
+ int mark_ends;
+ int dont_jump_in;
+{
+ struct nesting *thisbind = nesting_stack;
+ tree decl;
+
+ if (warn_unused)
+ for (decl = vars; decl; decl = TREE_CHAIN (decl))
+ if (! TREE_USED (TREE_VALUE (decl)) && TREE_CODE (TREE_VALUE (decl)) == VAR_DECL)
+ warning_with_decl (decl, "unused variable `%s'");
+
+ bc_emit_bytecode_labeldef (thisbind->exit_label->bc_label);
+
+ /* Pop block/bindings off stack */
+ POPSTACK (nesting_stack);
+ POPSTACK (block_stack);
+}
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.)
@@ -2854,7 +3347,15 @@ expand_decl (decl)
register tree decl;
{
struct nesting *thisblock = block_stack;
- tree type = TREE_TYPE (decl);
+ tree type;
+
+ if (output_bytecode)
+ {
+ bc_expand_decl (decl, 0);
+ return;
+ }
+
+ type = TREE_TYPE (decl);
/* Only automatic variables need any expansion done.
Static and external variables, and external functions,
@@ -3046,6 +3547,52 @@ expand_decl (decl)
if (obey_regdecls)
use_variable (DECL_RTL (decl));
}
+
+
+/* Generate code for the automatic variable declaration DECL. For
+ most variables this just means we give it a stack offset. The
+ compiler sometimes emits cleanups without variables and we will
+ have to deal with those too. */
+
+void
+bc_expand_decl (decl, cleanup)
+ tree decl;
+ tree cleanup;
+{
+ tree type;
+
+ if (!decl)
+ {
+ /* A cleanup with no variable. */
+ if (!cleanup)
+ abort ();
+
+ return;
+ }
+
+ /* Only auto variables need any work. */
+ if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ return;
+
+ type = TREE_TYPE (decl);
+
+ if (type == error_mark_node)
+ DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
+
+ else if (DECL_SIZE (decl) == 0)
+
+ /* Variable with incomplete type. The stack offset herein will be
+ fixed later in expand_decl_init (). */
+ DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
+
+ else if (TREE_CONSTANT (DECL_SIZE (decl)))
+ {
+ DECL_RTL (decl) = bc_allocate_local (TREE_INT_CST_LOW (DECL_SIZE (decl)) / BITS_PER_UNIT,
+ DECL_ALIGN (decl));
+ }
+ else
+ DECL_RTL (decl) = bc_allocate_variable_array (DECL_SIZE (decl));
+}
/* Emit code to perform the initialization of a declaration DECL. */
@@ -3083,6 +3630,82 @@ expand_decl_init (decl)
free_temp_slots ();
}
+/* Expand initialization for variable-sized types. Allocate array
+ using newlocalSI and set local variable, which is a pointer to the
+ storage. */
+
+bc_expand_variable_local_init (decl)
+ tree decl;
+{
+ /* Evaluate size expression and coerce to SI */
+ bc_expand_expr (DECL_SIZE (decl));
+
+ /* Type sizes are always (?) of TREE_CODE INTEGER_CST, so
+ no coercion is necessary (?) */
+
+/* emit_typecode_conversion (preferred_typecode (TYPE_MODE (DECL_SIZE (decl)),
+ TREE_UNSIGNED (DECL_SIZE (decl))), SIcode); */
+
+ /* Emit code to allocate array */
+ bc_emit_instruction (newlocalSI);
+
+ /* Store array pointer in local variable. This is the only instance
+ where we actually want the address of the pointer to the
+ variable-size block, rather than the pointer itself. We avoid
+ using expand_address() since that would cause the pointer to be
+ pushed rather than its address. Hence the hard-coded reference;
+ notice also that the variable is always local (no global
+ variable-size type variables). */
+
+ bc_load_localaddr (DECL_RTL (decl));
+ bc_emit_instruction (storeP);
+}
+
+
+/* Emit code to initialize a declaration. */
+void
+bc_expand_decl_init (decl)
+ tree decl;
+{
+ int org_stack_depth;
+
+ /* Statical initializers are handled elsewhere */
+
+ if (TREE_STATIC (decl))
+ return;
+
+ /* Memory original stack depth */
+ org_stack_depth = stack_depth;
+
+ /* If the type is variable-size, we first create its space (we ASSUME
+ it CAN'T be static). We do this regardless of whether there's an
+ initializer assignment or not. */
+
+ if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+ bc_expand_variable_local_init (decl);
+
+ /* Expand initializer assignment */
+ if (DECL_INITIAL (decl) == error_mark_node)
+ {
+ enum tree_code code = TREE_CODE (TREE_TYPE (decl));
+
+ if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
+ || code == POINTER_TYPE)
+
+ expand_assignment (TREE_TYPE (decl), decl,
+ convert (TREE_TYPE (decl), integer_zero_node));
+ }
+ else if (DECL_INITIAL (decl))
+ expand_assignment (TREE_TYPE (decl), decl, DECL_INITIAL (decl));
+
+ /* Restore stack depth */
+ if (org_stack_depth > stack_depth)
+ abort ();
+
+ bc_adjust_stack (stack_depth - org_stack_depth);
+}
+
+
/* CLEANUP is an expression to be executed at exit from this binding contour;
for example, in C++, it might call the destructor for this variable.
@@ -3301,6 +3924,12 @@ expand_start_case (exit_flag, expr, type, printname)
case_stack = thiscase;
nesting_stack = thiscase;
+ if (output_bytecode)
+ {
+ bc_expand_start_case (thiscase, expr, type, printname);
+ return;
+ }
+
do_pending_stack_adjust ();
/* Make sure case_stmt.start points to something that won't
@@ -3311,6 +3940,32 @@ expand_start_case (exit_flag, expr, type, printname)
thiscase->data.case_stmt.start = get_last_insn ();
}
+
+/* Enter a case statement. It is assumed that the caller has pushed
+ the current context onto the case stack. */
+void
+bc_expand_start_case (thiscase, expr, type, printname)
+ struct nesting *thiscase;
+ tree expr;
+ tree type;
+ char *printname;
+{
+ bc_expand_expr (expr);
+ bc_expand_conversion (TREE_TYPE (expr), type);
+
+ /* For cases, the skip is a place we jump to that's emitted after
+ the size of the jump table is known. */
+
+ thiscase->data.case_stmt.skip_label = gen_label_rtx ();
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (thiscase->data.case_stmt.skip_label->bc_label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+}
+
+
/* Start a "dummy case statement" within which case labels are invalid
and are not connected to any larger real case statement.
This can be used if you don't want to let a case statement jump
@@ -3382,6 +4037,9 @@ pushcase (value, converter, label, duplicate)
tree index_type;
tree nominal_type;
+ if (output_bytecode)
+ return bc_pushcase (value, label);
+
/* Fail if not inside a real case statement. */
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
@@ -3588,6 +4246,62 @@ pushcase_range (value1, value2, converter, label, duplicate)
return 0;
}
+
+
+/* Accumulate one case or default label; VALUE is the value of the
+ case, or nil for a default label. If not currently inside a case,
+ return 1 and do nothing. If VALUE is a duplicate or overlaps, return
+ 2 and do nothing. If VALUE is out of range, return 3 and do nothing.
+ Return 0 on success. This function is a leftover from the earlier
+ bytecode compiler, which was based on gcc 1.37. It should be
+ merged into pushcase. */
+
+int
+bc_pushcase (value, label)
+ tree value;
+ tree label;
+{
+ struct nesting *thiscase = case_stack;
+ struct case_node *case_label, *new_label;
+
+ if (! thiscase)
+ return 1;
+
+ /* Fail if duplicate, overlap, or out of type range. */
+ if (value)
+ {
+ value = convert (thiscase->data.case_stmt.nominal_type, value);
+ if (! int_fits_type_p (value, thiscase->data.case_stmt.nominal_type))
+ return 3;
+
+ for (case_label = thiscase->data.case_stmt.case_list;
+ case_label->left; case_label = case_label->left)
+ if (! tree_int_cst_lt (case_label->left->high, value))
+ break;
+
+ if (case_label != thiscase->data.case_stmt.case_list
+ && ! tree_int_cst_lt (case_label->high, value)
+ || case_label->left && ! tree_int_cst_lt (value, case_label->left->low))
+ return 2;
+
+ new_label = (struct case_node *) oballoc (sizeof (struct case_node));
+ new_label->low = new_label->high = copy_node (value);
+ new_label->code_label = label;
+ new_label->left = case_label->left;
+
+ case_label->left = new_label;
+ thiscase->data.case_stmt.num_ranges++;
+ }
+ else
+ {
+ if (thiscase->data.case_stmt.default_label)
+ return 2;
+ thiscase->data.case_stmt.default_label = label;
+ }
+
+ expand_label (label);
+ return 0;
+}
/* Called when the index of a switch statement is an enumerated type
and there is no default label.
@@ -3609,6 +4323,12 @@ check_for_full_enumeration_handling (type)
register tree chain;
int all_values = 1;
+ if (output_bytecode)
+ {
+ bc_check_for_full_enumeration_handling (type);
+ return;
+ }
+
/* The time complexity of this loop is currently O(N * M), with
N being the number of members in the enumerated type, and
M being the number of case expressions in the switch. */
@@ -3707,6 +4427,46 @@ check_for_full_enumeration_handling (type)
}
#endif /* 0 */
}
+
+
+/* Check that all enumeration literals are covered by the case
+ expressions of a switch. Also warn if there are any cases
+ that are not elements of the enumerated type. */
+void
+bc_check_for_full_enumeration_handling (type)
+ tree type;
+{
+ struct nesting *thiscase = case_stack;
+ struct case_node *c;
+ tree e;
+
+ /* Check for enums not handled. */
+ for (e = TYPE_VALUES (type); e; e = TREE_CHAIN (e))
+ {
+ for (c = thiscase->data.case_stmt.case_list->left;
+ c && tree_int_cst_lt (c->high, TREE_VALUE (e));
+ c = c->left)
+ ;
+ if (! (c && tree_int_cst_equal (c->low, TREE_VALUE (e))))
+ warning ("enumerated value `%s' not handled in switch",
+ IDENTIFIER_POINTER (TREE_PURPOSE (e)));
+ }
+
+ /* Check for cases not in the enumeration. */
+ for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+ {
+ for (e = TYPE_VALUES (type);
+ e && !tree_int_cst_equal (c->low, TREE_VALUE (e));
+ e = TREE_CHAIN (e))
+ ;
+ if (! e)
+ warning ("case value `%d' not in enumerated type `%s'",
+ TREE_INT_CST_LOW (c->low),
+ IDENTIFIER_POINTER (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
+ ? TYPE_NAME (type)
+ : DECL_NAME (TYPE_NAME (type))));
+ }
+}
/* Terminate a case (Pascal) or switch (C) statement
in which ORIG_INDEX is the expression to be tested.
@@ -3721,14 +4481,24 @@ expand_end_case (orig_index)
register struct case_node *n;
int count;
rtx index;
- rtx table_label = gen_label_rtx ();
+ rtx table_label;
int ncases;
rtx *labelvec;
register int i;
rtx before_case;
register struct nesting *thiscase = case_stack;
- tree index_expr = thiscase->data.case_stmt.index_expr;
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
+ tree index_expr;
+ int unsignedp;
+
+ if (output_bytecode)
+ {
+ bc_expand_end_case (orig_index);
+ return;
+ }
+
+ table_label = gen_label_rtx ();
+ index_expr = thiscase->data.case_stmt.index_expr;
+ unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
do_pending_stack_adjust ();
@@ -4069,6 +4839,110 @@ expand_end_case (orig_index)
free_temp_slots ();
}
+
+/* Terminate a case statement. EXPR is the original index
+ expression. */
+void
+bc_expand_end_case (expr)
+ tree expr;
+{
+ struct nesting *thiscase = case_stack;
+ enum bytecode_opcode opcode;
+ struct bc_label *jump_label;
+ struct case_node *c;
+
+ bc_emit_bytecode (jump);
+ bc_emit_bytecode_labelref (thiscase->exit_label->bc_label);
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ /* Now that the size of the jump table is known, emit the actual
+ indexed jump instruction. */
+ bc_emit_bytecode_labeldef (thiscase->data.case_stmt.skip_label->bc_label);
+
+ opcode = TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode
+ ? TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseSU : caseSI
+ : TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseDU : caseDI;
+
+ bc_emit_bytecode (opcode);
+
+ /* Now emit the case instructions literal arguments, in order.
+ In addition to the value on the stack, it uses:
+ 1. The address of the jump table.
+ 2. The size of the jump table.
+ 3. The default label. */
+
+ jump_label = bc_get_bytecode_label ();
+ bc_emit_bytecode_labelref (jump_label);
+ bc_emit_bytecode_const ((char *) &thiscase->data.case_stmt.num_ranges,
+ sizeof thiscase->data.case_stmt.num_ranges);
+
+ if (thiscase->data.case_stmt.default_label)
+ bc_emit_bytecode_labelref (DECL_RTL (thiscase->
+ data.case_stmt.default_label)->bc_label);
+ else
+ bc_emit_bytecode_labelref (thiscase->exit_label->bc_label);
+
+ /* Output the jump table. */
+
+ bc_align_bytecode (3 /* PTR_ALIGN */);
+ bc_emit_bytecode_labeldef (jump_label);
+
+ if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode)
+ for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+ {
+ opcode = TREE_INT_CST_LOW (c->low);
+ bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
+
+ opcode = TREE_INT_CST_LOW (c->high);
+ bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
+
+ bc_emit_bytecode_labelref (DECL_RTL (c->code_label)->bc_label);
+ }
+ else
+ if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == DImode)
+ for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
+ {
+ bc_emit_bytecode_DI_const (c->low);
+ bc_emit_bytecode_DI_const (c->high);
+
+ bc_emit_bytecode_labelref (DECL_RTL (c->code_label)->bc_label);
+ }
+ else
+ /* Bad mode */
+ abort ();
+
+
+ bc_emit_bytecode_labeldef (thiscase->exit_label->bc_label);
+
+ /* Possibly issue enumeration warnings. */
+
+ if (!thiscase->data.case_stmt.default_label
+ && TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
+ && TREE_CODE (expr) != INTEGER_CST
+ && warn_switch)
+ check_for_full_enumeration_handling (TREE_TYPE (expr));
+
+
+#ifdef DEBUG_PRINT_CODE
+ fputc ('\n', stderr);
+#endif
+
+ POPSTACK (case_stack);
+}
+
+
+/* Return unique bytecode ID. */
+int
+bc_new_uid ()
+{
+ static int bc_uid = 0;
+
+ return (++bc_uid);
+}
+
/* Generate code to jump to LABEL if OP1 and OP2 are equal. */
static void
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 498610f..94e4280 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -57,6 +57,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
+
+#include "bytecode.h"
+#include "bc-emit.h"
#ifdef VMS
/* The extra parameters substantially improve the I/O performance. */
@@ -211,6 +214,9 @@ int errorcount = 0;
int warningcount = 0;
int sorrycount = 0;
+/* Flag to output bytecode instead of native assembler */
+int output_bytecode = 0;
+
/* Pointer to function to compute the name to use to print a declaration. */
char *(*decl_printable_name) ();
@@ -515,6 +521,7 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"inhibit-size-directive", &flag_inhibit_size_directive, 1},
{"verbose-asm", &flag_verbose_asm, 1},
{"gnu-linker", &flag_gnu_linker, 1}
+ {"bytecode", &output_bytecode, 1}
};
/* Table of language-specific options. */
@@ -885,11 +892,14 @@ void
fatal_insn_not_found (insn)
rtx insn;
{
- if (INSN_CODE (insn) < 0)
- error ("internal error--unrecognizable insn:", 0);
- else
- error ("internal error--insn does not satisfy its constraints:", 0);
- debug_rtx (insn);
+ if (!output_bytecode)
+ {
+ if (INSN_CODE (insn) < 0)
+ error ("internal error--unrecognizable insn:", 0);
+ else
+ error ("internal error--insn does not satisfy its constraints:", 0);
+ debug_rtx (insn);
+ }
if (asm_out_file)
fflush (asm_out_file);
if (aux_info_file)
@@ -1585,6 +1595,8 @@ compile_file (name)
init_obstacks ();
init_tree_codes ();
init_lex ();
+ /* Some of these really don't need to be called when generating bytecode,
+ but the options would have to be parsed first to know that. -bson */
init_rtl ();
init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE);
@@ -1813,34 +1825,51 @@ compile_file (name)
input_file_stack->next = 0;
input_file_stack->name = input_filename;
- ASM_FILE_START (asm_out_file);
+ if (!output_bytecode)
+ {
+ ASM_FILE_START (asm_out_file);
+ }
- /* Output something to inform GDB that this compilation was by GCC. */
+ /* Output something to inform GDB that this compilation was by GCC. Also
+ serves to tell GDB file consists of bytecodes. */
+ if (output_bytecode)
+ fprintf (asm_out_file, "bc_gcc2_compiled.:\n");
+ else
+ {
#ifndef ASM_IDENTIFY_GCC
- fprintf (asm_out_file, "gcc2_compiled.:\n");
+ fprintf (asm_out_file, "gcc2_compiled.:\n");
#else
- ASM_IDENTIFY_GCC (asm_out_file);
+ ASM_IDENTIFY_GCC (asm_out_file);
#endif
+ }
/* Output something to identify which front-end produced this file. */
#ifdef ASM_IDENTIFY_LANGUAGE
ASM_IDENTIFY_LANGUAGE (asm_out_file);
#endif
-/* ??? Note: There used to be a conditional here
- to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
- This was to guarantee separation between gcc_compiled. and
- the first function, for the sake of dbx on Suns.
- However, having the extra zero here confused the Emacs
- code for unexec, and might confuse other programs too.
- Therefore, I took out that change.
- In future versions we should find another way to solve
- that dbx problem. -- rms, 23 May 93. */
-
- /* Don't let the first function fall at the same address
- as gcc_compiled., if profiling. */
- if (profile_flag || profile_block_flag)
- assemble_zeros (UNITS_PER_WORD);
+ if (output_bytecode)
+ {
+ if (profile_flag || profile_block_flag)
+ error ("profiling not supported in bytecode compilation");
+ }
+ else
+ {
+ /* ??? Note: There used to be a conditional here
+ to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
+ This was to guarantee separation between gcc_compiled. and
+ the first function, for the sake of dbx on Suns.
+ However, having the extra zero here confused the Emacs
+ code for unexec, and might confuse other programs too.
+ Therefore, I took out that change.
+ In future versions we should find another way to solve
+ that dbx problem. -- rms, 23 May 93. */
+
+ /* Don't let the first function fall at the same address
+ as gcc_compiled., if profiling. */
+ if (profile_flag || profile_block_flag)
+ assemble_zeros (UNITS_PER_WORD);
+ }
/* If dbx symbol table desired, initialize writing it
and output the predefined types. */
@@ -1861,7 +1890,8 @@ compile_file (name)
/* Initialize yet another pass. */
- init_final (main_input_filename);
+ if (!output_bytecode)
+ init_final (main_input_filename);
start_time = get_run_time ();
@@ -2031,11 +2061,14 @@ compile_file (name)
/* Output some stuff at end of file if nec. */
- end_final (main_input_filename);
+ if (!output_bytecode)
+ {
+ end_final (main_input_filename);
#ifdef ASM_FILE_END
- ASM_FILE_END (asm_out_file);
+ ASM_FILE_END (asm_out_file);
#endif
+ }
after_finish_compilation:
@@ -2113,24 +2146,28 @@ compile_file (name)
{
fprintf (stderr,"\n");
print_time ("parse", parse_time);
- print_time ("integration", integration_time);
- print_time ("jump", jump_time);
- print_time ("cse", cse_time);
- print_time ("loop", loop_time);
- print_time ("cse2", cse2_time);
- print_time ("flow", flow_time);
- print_time ("combine", combine_time);
- print_time ("sched", sched_time);
- print_time ("local-alloc", local_alloc_time);
- print_time ("global-alloc", global_alloc_time);
- print_time ("sched2", sched2_time);
- print_time ("dbranch", dbr_sched_time);
- print_time ("shorten-branch", shorten_branch_time);
- print_time ("stack-reg", stack_reg_time);
- print_time ("final", final_time);
- print_time ("varconst", varconst_time);
- print_time ("symout", symout_time);
- print_time ("dump", dump_time);
+
+ if (!output_bytecode)
+ {
+ print_time ("integration", integration_time);
+ print_time ("jump", jump_time);
+ print_time ("cse", cse_time);
+ print_time ("loop", loop_time);
+ print_time ("cse2", cse2_time);
+ print_time ("flow", flow_time);
+ print_time ("combine", combine_time);
+ print_time ("sched", sched_time);
+ print_time ("local-alloc", local_alloc_time);
+ print_time ("global-alloc", global_alloc_time);
+ print_time ("sched2", sched2_time);
+ print_time ("dbranch", dbr_sched_time);
+ print_time ("shorten-branch", shorten_branch_time);
+ print_time ("stack-reg", stack_reg_time);
+ print_time ("final", final_time);
+ print_time ("varconst", varconst_time);
+ print_time ("symout", symout_time);
+ print_time ("dump", dump_time);
+ }
}
}
@@ -2236,6 +2273,9 @@ rest_of_compilation (decl)
tree saved_arguments = 0;
int failure = 0;
+ if (output_bytecode)
+ return;
+
/* If we are reconsidering an inline function
at the end of compilation, skip the stuff for making it inline. */
@@ -3166,7 +3206,12 @@ main (argc, argv, envp)
error ("Invalid option `%s'", argv[i]);
}
else if (!strcmp (str, "p"))
- profile_flag = 1;
+ {
+ if (!output_bytecode)
+ profile_flag = 1;
+ else
+ error ("profiling not supported in bytecode compilation");
+ }
else if (!strcmp (str, "a"))
{
#if !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER)
@@ -3325,6 +3370,18 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
filename = argv[i];
}
+ /* Initialize for bytecode output. A good idea to do this as soon as
+ possible after the "-f" options have been parsed. */
+ if (output_bytecode)
+ {
+#ifndef TARGET_SUPPORTS_BYTECODE
+ /* Just die with a fatal error if not supported */
+ fatal ("-fbytecode can not be used for this target");
+#else
+ bc_initialize ();
+#endif
+ }
+
if (optimize == 0)
{
/* Inlining does not work if not optimizing,
@@ -3398,10 +3455,14 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
}
/* Now that register usage is specified, convert it to HARD_REG_SETs. */
- init_reg_sets_1 ();
+ if (!output_bytecode)
+ init_reg_sets_1 ();
compile_file (filename);
+ if (output_bytecode)
+ bc_write_file (stdout);
+
#ifndef OS2
#ifndef VMS
if (flag_print_mem)
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 66128bb..7d16f36 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -38,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h"
#include "defaults.h"
#include "real.h"
+#include "bytecode.h"
#include "obstack.h"
@@ -96,9 +97,11 @@ void assemble_name ();
int output_addressed_constants ();
void output_constant ();
void output_constructor ();
+void output_byte_asm ();
void text_section ();
void readonly_data_section ();
void data_section ();
+static void bc_assemble_integer ();
#ifdef EXTRA_SECTIONS
static enum in_section {no_section, in_text, in_data, EXTRA_SECTIONS} in_section
@@ -120,7 +123,11 @@ text_section ()
{
if (in_section != in_text)
{
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ if (output_bytecode)
+ bc_text ();
+ else
+ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+
in_section = in_text;
}
}
@@ -132,16 +139,21 @@ data_section ()
{
if (in_section != in_data)
{
- if (flag_shared_data)
+ if (output_bytecode)
+ bc_data ();
+ else
{
+ if (flag_shared_data)
+ {
#ifdef SHARED_SECTION_ASM_OP
- fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
+ fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
#else
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
+ fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
#endif
+ }
+ else
+ fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
}
- else
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
in_section = in_data;
}
@@ -178,6 +190,16 @@ make_function_rtl (decl)
{
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ if (output_bytecode)
+ {
+ if (DECL_RTL (decl) == 0)
+ DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
+
+ /* Record that at least one function has been defined. */
+ function_defined = 1;
+ return;
+ }
+
/* Rename a nested function to avoid conflicts. */
if (decl_function_context (decl) != 0
&& DECL_INITIAL (decl) != 0
@@ -211,6 +233,48 @@ make_function_rtl (decl)
function_defined = 1;
}
+/* Create the DECL_RTL for a declaration for a static or external
+ variable or static or external function.
+ ASMSPEC, if not 0, is the string which the user specified
+ as the assembler symbol name.
+ TOP_LEVEL is nonzero if this is a file-scope variable.
+ This is never called for PARM_DECLs. */
+void
+bc_make_decl_rtl (decl, asmspec, top_level)
+ tree decl;
+ char *asmspec;
+ int top_level;
+{
+ register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+ if (DECL_RTL (decl) == 0)
+ {
+ /* Print an error message for register variables. */
+ if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
+ error ("function declared `register'");
+ else if (DECL_REGISTER (decl))
+ error ("global register variables not supported in the interpreter");
+
+ /* Handle ordinary static variables and functions. */
+ if (DECL_RTL (decl) == 0)
+ {
+ /* Can't use just the variable's own name for a variable
+ whose scope is less than the whole file.
+ Concatenate a distinguishing number. */
+ if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
+ {
+ char *label;
+
+ ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
+ name = obstack_copy0 (saveable_obstack, label, strlen (label));
+ var_labelno++;
+ }
+
+ DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
+ }
+ }
+}
+
/* Given NAME, a putative register name, discard any customary prefixes. */
static char *
@@ -301,7 +365,15 @@ make_decl_rtl (decl, asmspec, top_level)
int top_level;
{
register char *name;
- int reg_number = decode_reg_name (asmspec);
+ int reg_number;
+
+ if (output_bytecode)
+ {
+ bc_make_decl_rtl (decl, asmspec, top_level);
+ return;
+ }
+
+ reg_number = decode_reg_name (asmspec);
if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
@@ -465,6 +537,12 @@ void
assemble_asm (string)
tree string;
{
+ if (output_bytecode)
+ {
+ error ("asm statements not allowed in interpreter");
+ return;
+ }
+
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
@@ -576,7 +654,12 @@ assemble_start_function (decl, fnname)
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
- ASM_OUTPUT_ALIGN (asm_out_file, align);
+ {
+ if (output_bytecode)
+ BC_OUTPUT_ALIGN (asm_out_file, align);
+ else
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ }
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
@@ -600,7 +683,10 @@ assemble_start_function (decl, fnname)
{
if (!first_global_object_name)
STRIP_NAME_ENCODING (first_global_object_name, fnname);
- ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
+ if (output_bytecode)
+ BC_GLOBALIZE_LABEL (asm_out_file, fnname);
+ else
+ ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
}
/* Do any machine/system dependent processing of the function name */
@@ -608,7 +694,10 @@ assemble_start_function (decl, fnname)
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else
/* Standard thing is just output label for the function. */
- ASM_OUTPUT_LABEL (asm_out_file, fnname);
+ if (output_bytecode)
+ BC_OUTPUT_LABEL (asm_out_file, fnname);
+ else
+ ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
}
@@ -631,6 +720,12 @@ void
assemble_zeros (size)
int size;
{
+ if (output_bytecode)
+ {
+ bc_emit_const_skip (size);
+ return;
+ }
+
#ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */
@@ -664,7 +759,12 @@ assemble_zeros (size)
else
#endif
if (size > 0)
- ASM_OUTPUT_SKIP (asm_out_file, size);
+ {
+ if (output_bytecode)
+ BC_OUTPUT_SKIP (asm_out_file, size);
+ else
+ ASM_OUTPUT_SKIP (asm_out_file, size);
+ }
}
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
@@ -688,6 +788,12 @@ assemble_string (p, size)
int pos = 0;
int maximum = 2000;
+ if (output_bytecode)
+ {
+ bc_emit (p, size);
+ return;
+ }
+
/* If the string is very long, split it up. */
while (pos < size)
@@ -696,7 +802,10 @@ assemble_string (p, size)
if (thissize > maximum)
thissize = maximum;
- ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
+ if (output_bytecode)
+ BC_OUTPUT_ASCII (asm_out_file, p, thissize);
+ else
+ ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
pos += thissize;
p += thissize;
@@ -725,6 +834,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
int reloc = 0;
enum in_section saved_in_section;
+ if (output_bytecode)
+ return;
+
if (GET_CODE (DECL_RTL (decl)) == REG)
{
/* Do output symbol info for global register variables, but do nothing
@@ -734,19 +846,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
return;
TREE_ASM_WRITTEN (decl) = 1;
+ if (!output_bytecode)
+ {
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
- /* File-scope global variables are output here. */
- if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
- && top_level)
- dbxout_symbol (decl, 0);
+ /* File-scope global variables are output here. */
+ if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
+ && top_level)
+ dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
- if (write_symbols == SDB_DEBUG && top_level
- /* Leave initialized global vars for end of compilation;
- see comment in compile_file. */
- && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
- sdbout_symbol (decl, 0);
+ if (write_symbols == SDB_DEBUG && top_level
+ /* Leave initialized global vars for end of compilation;
+ see comment in compile_file. */
+ && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
+ sdbout_symbol (decl, 0);
#endif
+ }
/* Don't output any DWARF debugging information for variables here.
In the case of local variables, the information for them is output
@@ -880,12 +995,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
else
#endif
+ if (output_bytecode)
+ BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
+ else
+ {
#ifdef ASM_OUTPUT_ALIGNED_COMMON
- ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
- DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
+ DECL_ALIGN (decl));
#else
- ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
+ ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
#endif
+ }
}
else
{
@@ -894,12 +1014,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
+ if (output_bytecode)
+ BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ else
+ {
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
- ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
- DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
+ DECL_ALIGN (decl));
#else
- ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
+ }
}
goto finish;
}
@@ -1017,14 +1142,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
DECL_ALIGN (decl) = align;
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ {
+ if (output_bytecode)
+ BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ else
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ }
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
#else
/* Standard thing is just output label for the object. */
- ASM_OUTPUT_LABEL (asm_out_file, name);
+ if (output_bytecode)
+ BC_OUTPUT_LABEL (asm_out_file, name);
+ else
+ ASM_OUTPUT_LABEL (asm_out_file, name);
#endif /* ASM_DECLARE_OBJECT_NAME */
if (!dont_output_data)
@@ -1110,6 +1243,55 @@ contains_pointers_p (type)
}
}
+/* Output text storage for constructor CONSTR. Returns rtx of
+ storage. */
+
+rtx
+bc_output_constructor (constr)
+ tree constr;
+{
+ int i;
+
+ /* Must always be a literal; non-literal constructors are handled
+ differently. */
+
+ if (!TREE_CONSTANT (constr))
+ abort ();
+
+ /* Always const */
+ text_section ();
+
+ /* Align */
+ for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
+ if (i > 0)
+ BC_OUTPUT_ALIGN (asm_out_file, i);
+
+ /* Output data */
+ output_constant (constr, int_size_in_bytes (TREE_TYPE (constr)));
+}
+
+
+/* Create storage for constructor CONSTR. */
+
+void
+bc_output_data_constructor (constr)
+ tree constr;
+{
+ int i;
+
+ /* Put in data section */
+ data_section ();
+
+ /* Align */
+ for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
+ if (i > 0)
+ BC_OUTPUT_ALIGN (asm_out_file, i);
+
+ /* The constructor is filled in at runtime. */
+ BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
+}
+
+
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */
@@ -1118,6 +1300,9 @@ void
assemble_external (decl)
tree decl;
{
+ if (output_bytecode)
+ return;
+
#ifdef ASM_OUTPUT_EXTERNAL
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
&& DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
@@ -1142,11 +1327,14 @@ assemble_external_libcall (fun)
rtx fun;
{
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
- /* Declare library function name external when first used, if nec. */
- if (! SYMBOL_REF_USED (fun))
+ if (!output_bytecode)
{
- SYMBOL_REF_USED (fun) = 1;
- ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
+ /* Declare library function name external when first used, if nec. */
+ if (! SYMBOL_REF_USED (fun))
+ {
+ SYMBOL_REF_USED (fun) = 1;
+ ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
+ }
}
#endif
}
@@ -1166,7 +1354,10 @@ void
assemble_label (name)
char *name;
{
- ASM_OUTPUT_LABEL (asm_out_file, name);
+ if (output_bytecode)
+ BC_OUTPUT_LABEL (asm_out_file, name);
+ else
+ ASM_OUTPUT_LABEL (asm_out_file, name);
}
/* Output to FILE a reference to the assembler name of a C-level name NAME.
@@ -1181,9 +1372,19 @@ assemble_name (file, name)
char *name;
{
if (name[0] == '*')
- fputs (&name[1], file);
+ {
+ if (output_bytecode)
+ bc_emit_labelref (name);
+ else
+ fputs (&name[1], file);
+ }
else
- ASM_OUTPUT_LABELREF (file, name);
+ {
+ if (output_bytecode)
+ BC_OUTPUT_LABELREF (file, name);
+ else
+ ASM_OUTPUT_LABELREF (file, name);
+ }
}
/* Allocate SIZE bytes writable static space with a gensym name
@@ -1214,12 +1415,21 @@ assemble_static_space (size)
strlen (name) + 2);
strcpy (namestring, name);
- x = gen_rtx (SYMBOL_REF, Pmode, namestring);
+ if (output_bytecode)
+ x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0);
+ else
+ x = gen_rtx (SYMBOL_REF, Pmode, namestring);
+
+ if (output_bytecode)
+ BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ else
+ {
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
- ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
+ ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
#else
- ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
+ }
return x;
}
@@ -1234,6 +1444,10 @@ assemble_trampoline_template ()
char *name;
int align;
+ /* Shouldn't get here */
+ if (output_bytecode)
+ abort ();
+
/* By default, put trampoline templates in read-only data section. */
#ifdef TRAMPOLINE_SECTION
@@ -1683,9 +1897,13 @@ decode_addr_const (exp, value)
break;
case LABEL_DECL:
- x = gen_rtx (MEM, FUNCTION_MODE,
- gen_rtx (LABEL_REF, VOIDmode,
- label_rtx (TREE_OPERAND (exp, 0))));
+ if (output_bytecode)
+ /* FIXME: this may not be correct, check it */
+ x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0);
+ else
+ x = gen_rtx (MEM, FUNCTION_MODE,
+ gen_rtx (LABEL_REF, VOIDmode,
+ label_rtx (TREE_OPERAND (exp, 0))));
break;
case REAL_CST:
@@ -1699,9 +1917,12 @@ decode_addr_const (exp, value)
abort ();
}
- if (GET_CODE (x) != MEM)
- abort ();
- x = XEXP (x, 0);
+ if (!output_bytecode)
+ {
+ if (GET_CODE (x) != MEM)
+ abort ();
+ x = XEXP (x, 0);
+ }
value->base = x;
value->offset = offset;
@@ -2171,47 +2392,57 @@ output_constant_def (exp)
to see if any of them describes EXP. If yes, the descriptor records
the label number already assigned. */
- hash = const_hash (exp) % MAX_HASH_TABLE;
-
- for (desc = const_hash_table[hash]; desc; desc = desc->next)
- if (compare_constant (exp, desc))
- {
- found = desc->label;
- break;
- }
-
- if (found == 0)
+ if (!output_bytecode)
{
- /* No constant equal to EXP is known to have been output.
- Make a constant descriptor to enter EXP in the hash table.
- Assign the label number and record it in the descriptor for
- future calls to this function to find. */
-
- /* Create a string containing the label name, in LABEL. */
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
-
- desc = record_constant (exp);
- desc->next = const_hash_table[hash];
- desc->label
- = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
- const_hash_table[hash] = desc;
+ hash = const_hash (exp) % MAX_HASH_TABLE;
+
+ for (desc = const_hash_table[hash]; desc; desc = desc->next)
+ if (compare_constant (exp, desc))
+ {
+ found = desc->label;
+ break;
+ }
+
+ if (found == 0)
+ {
+ /* No constant equal to EXP is known to have been output.
+ Make a constant descriptor to enter EXP in the hash table.
+ Assign the label number and record it in the descriptor for
+ future calls to this function to find. */
+
+ /* Create a string containing the label name, in LABEL. */
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+
+ desc = record_constant (exp);
+ desc->next = const_hash_table[hash];
+ desc->label
+ = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
+ const_hash_table[hash] = desc;
+ }
+ else
+ {
+ /* Create a string containing the label name, in LABEL. */
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+ }
}
-
+
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
push_obstacks_nochange ();
if (TREE_PERMANENT (exp))
end_temporary_allocation ();
- def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
-
- TREE_CST_RTL (exp)
- = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
- RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
- MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
-
+ if (!output_bytecode)
+ {
+ def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
+
+ TREE_CST_RTL (exp)
+ = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
+ RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
+ }
pop_obstacks ();
/* Optionally set flags or add text to the name to record information
@@ -2283,7 +2514,12 @@ output_constant_def_contents (exp, reloc, labelno)
#endif
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ {
+ if (!output_bytecode)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ else
+ BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ }
/* Output the label itself. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
@@ -2891,6 +3127,22 @@ output_addressed_constants (exp)
}
return reloc;
}
+
+
+/* Output assembler for byte constant */
+void
+output_byte_asm (byte)
+ int byte;
+{
+ if (output_bytecode)
+ bc_emit_const ((char *) &byte, sizeof (char));
+#ifdef ASM_OUTPUT_BYTE
+ else
+ {
+ ASM_OUTPUT_BYTE (asm_out_file, byte);
+ }
+#endif
+}
/* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
@@ -2925,7 +3177,10 @@ output_constant (exp, size)
This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
{
- assemble_zeros (size);
+ if (output_bytecode)
+ bc_emit_const_skip (size);
+ else
+ assemble_zeros (size);
return;
}
@@ -3005,6 +3260,101 @@ output_constant (exp, size)
if (size > 0)
assemble_zeros (size);
}
+
+
+/* Bytecode specific code to output assembler for integer. */
+void
+bc_assemble_integer (exp, size)
+ tree exp;
+ int size;
+{
+ tree const_part;
+ tree addr_part;
+ tree tmp;
+
+ /* FIXME: is this fold() business going to be as good as the
+ expand_expr() using EXPAND_SUM above in the RTL case? I
+ hate RMS.
+ FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
+
+ exp = fold (exp);
+
+ while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
+ exp = TREE_OPERAND (exp, 0);
+ if (TREE_CODE (exp) == INTEGER_CST)
+ {
+ const_part = exp;
+ addr_part = 0;
+ }
+ else if (TREE_CODE (exp) == PLUS_EXPR)
+ {
+ const_part = TREE_OPERAND (exp, 0);
+ while (TREE_CODE (const_part) == NOP_EXPR
+ || TREE_CODE (const_part) == CONVERT_EXPR)
+ const_part = TREE_OPERAND (const_part, 0);
+ addr_part = TREE_OPERAND (exp, 1);
+ while (TREE_CODE (addr_part) == NOP_EXPR
+ || TREE_CODE (addr_part) == CONVERT_EXPR)
+ addr_part = TREE_OPERAND (addr_part, 0);
+ if (TREE_CODE (const_part) != INTEGER_CST)
+ tmp = const_part, const_part = addr_part, addr_part = tmp;
+ if (TREE_CODE (const_part) != INTEGER_CST
+ || TREE_CODE (addr_part) != ADDR_EXPR)
+ abort (); /* FIXME: we really haven't considered
+ all the possible cases here. */
+ }
+ else if (TREE_CODE (exp) == ADDR_EXPR)
+ {
+ const_part = integer_zero_node;
+ addr_part = exp;
+ }
+ else
+ abort (); /* FIXME: ditto previous. */
+
+ if (addr_part == 0)
+ {
+ if (size == 1)
+ {
+ char c = TREE_INT_CST_LOW (const_part);
+ bc_emit (&c, 1);
+ size -= 1;
+ }
+ else if (size == 2)
+ {
+ short s = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &s, 2);
+ size -= 2;
+ }
+ else if (size == 4)
+ {
+ int i = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &i, 4);
+ size -= 4;
+ }
+ else if (size == 8)
+ {
+#if WORDS_BIG_ENDIAN
+ int i = TREE_INT_CST_HIGH (const_part);
+ bc_emit ((char *) &i, 4);
+ i = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &i, 4);
+#else
+ int i = TREE_INT_CST_LOW (const_part);
+ bc_emit ((char *) &i, 4);
+ i = TREE_INT_CST_HIGH (const_part);
+ bc_emit ((char *) &i, 4);
+#endif
+ size -= 8;
+ }
+ }
+ else
+ if (size == 4
+ && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
+ bc_emit_labelref (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0)),
+ TREE_INT_CST_LOW (const_part));
+ else
+ abort (); /* FIXME: there may be more cases. */
+}
/* Subroutine of output_constant, used for CONSTRUCTORs
(aggregate constants).
@@ -3083,7 +3433,10 @@ output_constructor (exp, size)
if each element has the proper size. */
if ((field != 0 || index != 0) && bitpos != total_bytes)
{
- assemble_zeros (bitpos - total_bytes);
+ if (!output_bytecode)
+ assemble_zeros (bitpos - total_bytes);
+ else
+ bc_emit_const_skip (bitpos - total_bytes);
total_bytes = bitpos;
}
@@ -3254,3 +3607,42 @@ output_constructor (exp, size)
if (total_bytes < size)
assemble_zeros (size - total_bytes);
}
+
+
+/* Output asm to handle ``#pragma weak'' */
+void
+handle_pragma_weak (what, asm_out_file, name, value)
+ enum pragma_state what;
+ FILE *asm_out_file;
+ char *name, *value;
+{
+ if (what == ps_name || what == ps_value)
+ {
+ fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
+
+ if (output_bytecode)
+ BC_OUTPUT_LABELREF (asm_out_file, name);
+ else
+ ASM_OUTPUT_LABELREF (asm_out_file, name);
+
+ fputc ('\n', asm_out_file);
+ if (what == ps_value)
+ {
+ fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
+ if (output_bytecode)
+ BC_OUTPUT_LABELREF (asm_out_file, name);
+ else
+ ASM_OUTPUT_LABELREF (asm_out_file, name);
+
+ fputc (',', asm_out_file);
+ if (output_bytecode)
+ BC_OUTPUT_LABELREF (asm_out_file, value);
+ else
+ ASM_OUTPUT_LABELREF (asm_out_file, value);
+
+ fputc ('\n', asm_out_file);
+ }
+ }
+ else if (! (what == ps_done || what == ps_start))
+ warning ("malformed `#pragma weak'");
+}