Commit ca695ac9 by Jan Brittenson

bytecode

From-SVN: r5379
parent 86d7f2db
...@@ -399,6 +399,9 @@ CPLUS_OBJS = cp-parse.o cp-decl.o cp-decl2.o \ ...@@ -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 \ cp-expr.o cp-pt.o cp-edsel.o cp-xref.o \
$(CPLUS_INPUT) cp-spew.o c-common.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. # Language-independent object files.
OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ 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 \ function.o stmt.o expr.o calls.o expmed.o explow.o optabs.o varasm.o \
...@@ -461,6 +464,7 @@ CONFIG_H = ...@@ -461,6 +464,7 @@ CONFIG_H =
RTL_H = rtl.h rtl.def machmode.h machmode.def RTL_H = rtl.h rtl.def machmode.h machmode.def
TREE_H = tree.h real.h tree.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 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. # Avoid a lot of time thinking about remaking Makefile.in and *.def.
.SUFFIXES: .in .def .SUFFIXES: .in .def
...@@ -484,7 +488,7 @@ for-bootstrap: start.encap $(LIBGCC) ...@@ -484,7 +488,7 @@ for-bootstrap: start.encap $(LIBGCC)
rest.encap: $(LIBGCC) stmp-headers $(STMP_FIXPROTO) $(EXTRA_PARTS) rest.encap: $(LIBGCC) stmp-headers $(STMP_FIXPROTO) $(EXTRA_PARTS)
# This is what is made with the host's compiler # This is what is made with the host's compiler
# whether making a cross compiler or not. # 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. # Define the names for selecting languages in LANGUAGES.
C c: cc1 C c: cc1
...@@ -545,14 +549,14 @@ g++-cross: $(srcdir)/g++.c ...@@ -545,14 +549,14 @@ g++-cross: $(srcdir)/g++.c
$(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o g++-cross \ $(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o g++-cross \
-DGCC_NAME=\"$(target)-gcc\" $(srcdir)/g++.c version.o $(LIBS) -DGCC_NAME=\"$(target)-gcc\" $(srcdir)/g++.c version.o $(LIBS)
cc1:$(P) $(C_OBJS) $(OBJS) $(LIBDEPS) cc1:$(P) $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(LIBS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(LIBDEPS) cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(OBJS) $(LIBS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(BC_OBJS) $(OBJS) $(LIBS)
cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(LIBDEPS) cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(LIBS) $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
# Copy float.h from its source. # Copy float.h from its source.
gfloat.h: $(FLOAT_H) gfloat.h: $(FLOAT_H)
...@@ -1247,6 +1251,63 @@ $(HOST_PREFIX_1)malloc.o: malloc.c ...@@ -1247,6 +1251,63 @@ $(HOST_PREFIX_1)malloc.o: malloc.c
$(HOST_PREFIX_1): $(HOST_PREFIX_1):
touch $(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. # Remake cpp and protoize.
# Making the preprocessor # Making the preprocessor
...@@ -1507,7 +1568,7 @@ $(srcdir)/INSTALL: install1.texi install.texi ...@@ -1507,7 +1568,7 @@ $(srcdir)/INSTALL: install1.texi install.texi
# `realclean' also deletes everything that could be regenerated automatically. # `realclean' also deletes everything that could be regenerated automatically.
mostlyclean: mostlyclean: bytecode.mostlyclean
-rm -f $(STAGESTUFF) -rm -f $(STAGESTUFF)
# Clean the objc subdir if we created one. # Clean the objc subdir if we created one.
if [ -d objc ]; then \ if [ -d objc ]; then \
...@@ -1545,7 +1606,7 @@ mostlyclean: ...@@ -1545,7 +1606,7 @@ mostlyclean:
# Delete all files made by compilation # Delete all files made by compilation
# that don't exist in the distribution. # that don't exist in the distribution.
clean: mostlyclean clean: mostlyclean bytecode.clean
# It may not be quite desirable to delete unprotoize.c here, # It may not be quite desirable to delete unprotoize.c here,
# but the spec for `make clean' requires it. # but the spec for `make clean' requires it.
# Using unprotoize.c is not quite right in the first place, # Using unprotoize.c is not quite right in the first place,
...@@ -1557,7 +1618,7 @@ clean: mostlyclean ...@@ -1557,7 +1618,7 @@ clean: mostlyclean
# Delete all files that users would normally create # Delete all files that users would normally create
# while building and installing GCC. # 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 tm.h aux-output.c config.h md config.status tconfig.h hconfig.h
-rm -f Makefile *.oaux -rm -f Makefile *.oaux
-rm -fr stage1 stage2 stage3 stage4 -rm -fr stage1 stage2 stage3 stage4
...@@ -1581,7 +1642,7 @@ extraclean: distclean ...@@ -1581,7 +1642,7 @@ extraclean: distclean
# Get rid of every file that's generated from some other file. # Get rid of every file that's generated from some other file.
# Most of these files ARE PRESENT in the GCC distribution. # 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 c-parse.y objc-parse.y
-rm -f cp-parse.c cp-parse.h cp-parse.output -rm -f cp-parse.c cp-parse.h cp-parse.output
-rm -f objc-parse.c objc-parse.output -rm -f objc-parse.c objc-parse.output
......
...@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h> #include <stdio.h>
#include "config.h" #include "config.h"
#include "tree.h" #include "tree.h"
#include "function.h"
#ifdef HANDLE_SYSV_PRAGMA #ifdef HANDLE_SYSV_PRAGMA
...@@ -45,20 +46,7 @@ handle_pragma_token (string, token) ...@@ -45,20 +46,7 @@ handle_pragma_token (string, token)
char *string; char *string;
tree token; tree token;
{ {
static enum pragma_state static enum pragma_state state = ps_start, type;
{
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 char *name; static char *name;
static char *value; static char *value;
static int align; static int align;
...@@ -76,24 +64,8 @@ handle_pragma_token (string, token) ...@@ -76,24 +64,8 @@ handle_pragma_token (string, token)
{ {
#ifdef HANDLE_PRAGMA_WEAK #ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK) if (HANDLE_PRAGMA_WEAK)
{ handle_pragma_weak (state, asm_out_file, name, value);
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'");
}
#endif /* HANDLE_PRAMA_WEAK */ #endif /* HANDLE_PRAMA_WEAK */
} }
......
...@@ -42,8 +42,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -42,8 +42,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h" #include "regs.h"
#include "insn-config.h" #include "insn-config.h"
#include "real.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> #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. /* 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. */ After rtl generation, it is 1 plus the largest register number used. */
...@@ -203,6 +224,11 @@ extern int emit_lineno; ...@@ -203,6 +224,11 @@ extern int emit_lineno;
rtx change_address (); rtx change_address ();
void init_emit (); void init_emit ();
extern struct obstack *rtl_obstack;
extern int stack_depth;
extern int max_stack_depth;
/* rtx gen_rtx (code, mode, [element1, ..., elementn]) /* rtx gen_rtx (code, mode, [element1, ..., elementn])
** **
** This routine generates an RTX of the size specified by ** This routine generates an RTX of the size specified by
...@@ -1216,8 +1242,12 @@ change_address (memref, mode, addr) ...@@ -1216,8 +1242,12 @@ change_address (memref, mode, addr)
rtx rtx
gen_label_rtx () gen_label_rtx ()
{ {
register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, register rtx label;
label_num++, NULL_PTR);
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; LABEL_NUSES (label) = 0;
return label; return label;
} }
...@@ -2559,6 +2589,13 @@ emit_line_note (file, line) ...@@ -2559,6 +2589,13 @@ emit_line_note (file, line)
char *file; char *file;
int line; 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_filename = file;
emit_lineno = line; emit_lineno = line;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "integrate.h" #include "integrate.h"
#include "real.h" #include "real.h"
#include "function.h" #include "function.h"
#include "bytecode.h"
#include "obstack.h" #include "obstack.h"
#define obstack_chunk_alloc xmalloc #define obstack_chunk_alloc xmalloc
...@@ -2850,9 +2851,16 @@ void ...@@ -2850,9 +2851,16 @@ void
output_inline_function (fndecl) output_inline_function (fndecl)
tree fndecl; tree fndecl;
{ {
rtx head = DECL_SAVED_INSNS (fndecl); rtx head;
rtx last; rtx last;
if (output_bytecode)
{
warning ("`inline' ignored for bytecode output");
return;
}
head = DECL_SAVED_INSNS (fndecl);
current_function_decl = fndecl; current_function_decl = fndecl;
/* This call is only used to initialize global variables. */ /* This call is only used to initialize global variables. */
......
...@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "recog.h" #include "recog.h"
#include "reload.h" #include "reload.h"
#include "real.h" #include "real.h"
#include "bytecode.h"
#ifndef REGISTER_MOVE_COST #ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2 #define REGISTER_MOVE_COST(x, y) 2
...@@ -413,6 +414,13 @@ fix_register (name, fixed, call_used) ...@@ -413,6 +414,13 @@ fix_register (name, fixed, call_used)
{ {
int i; 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 /* Decode the name and update the primary form of
the register info. */ the register info. */
......
...@@ -139,6 +139,22 @@ typedef struct rtx_def ...@@ -139,6 +139,22 @@ typedef struct rtx_def
The number of operands and their types are controlled The number of operands and their types are controlled
by the `code' field, according to rtl.def. */ by the `code' field, according to rtl.def. */
rtunion fld[1]; 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; } *rtx;
/* Add prototype support. */ /* Add prototype support. */
...@@ -640,6 +656,7 @@ extern rtx gen_rtx PROTO((enum rtx_code, enum machine_mode, ...)); ...@@ -640,6 +656,7 @@ extern rtx gen_rtx PROTO((enum rtx_code, enum machine_mode, ...));
extern rtvec gen_rtvec PROTO((int, ...)); extern rtvec gen_rtvec PROTO((int, ...));
#else #else
extern rtx bc_gen_rtx ();
extern rtx gen_rtx (); extern rtx gen_rtx ();
extern rtvec gen_rtvec (); extern rtvec gen_rtvec ();
#endif #endif
......
...@@ -49,6 +49,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -49,6 +49,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h" #include "obstack.h"
#include "loop.h" #include "loop.h"
#include "recog.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_alloc xmalloc
#define obstack_chunk_free free #define obstack_chunk_free free
...@@ -181,13 +188,28 @@ static void emit_jump_if_reachable (); ...@@ -181,13 +188,28 @@ static void emit_jump_if_reachable ();
static int warn_if_unused_value (); static int warn_if_unused_value ();
static void expand_goto_internal (); static void expand_goto_internal ();
static void bc_expand_goto_internal ();
static int expand_fixup (); static int expand_fixup ();
static void bc_expand_fixup ();
void fixup_gotos (); void fixup_gotos ();
static void bc_fixup_gotos ();
void free_temp_slots (); void free_temp_slots ();
static void expand_cleanups (); static void expand_cleanups ();
static void expand_null_return_1 (); static void expand_null_return_1 ();
static int tail_recursion_args (); static int tail_recursion_args ();
static void do_jump_if_equal (); 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. /* Stack of control and binding constructs we are currently inside.
...@@ -250,7 +272,8 @@ struct nesting ...@@ -250,7 +272,8 @@ struct nesting
/* Sequence number of this binding contour within the function, /* Sequence number of this binding contour within the function,
in order of entry. */ in order of entry. */
int block_start_count; 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; rtx stack_level;
/* The NOTE that starts this contour. /* The NOTE that starts this contour.
Used by expand_goto to check whether the destination Used by expand_goto to check whether the destination
...@@ -277,6 +300,8 @@ struct nesting ...@@ -277,6 +300,8 @@ struct nesting
struct label_chain *label_chain; struct label_chain *label_chain;
/* Number of function calls seen, as of start of this block. */ /* Number of function calls seen, as of start of this block. */
int function_call_count; int function_call_count;
/* Bytecode specific: stack level to restore stack to on exit. */
int bc_stack_level;
} block; } block;
/* For switch (C) or case (Pascal) statements, /* For switch (C) or case (Pascal) statements,
and also for dummies (see `expand_start_case_dummy'). */ and also for dummies (see `expand_start_case_dummy'). */
...@@ -285,6 +310,10 @@ struct nesting ...@@ -285,6 +310,10 @@ struct nesting
/* The insn after which the case dispatch should finally /* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */ be emitted. Zero for a dummy. */
rtx start; 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 /* A list of case labels, kept in ascending order by value
as the list is built. as the list is built.
During expand_end_case, this list may be rearranged into a During expand_end_case, this list may be rearranged into a
...@@ -425,6 +454,21 @@ struct goto_fixup ...@@ -425,6 +454,21 @@ struct goto_fixup
time this goto was seen. time this goto was seen.
The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */ The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
tree cleanup_list_list; 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; static struct goto_fixup *goto_fixup_chain;
...@@ -514,11 +558,16 @@ restore_stmt_status (p) ...@@ -514,11 +558,16 @@ restore_stmt_status (p)
void void
emit_nop () emit_nop ()
{ {
rtx last_insn = get_last_insn (); rtx last_insn;
if (!optimize
&& (GET_CODE (last_insn) == CODE_LABEL if (!output_bytecode)
|| prev_real_insn (last_insn) == 0)) {
emit_insn (gen_nop ()); 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, /* Return the rtx-label that corresponds to a LABEL_DECL,
...@@ -555,9 +604,17 @@ void ...@@ -555,9 +604,17 @@ void
expand_computed_goto (exp) expand_computed_goto (exp)
tree exp; tree exp;
{ {
rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0); if (output_bytecode)
emit_queue (); {
emit_indirect_jump (x); 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. */ /* Handle goto statements and the labels that they can go to. */
...@@ -579,6 +636,15 @@ expand_label (label) ...@@ -579,6 +636,15 @@ expand_label (label)
{ {
struct label_chain *p; 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 (); do_pending_stack_adjust ();
emit_label (label_rtx (label)); emit_label (label_rtx (label));
if (DECL_NAME (label)) if (DECL_NAME (label))
...@@ -620,8 +686,16 @@ void ...@@ -620,8 +686,16 @@ void
expand_goto (label) expand_goto (label)
tree 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. */ /* 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) if (context != 0 && context != current_function_decl)
{ {
struct function *p = find_function_data (context); struct function *p = find_function_data (context);
...@@ -701,6 +775,16 @@ expand_goto_internal (body, label, last_insn) ...@@ -701,6 +775,16 @@ expand_goto_internal (body, label, last_insn)
struct nesting *block; struct nesting *block;
rtx stack_level = 0; 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) if (GET_CODE (label) != CODE_LABEL)
abort (); abort ();
...@@ -753,6 +837,77 @@ expand_goto_internal (body, label, last_insn) ...@@ -753,6 +837,77 @@ expand_goto_internal (body, label, last_insn)
emit_jump (label); 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 /* Generate if necessary a fixup for a goto
whose target label in tree structure (if any) is TREE_LABEL whose target label in tree structure (if any) is TREE_LABEL
and whose target in rtl is RTL_LABEL. and whose target in rtl is RTL_LABEL.
...@@ -884,6 +1039,37 @@ expand_fixup (tree_label, rtl_label, last_insn) ...@@ -884,6 +1039,37 @@ expand_fixup (tree_label, rtl_label, last_insn)
return block != 0; 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. /* When exiting a binding contour, process all pending gotos requiring fixups.
THISBLOCK is the structure that describes the block being exited. THISBLOCK is the structure that describes the block being exited.
STACK_LEVEL is the rtx for the stack level to restore exiting this contour. 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) ...@@ -907,6 +1093,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
{ {
register struct goto_fixup *f, *prev; 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. */ /* 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 /* We run this loop in two passes so that cleanups of exited blocks
are run first, and blocks that are exited are marked so 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) ...@@ -1039,6 +1231,72 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
f->stack_level = stack_level; 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). /* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text, BODY is a STRING_CST node containing the assembler code text,
...@@ -1048,6 +1306,12 @@ void ...@@ -1048,6 +1306,12 @@ void
expand_asm (body) expand_asm (body)
tree body; tree body;
{ {
if (output_bytecode)
{
error ("`asm' is illegal when generating bytecode");
return;
}
if (TREE_CODE (body) == ADDR_EXPR) if (TREE_CODE (body) == ADDR_EXPR)
body = TREE_OPERAND (body, 0); body = TREE_OPERAND (body, 0);
...@@ -1090,6 +1354,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1090,6 +1354,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* The insn we have emitted. */ /* The insn we have emitted. */
rtx insn; rtx insn;
if (output_bytecode)
{
error ("`asm' is illegal when generating bytecode");
return;
}
/* Count the number of meaningful clobbered registers, ignoring what /* Count the number of meaningful clobbered registers, ignoring what
we would ignore later. */ we would ignore later. */
nclobbers = 0; nclobbers = 0;
...@@ -1310,6 +1580,22 @@ void ...@@ -1310,6 +1580,22 @@ void
expand_expr_stmt (exp) expand_expr_stmt (exp)
tree 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, /* If -W, warn about statements with no side effects,
except for an explicit cast to void (e.g. for assert()), and except for an explicit cast to void (e.g. for assert()), and
except inside a ({...}) where they may be useful. */ except inside a ({...}) where they may be useful. */
...@@ -1459,10 +1745,17 @@ clear_last_expr () ...@@ -1459,10 +1745,17 @@ clear_last_expr ()
tree tree
expand_start_stmt_expr () 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, /* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */ so that rtl_expr_chain doesn't become garbage. */
int momentary = suspend_momentary (); momentary = suspend_momentary ();
tree t = make_node (RTL_EXPR); t = make_node (RTL_EXPR);
resume_momentary (momentary); resume_momentary (momentary);
start_sequence (); start_sequence ();
NO_DEFER_POP; NO_DEFER_POP;
...@@ -1486,6 +1779,38 @@ tree ...@@ -1486,6 +1779,38 @@ tree
expand_end_stmt_expr (t) expand_end_stmt_expr (t)
tree 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; OK_DEFER_POP;
if (last_expr_type == 0) if (last_expr_type == 0)
...@@ -1849,7 +2174,10 @@ expand_start_cond (cond, exitflag) ...@@ -1849,7 +2174,10 @@ expand_start_cond (cond, exitflag)
cond_stack = thiscond; cond_stack = thiscond;
nesting_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 /* Generate RTL between then-clause and the elseif-clause
...@@ -1875,6 +2203,13 @@ expand_start_else () ...@@ -1875,6 +2203,13 @@ expand_start_else ()
{ {
if (cond_stack->data.cond.endif_label == 0) if (cond_stack->data.cond.endif_label == 0)
cond_stack->data.cond.endif_label = gen_label_rtx (); 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_jump (cond_stack->data.cond.endif_label);
emit_label (cond_stack->data.cond.next_label); emit_label (cond_stack->data.cond.next_label);
cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */ cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
...@@ -1888,15 +2223,71 @@ expand_end_cond () ...@@ -1888,15 +2223,71 @@ expand_end_cond ()
{ {
struct nesting *thiscond = cond_stack; struct nesting *thiscond = cond_stack;
do_pending_stack_adjust (); if (output_bytecode)
if (thiscond->data.cond.next_label) bc_expand_end_cond ();
emit_label (thiscond->data.cond.next_label); else
if (thiscond->data.cond.endif_label) {
emit_label (thiscond->data.cond.endif_label); 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); POPSTACK (cond_stack);
last_expr_type = 0; 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 /* 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 loop should be exited by `exit_something'. This is a loop for which
...@@ -1923,6 +2314,12 @@ expand_start_loop (exit_flag) ...@@ -1923,6 +2314,12 @@ expand_start_loop (exit_flag)
loop_stack = thisloop; loop_stack = thisloop;
nesting_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 (); do_pending_stack_adjust ();
emit_queue (); emit_queue ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG); emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
...@@ -1951,21 +2348,54 @@ expand_start_loop_continue_elsewhere (exit_flag) ...@@ -1951,21 +2348,54 @@ expand_start_loop_continue_elsewhere (exit_flag)
void void
expand_loop_continue_here () expand_loop_continue_here ()
{ {
if (output_bytecode)
{
bc_emit_bytecode_labeldef (loop_stack->data.loop.continue_label->bc_label);
return;
}
do_pending_stack_adjust (); do_pending_stack_adjust ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT); emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
emit_label (loop_stack->data.loop.continue_label); 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. /* Finish a loop. Generate a jump back to the top and the loop-exit label.
Pop the block off of loop_stack. */ Pop the block off of loop_stack. */
void void
expand_end_loop () expand_end_loop ()
{ {
register rtx insn = get_last_insn (); register rtx insn;
register rtx start_label = loop_stack->data.loop.start_label; register rtx start_label;
rtx last_test_insn = 0; rtx last_test_insn = 0;
int num_insns = 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. */ /* Mark the continue-point at the top of the loop if none elsewhere. */
if (start_label == loop_stack->data.loop.continue_label) if (start_label == loop_stack->data.loop.continue_label)
...@@ -2113,7 +2543,15 @@ expand_exit_loop_if_false (whichloop, cond) ...@@ -2113,7 +2543,15 @@ expand_exit_loop_if_false (whichloop, cond)
whichloop = loop_stack; whichloop = loop_stack;
if (whichloop == 0) if (whichloop == 0)
return 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; return 1;
} }
...@@ -2176,6 +2614,12 @@ expand_null_return () ...@@ -2176,6 +2614,12 @@ expand_null_return ()
struct nesting *block = block_stack; struct nesting *block = block_stack;
rtx last_insn = 0; rtx last_insn = 0;
if (output_bytecode)
{
bc_emit_instruction (ret);
return;
}
/* Does any pending block have cleanups? */ /* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0) while (block && block->data.block.cleanups == 0)
...@@ -2298,6 +2742,15 @@ expand_return (retval) ...@@ -2298,6 +2742,15 @@ expand_return (retval)
int cleanups; int cleanups;
struct nesting *block; 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 function wants no value, give it none. */
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE) if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{ {
...@@ -2536,8 +2989,10 @@ expand_start_bindings (exit_flag) ...@@ -2536,8 +2989,10 @@ expand_start_bindings (exit_flag)
int exit_flag; int exit_flag;
{ {
struct nesting *thisblock = ALLOC_NESTING (); 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. */ /* Make an entry on block_stack for the block we are entering. */
...@@ -2580,8 +3035,11 @@ expand_start_bindings (exit_flag) ...@@ -2580,8 +3035,11 @@ expand_start_bindings (exit_flag)
block_stack = thisblock; block_stack = thisblock;
nesting_stack = thisblock; nesting_stack = thisblock;
/* Make a new level for allocating stack slots. */ if (!output_bytecode)
push_temp_slots (); {
/* 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 /* 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) ...@@ -2614,6 +3072,12 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
register struct nesting *thisblock = block_stack; register struct nesting *thisblock = block_stack;
register tree decl; register tree decl;
if (output_bytecode)
{
bc_expand_end_bindings (vars, mark_ends, dont_jump_in);
return;
}
if (warn_unused) if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl)) for (decl = vars; decl; decl = TREE_CHAIN (decl))
if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
...@@ -2830,6 +3294,35 @@ expand_end_bindings (vars, mark_ends, dont_jump_in) ...@@ -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 the stack slot nesting and free any slots at this level. */
pop_temp_slots (); 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. /* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) (Other kinds of declarations are simply ignored if seen here.)
...@@ -2854,7 +3347,15 @@ expand_decl (decl) ...@@ -2854,7 +3347,15 @@ expand_decl (decl)
register tree decl; register tree decl;
{ {
struct nesting *thisblock = block_stack; 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. /* Only automatic variables need any expansion done.
Static and external variables, and external functions, Static and external variables, and external functions,
...@@ -3046,6 +3547,52 @@ expand_decl (decl) ...@@ -3046,6 +3547,52 @@ expand_decl (decl)
if (obey_regdecls) if (obey_regdecls)
use_variable (DECL_RTL (decl)); 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. */ /* Emit code to perform the initialization of a declaration DECL. */
...@@ -3083,6 +3630,82 @@ expand_decl_init (decl) ...@@ -3083,6 +3630,82 @@ expand_decl_init (decl)
free_temp_slots (); 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; /* 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. for example, in C++, it might call the destructor for this variable.
...@@ -3301,6 +3924,12 @@ expand_start_case (exit_flag, expr, type, printname) ...@@ -3301,6 +3924,12 @@ expand_start_case (exit_flag, expr, type, printname)
case_stack = thiscase; case_stack = thiscase;
nesting_stack = thiscase; nesting_stack = thiscase;
if (output_bytecode)
{
bc_expand_start_case (thiscase, expr, type, printname);
return;
}
do_pending_stack_adjust (); do_pending_stack_adjust ();
/* Make sure case_stmt.start points to something that won't /* Make sure case_stmt.start points to something that won't
...@@ -3311,6 +3940,32 @@ expand_start_case (exit_flag, expr, type, printname) ...@@ -3311,6 +3940,32 @@ expand_start_case (exit_flag, expr, type, printname)
thiscase->data.case_stmt.start = get_last_insn (); 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 /* Start a "dummy case statement" within which case labels are invalid
and are not connected to any larger real case statement. 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 This can be used if you don't want to let a case statement jump
...@@ -3382,6 +4037,9 @@ pushcase (value, converter, label, duplicate) ...@@ -3382,6 +4037,9 @@ pushcase (value, converter, label, duplicate)
tree index_type; tree index_type;
tree nominal_type; tree nominal_type;
if (output_bytecode)
return bc_pushcase (value, label);
/* Fail if not inside a real case statement. */ /* Fail if not inside a real case statement. */
if (! (case_stack && case_stack->data.case_stmt.start)) if (! (case_stack && case_stack->data.case_stmt.start))
return 1; return 1;
...@@ -3588,6 +4246,62 @@ pushcase_range (value1, value2, converter, label, duplicate) ...@@ -3588,6 +4246,62 @@ pushcase_range (value1, value2, converter, label, duplicate)
return 0; 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 /* Called when the index of a switch statement is an enumerated type
and there is no default label. and there is no default label.
...@@ -3609,6 +4323,12 @@ check_for_full_enumeration_handling (type) ...@@ -3609,6 +4323,12 @@ check_for_full_enumeration_handling (type)
register tree chain; register tree chain;
int all_values = 1; 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 /* The time complexity of this loop is currently O(N * M), with
N being the number of members in the enumerated type, and N being the number of members in the enumerated type, and
M being the number of case expressions in the switch. */ M being the number of case expressions in the switch. */
...@@ -3707,6 +4427,46 @@ check_for_full_enumeration_handling (type) ...@@ -3707,6 +4427,46 @@ check_for_full_enumeration_handling (type)
} }
#endif /* 0 */ #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 /* Terminate a case (Pascal) or switch (C) statement
in which ORIG_INDEX is the expression to be tested. in which ORIG_INDEX is the expression to be tested.
...@@ -3721,14 +4481,24 @@ expand_end_case (orig_index) ...@@ -3721,14 +4481,24 @@ expand_end_case (orig_index)
register struct case_node *n; register struct case_node *n;
int count; int count;
rtx index; rtx index;
rtx table_label = gen_label_rtx (); rtx table_label;
int ncases; int ncases;
rtx *labelvec; rtx *labelvec;
register int i; register int i;
rtx before_case; rtx before_case;
register struct nesting *thiscase = case_stack; register struct nesting *thiscase = case_stack;
tree index_expr = thiscase->data.case_stmt.index_expr; tree index_expr;
int unsignedp = TREE_UNSIGNED (TREE_TYPE (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 (); do_pending_stack_adjust ();
...@@ -4069,6 +4839,110 @@ expand_end_case (orig_index) ...@@ -4069,6 +4839,110 @@ expand_end_case (orig_index)
free_temp_slots (); 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. */ /* Generate code to jump to LABEL if OP1 and OP2 are equal. */
static void static void
......
...@@ -57,6 +57,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -57,6 +57,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef XCOFF_DEBUGGING_INFO #ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" #include "xcoffout.h"
#endif #endif
#include "bytecode.h"
#include "bc-emit.h"
#ifdef VMS #ifdef VMS
/* The extra parameters substantially improve the I/O performance. */ /* The extra parameters substantially improve the I/O performance. */
...@@ -211,6 +214,9 @@ int errorcount = 0; ...@@ -211,6 +214,9 @@ int errorcount = 0;
int warningcount = 0; int warningcount = 0;
int sorrycount = 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. */ /* Pointer to function to compute the name to use to print a declaration. */
char *(*decl_printable_name) (); char *(*decl_printable_name) ();
...@@ -515,6 +521,7 @@ struct { char *string; int *variable; int on_value;} f_options[] = ...@@ -515,6 +521,7 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"inhibit-size-directive", &flag_inhibit_size_directive, 1}, {"inhibit-size-directive", &flag_inhibit_size_directive, 1},
{"verbose-asm", &flag_verbose_asm, 1}, {"verbose-asm", &flag_verbose_asm, 1},
{"gnu-linker", &flag_gnu_linker, 1} {"gnu-linker", &flag_gnu_linker, 1}
{"bytecode", &output_bytecode, 1}
}; };
/* Table of language-specific options. */ /* Table of language-specific options. */
...@@ -885,11 +892,14 @@ void ...@@ -885,11 +892,14 @@ void
fatal_insn_not_found (insn) fatal_insn_not_found (insn)
rtx insn; rtx insn;
{ {
if (INSN_CODE (insn) < 0) if (!output_bytecode)
error ("internal error--unrecognizable insn:", 0); {
else if (INSN_CODE (insn) < 0)
error ("internal error--insn does not satisfy its constraints:", 0); error ("internal error--unrecognizable insn:", 0);
debug_rtx (insn); else
error ("internal error--insn does not satisfy its constraints:", 0);
debug_rtx (insn);
}
if (asm_out_file) if (asm_out_file)
fflush (asm_out_file); fflush (asm_out_file);
if (aux_info_file) if (aux_info_file)
...@@ -1585,6 +1595,8 @@ compile_file (name) ...@@ -1585,6 +1595,8 @@ compile_file (name)
init_obstacks (); init_obstacks ();
init_tree_codes (); init_tree_codes ();
init_lex (); 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_rtl ();
init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE); || debug_info_level == DINFO_LEVEL_VERBOSE);
...@@ -1813,34 +1825,51 @@ compile_file (name) ...@@ -1813,34 +1825,51 @@ compile_file (name)
input_file_stack->next = 0; input_file_stack->next = 0;
input_file_stack->name = input_filename; 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 #ifndef ASM_IDENTIFY_GCC
fprintf (asm_out_file, "gcc2_compiled.:\n"); fprintf (asm_out_file, "gcc2_compiled.:\n");
#else #else
ASM_IDENTIFY_GCC (asm_out_file); ASM_IDENTIFY_GCC (asm_out_file);
#endif #endif
}
/* Output something to identify which front-end produced this file. */ /* Output something to identify which front-end produced this file. */
#ifdef ASM_IDENTIFY_LANGUAGE #ifdef ASM_IDENTIFY_LANGUAGE
ASM_IDENTIFY_LANGUAGE (asm_out_file); ASM_IDENTIFY_LANGUAGE (asm_out_file);
#endif #endif
/* ??? Note: There used to be a conditional here if (output_bytecode)
to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined. {
This was to guarantee separation between gcc_compiled. and if (profile_flag || profile_block_flag)
the first function, for the sake of dbx on Suns. error ("profiling not supported in bytecode compilation");
However, having the extra zero here confused the Emacs }
code for unexec, and might confuse other programs too. else
Therefore, I took out that change. {
In future versions we should find another way to solve /* ??? Note: There used to be a conditional here
that dbx problem. -- rms, 23 May 93. */ to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
This was to guarantee separation between gcc_compiled. and
/* Don't let the first function fall at the same address the first function, for the sake of dbx on Suns.
as gcc_compiled., if profiling. */ However, having the extra zero here confused the Emacs
if (profile_flag || profile_block_flag) code for unexec, and might confuse other programs too.
assemble_zeros (UNITS_PER_WORD); 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 /* If dbx symbol table desired, initialize writing it
and output the predefined types. */ and output the predefined types. */
...@@ -1861,7 +1890,8 @@ compile_file (name) ...@@ -1861,7 +1890,8 @@ compile_file (name)
/* Initialize yet another pass. */ /* Initialize yet another pass. */
init_final (main_input_filename); if (!output_bytecode)
init_final (main_input_filename);
start_time = get_run_time (); start_time = get_run_time ();
...@@ -2031,11 +2061,14 @@ compile_file (name) ...@@ -2031,11 +2061,14 @@ compile_file (name)
/* Output some stuff at end of file if nec. */ /* 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 #ifdef ASM_FILE_END
ASM_FILE_END (asm_out_file); ASM_FILE_END (asm_out_file);
#endif #endif
}
after_finish_compilation: after_finish_compilation:
...@@ -2113,24 +2146,28 @@ compile_file (name) ...@@ -2113,24 +2146,28 @@ compile_file (name)
{ {
fprintf (stderr,"\n"); fprintf (stderr,"\n");
print_time ("parse", parse_time); print_time ("parse", parse_time);
print_time ("integration", integration_time);
print_time ("jump", jump_time); if (!output_bytecode)
print_time ("cse", cse_time); {
print_time ("loop", loop_time); print_time ("integration", integration_time);
print_time ("cse2", cse2_time); print_time ("jump", jump_time);
print_time ("flow", flow_time); print_time ("cse", cse_time);
print_time ("combine", combine_time); print_time ("loop", loop_time);
print_time ("sched", sched_time); print_time ("cse2", cse2_time);
print_time ("local-alloc", local_alloc_time); print_time ("flow", flow_time);
print_time ("global-alloc", global_alloc_time); print_time ("combine", combine_time);
print_time ("sched2", sched2_time); print_time ("sched", sched_time);
print_time ("dbranch", dbr_sched_time); print_time ("local-alloc", local_alloc_time);
print_time ("shorten-branch", shorten_branch_time); print_time ("global-alloc", global_alloc_time);
print_time ("stack-reg", stack_reg_time); print_time ("sched2", sched2_time);
print_time ("final", final_time); print_time ("dbranch", dbr_sched_time);
print_time ("varconst", varconst_time); print_time ("shorten-branch", shorten_branch_time);
print_time ("symout", symout_time); print_time ("stack-reg", stack_reg_time);
print_time ("dump", dump_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) ...@@ -2236,6 +2273,9 @@ rest_of_compilation (decl)
tree saved_arguments = 0; tree saved_arguments = 0;
int failure = 0; int failure = 0;
if (output_bytecode)
return;
/* If we are reconsidering an inline function /* If we are reconsidering an inline function
at the end of compilation, skip the stuff for making it inline. */ at the end of compilation, skip the stuff for making it inline. */
...@@ -3166,7 +3206,12 @@ main (argc, argv, envp) ...@@ -3166,7 +3206,12 @@ main (argc, argv, envp)
error ("Invalid option `%s'", argv[i]); error ("Invalid option `%s'", argv[i]);
} }
else if (!strcmp (str, "p")) 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")) else if (!strcmp (str, "a"))
{ {
#if !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER) #if !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER)
...@@ -3325,6 +3370,18 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! ...@@ -3325,6 +3370,18 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
filename = argv[i]; 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) if (optimize == 0)
{ {
/* Inlining does not work if not optimizing, /* Inlining does not work if not optimizing,
...@@ -3398,10 +3455,14 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! ...@@ -3398,10 +3455,14 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
} }
/* Now that register usage is specified, convert it to HARD_REG_SETs. */ /* 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); compile_file (filename);
if (output_bytecode)
bc_write_file (stdout);
#ifndef OS2 #ifndef OS2
#ifndef VMS #ifndef VMS
if (flag_print_mem) if (flag_print_mem)
......
...@@ -38,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -38,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h" #include "regs.h"
#include "defaults.h" #include "defaults.h"
#include "real.h" #include "real.h"
#include "bytecode.h"
#include "obstack.h" #include "obstack.h"
...@@ -96,9 +97,11 @@ void assemble_name (); ...@@ -96,9 +97,11 @@ void assemble_name ();
int output_addressed_constants (); int output_addressed_constants ();
void output_constant (); void output_constant ();
void output_constructor (); void output_constructor ();
void output_byte_asm ();
void text_section (); void text_section ();
void readonly_data_section (); void readonly_data_section ();
void data_section (); void data_section ();
static void bc_assemble_integer ();
#ifdef EXTRA_SECTIONS #ifdef EXTRA_SECTIONS
static enum in_section {no_section, in_text, in_data, EXTRA_SECTIONS} in_section static enum in_section {no_section, in_text, in_data, EXTRA_SECTIONS} in_section
...@@ -120,7 +123,11 @@ text_section () ...@@ -120,7 +123,11 @@ text_section ()
{ {
if (in_section != in_text) 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; in_section = in_text;
} }
} }
...@@ -132,16 +139,21 @@ data_section () ...@@ -132,16 +139,21 @@ data_section ()
{ {
if (in_section != in_data) if (in_section != in_data)
{ {
if (flag_shared_data) if (output_bytecode)
bc_data ();
else
{ {
if (flag_shared_data)
{
#ifdef SHARED_SECTION_ASM_OP #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 #else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
#endif #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; in_section = in_data;
} }
...@@ -178,6 +190,16 @@ make_function_rtl (decl) ...@@ -178,6 +190,16 @@ make_function_rtl (decl)
{ {
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (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. */ /* Rename a nested function to avoid conflicts. */
if (decl_function_context (decl) != 0 if (decl_function_context (decl) != 0
&& DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != 0
...@@ -211,6 +233,48 @@ make_function_rtl (decl) ...@@ -211,6 +233,48 @@ make_function_rtl (decl)
function_defined = 1; 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. */ /* Given NAME, a putative register name, discard any customary prefixes. */
static char * static char *
...@@ -301,7 +365,15 @@ make_decl_rtl (decl, asmspec, top_level) ...@@ -301,7 +365,15 @@ make_decl_rtl (decl, asmspec, top_level)
int top_level; int top_level;
{ {
register char *name; 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) if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
...@@ -465,6 +537,12 @@ void ...@@ -465,6 +537,12 @@ void
assemble_asm (string) assemble_asm (string)
tree string; tree string;
{ {
if (output_bytecode)
{
error ("asm statements not allowed in interpreter");
return;
}
app_enable (); app_enable ();
if (TREE_CODE (string) == ADDR_EXPR) if (TREE_CODE (string) == ADDR_EXPR)
...@@ -576,7 +654,12 @@ assemble_start_function (decl, fnname) ...@@ -576,7 +654,12 @@ assemble_start_function (decl, fnname)
/* Tell assembler to move to target machine's alignment for functions. */ /* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0) 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 #ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname); ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
...@@ -600,7 +683,10 @@ assemble_start_function (decl, fnname) ...@@ -600,7 +683,10 @@ assemble_start_function (decl, fnname)
{ {
if (!first_global_object_name) if (!first_global_object_name)
STRIP_NAME_ENCODING (first_global_object_name, fnname); 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 */ /* Do any machine/system dependent processing of the function name */
...@@ -608,7 +694,10 @@ assemble_start_function (decl, fnname) ...@@ -608,7 +694,10 @@ assemble_start_function (decl, fnname)
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl); ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else #else
/* Standard thing is just output label for the function. */ /* 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 */ #endif /* ASM_DECLARE_FUNCTION_NAME */
} }
...@@ -631,6 +720,12 @@ void ...@@ -631,6 +720,12 @@ void
assemble_zeros (size) assemble_zeros (size)
int size; int size;
{ {
if (output_bytecode)
{
bc_emit_const_skip (size);
return;
}
#ifdef ASM_NO_SKIP_IN_TEXT #ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s, /* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */ so we must output 0s explicitly in the text section. */
...@@ -664,7 +759,12 @@ assemble_zeros (size) ...@@ -664,7 +759,12 @@ assemble_zeros (size)
else else
#endif #endif
if (size > 0) 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. */ /* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
...@@ -688,6 +788,12 @@ assemble_string (p, size) ...@@ -688,6 +788,12 @@ assemble_string (p, size)
int pos = 0; int pos = 0;
int maximum = 2000; int maximum = 2000;
if (output_bytecode)
{
bc_emit (p, size);
return;
}
/* If the string is very long, split it up. */ /* If the string is very long, split it up. */
while (pos < size) while (pos < size)
...@@ -696,7 +802,10 @@ assemble_string (p, size) ...@@ -696,7 +802,10 @@ assemble_string (p, size)
if (thissize > maximum) if (thissize > maximum)
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; pos += thissize;
p += thissize; p += thissize;
...@@ -725,6 +834,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ...@@ -725,6 +834,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
int reloc = 0; int reloc = 0;
enum in_section saved_in_section; enum in_section saved_in_section;
if (output_bytecode)
return;
if (GET_CODE (DECL_RTL (decl)) == REG) if (GET_CODE (DECL_RTL (decl)) == REG)
{ {
/* Do output symbol info for global register variables, but do nothing /* 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) ...@@ -734,19 +846,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
return; return;
TREE_ASM_WRITTEN (decl) = 1; TREE_ASM_WRITTEN (decl) = 1;
if (!output_bytecode)
{
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
/* File-scope global variables are output here. */ /* File-scope global variables are output here. */
if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
&& top_level) && top_level)
dbxout_symbol (decl, 0); dbxout_symbol (decl, 0);
#endif #endif
#ifdef SDB_DEBUGGING_INFO #ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && top_level if (write_symbols == SDB_DEBUG && top_level
/* Leave initialized global vars for end of compilation; /* Leave initialized global vars for end of compilation;
see comment in compile_file. */ see comment in compile_file. */
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0)) && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0); sdbout_symbol (decl, 0);
#endif #endif
}
/* Don't output any DWARF debugging information for variables here. /* Don't output any DWARF debugging information for variables here.
In the case of local variables, the information for them is output 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) ...@@ -880,12 +995,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded); ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
else else
#endif #endif
if (output_bytecode)
BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
else
{
#ifdef ASM_OUTPUT_ALIGNED_COMMON #ifdef ASM_OUTPUT_ALIGNED_COMMON
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
DECL_ALIGN (decl)); DECL_ALIGN (decl));
#else #else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded); ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
#endif #endif
}
} }
else else
{ {
...@@ -894,12 +1014,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ...@@ -894,12 +1014,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else else
#endif #endif
if (output_bytecode)
BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
else
{
#ifdef ASM_OUTPUT_ALIGNED_LOCAL #ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
DECL_ALIGN (decl)); DECL_ALIGN (decl));
#else #else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif #endif
}
} }
goto finish; goto finish;
} }
...@@ -1017,14 +1142,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ...@@ -1017,14 +1142,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
DECL_ALIGN (decl) = align; DECL_ALIGN (decl) = align;
if (align > BITS_PER_UNIT) 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. */ /* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME #ifdef ASM_DECLARE_OBJECT_NAME
ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
#else #else
/* Standard thing is just output label for the object. */ /* 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 */ #endif /* ASM_DECLARE_OBJECT_NAME */
if (!dont_output_data) if (!dont_output_data)
...@@ -1110,6 +1243,55 @@ contains_pointers_p (type) ...@@ -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. /* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.) (Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */ Do nothing if DECL is not external. */
...@@ -1118,6 +1300,9 @@ void ...@@ -1118,6 +1300,9 @@ void
assemble_external (decl) assemble_external (decl)
tree decl; tree decl;
{ {
if (output_bytecode)
return;
#ifdef ASM_OUTPUT_EXTERNAL #ifdef ASM_OUTPUT_EXTERNAL
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd' if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
&& DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
...@@ -1142,11 +1327,14 @@ assemble_external_libcall (fun) ...@@ -1142,11 +1327,14 @@ assemble_external_libcall (fun)
rtx fun; rtx fun;
{ {
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL #ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
/* Declare library function name external when first used, if nec. */ if (!output_bytecode)
if (! SYMBOL_REF_USED (fun))
{ {
SYMBOL_REF_USED (fun) = 1; /* Declare library function name external when first used, if nec. */
ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun); if (! SYMBOL_REF_USED (fun))
{
SYMBOL_REF_USED (fun) = 1;
ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
}
} }
#endif #endif
} }
...@@ -1166,7 +1354,10 @@ void ...@@ -1166,7 +1354,10 @@ void
assemble_label (name) assemble_label (name)
char *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. /* Output to FILE a reference to the assembler name of a C-level name NAME.
...@@ -1181,9 +1372,19 @@ assemble_name (file, name) ...@@ -1181,9 +1372,19 @@ assemble_name (file, name)
char *name; char *name;
{ {
if (name[0] == '*') if (name[0] == '*')
fputs (&name[1], file); {
if (output_bytecode)
bc_emit_labelref (name);
else
fputs (&name[1], file);
}
else 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 /* Allocate SIZE bytes writable static space with a gensym name
...@@ -1214,12 +1415,21 @@ assemble_static_space (size) ...@@ -1214,12 +1415,21 @@ assemble_static_space (size)
strlen (name) + 2); strlen (name) + 2);
strcpy (namestring, name); 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 #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 #else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif #endif
}
return x; return x;
} }
...@@ -1234,6 +1444,10 @@ assemble_trampoline_template () ...@@ -1234,6 +1444,10 @@ assemble_trampoline_template ()
char *name; char *name;
int align; int align;
/* Shouldn't get here */
if (output_bytecode)
abort ();
/* By default, put trampoline templates in read-only data section. */ /* By default, put trampoline templates in read-only data section. */
#ifdef TRAMPOLINE_SECTION #ifdef TRAMPOLINE_SECTION
...@@ -1683,9 +1897,13 @@ decode_addr_const (exp, value) ...@@ -1683,9 +1897,13 @@ decode_addr_const (exp, value)
break; break;
case LABEL_DECL: case LABEL_DECL:
x = gen_rtx (MEM, FUNCTION_MODE, if (output_bytecode)
gen_rtx (LABEL_REF, VOIDmode, /* FIXME: this may not be correct, check it */
label_rtx (TREE_OPERAND (exp, 0)))); 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; break;
case REAL_CST: case REAL_CST:
...@@ -1699,9 +1917,12 @@ decode_addr_const (exp, value) ...@@ -1699,9 +1917,12 @@ decode_addr_const (exp, value)
abort (); abort ();
} }
if (GET_CODE (x) != MEM) if (!output_bytecode)
abort (); {
x = XEXP (x, 0); if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
}
value->base = x; value->base = x;
value->offset = offset; value->offset = offset;
...@@ -2171,47 +2392,57 @@ output_constant_def (exp) ...@@ -2171,47 +2392,57 @@ output_constant_def (exp)
to see if any of them describes EXP. If yes, the descriptor records to see if any of them describes EXP. If yes, the descriptor records
the label number already assigned. */ the label number already assigned. */
hash = const_hash (exp) % MAX_HASH_TABLE; if (!output_bytecode)
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. hash = const_hash (exp) % MAX_HASH_TABLE;
Make a constant descriptor to enter EXP in the hash table.
Assign the label number and record it in the descriptor for for (desc = const_hash_table[hash]; desc; desc = desc->next)
future calls to this function to find. */ if (compare_constant (exp, desc))
{
/* Create a string containing the label name, in LABEL. */ found = desc->label;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); break;
}
desc = record_constant (exp);
desc->next = const_hash_table[hash]; if (found == 0)
desc->label {
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); /* No constant equal to EXP is known to have been output.
const_hash_table[hash] = desc; 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. */ /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
push_obstacks_nochange (); push_obstacks_nochange ();
if (TREE_PERMANENT (exp)) if (TREE_PERMANENT (exp))
end_temporary_allocation (); end_temporary_allocation ();
def = gen_rtx (SYMBOL_REF, Pmode, desc->label); if (!output_bytecode)
{
TREE_CST_RTL (exp) def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
= gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1; TREE_CST_RTL (exp)
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
|| TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
MEM_IN_STRUCT_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 (); pop_obstacks ();
/* Optionally set flags or add text to the name to record information /* Optionally set flags or add text to the name to record information
...@@ -2283,7 +2514,12 @@ output_constant_def_contents (exp, reloc, labelno) ...@@ -2283,7 +2514,12 @@ output_constant_def_contents (exp, reloc, labelno)
#endif #endif
if (align > BITS_PER_UNIT) 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. */ /* Output the label itself. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
...@@ -2891,6 +3127,22 @@ output_addressed_constants (exp) ...@@ -2891,6 +3127,22 @@ output_addressed_constants (exp)
} }
return reloc; 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. /* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline. This includes the pseudo-op such as ".int" or ".byte", and a newline.
...@@ -2925,7 +3177,10 @@ output_constant (exp, size) ...@@ -2925,7 +3177,10 @@ output_constant (exp, size)
This means to fill the space with zeros. */ This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0) 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; return;
} }
...@@ -3005,6 +3260,101 @@ output_constant (exp, size) ...@@ -3005,6 +3260,101 @@ output_constant (exp, size)
if (size > 0) if (size > 0)
assemble_zeros (size); 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 /* Subroutine of output_constant, used for CONSTRUCTORs
(aggregate constants). (aggregate constants).
...@@ -3083,7 +3433,10 @@ output_constructor (exp, size) ...@@ -3083,7 +3433,10 @@ output_constructor (exp, size)
if each element has the proper size. */ if each element has the proper size. */
if ((field != 0 || index != 0) && bitpos != total_bytes) 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; total_bytes = bitpos;
} }
...@@ -3254,3 +3607,42 @@ output_constructor (exp, size) ...@@ -3254,3 +3607,42 @@ output_constructor (exp, size)
if (total_bytes < size) if (total_bytes < size)
assemble_zeros (size - total_bytes); 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'");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment