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 \
cp-expr.o cp-pt.o cp-edsel.o cp-xref.o \
$(CPLUS_INPUT) cp-spew.o c-common.o
# Files specific to the C interpreter bytecode compiler(s).
BC_OBJS = bc-emit.o bc-optab.o
# Language-independent object files.
OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
function.o stmt.o expr.o calls.o expmed.o explow.o optabs.o varasm.o \
......@@ -461,6 +464,7 @@ CONFIG_H =
RTL_H = rtl.h rtl.def machmode.h machmode.def
TREE_H = tree.h real.h tree.def machmode.h machmode.def
CPLUS_TREE_H = $(TREE_H) cp-tree.h cp-tree.def
BYTECODE_H = bytecode.h bc-emit.h bc-optab.h
# Avoid a lot of time thinking about remaking Makefile.in and *.def.
.SUFFIXES: .in .def
......@@ -484,7 +488,7 @@ for-bootstrap: start.encap $(LIBGCC)
rest.encap: $(LIBGCC) stmp-headers $(STMP_FIXPROTO) $(EXTRA_PARTS)
# This is what is made with the host's compiler
# whether making a cross compiler or not.
native: config.status cpp $(LANGUAGES) $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
native: bytecode config.status cpp $(LANGUAGES) $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
# Define the names for selecting languages in LANGUAGES.
C c: cc1
......@@ -545,14 +549,14 @@ g++-cross: $(srcdir)/g++.c
$(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o g++-cross \
-DGCC_NAME=\"$(target)-gcc\" $(srcdir)/g++.c version.o $(LIBS)
cc1:$(P) $(C_OBJS) $(OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(LIBS)
cc1:$(P) $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(OBJS) $(LIBS)
cc1plus:$(P) $(CPLUS_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(BC_OBJS) $(OBJS) $(LIBS)
cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(LIBS)
cc1obj:$(P) $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1obj $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
# Copy float.h from its source.
gfloat.h: $(FLOAT_H)
......@@ -1247,6 +1251,63 @@ $(HOST_PREFIX_1)malloc.o: malloc.c
$(HOST_PREFIX_1):
touch $(HOST_PREFIX_1)
# Remake bytecode files.
# BI_ALL=bi-run.o
BI_ALL=
BC_ALL=bc-opname.h bc-opcode.h bc-arity.h
BI_OBJ=bi-parser.o bi-lexer.o bi-reverse.o
bc-emit.o : bc-emit.c $(CONFIG_H) $(BYTECODE_H)
bc-optab.o : bc-optab.c bc-typecd.def $(CONFIG_H) $(BYTECODE_H)
bytecode: $(BI_ALL) $(BC_ALL)
bi-arity: bi-arity.o
bi-opcode: bi-opcode.o
bi-opname: bi-opname.o
bi-unparse: bi-unparse.o
bi-lexer: bi-lexer.o
bi-arity bi-opcode bi-opname bi-unparse bi-lexer: $(BI_OBJ)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $^ $(LEXLIB)
bi-run.o: $(srcdir)/bi-run.c $(srcdir)/bi-run.h $(srcdir)/bc-typecd.h bc-opname.h bc-arity.h bc-opcode.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
bi-parser.c: $(srcdir)/bi-parser.y $(srcdir)/bi-parser.h
bi-parser.o: $(srcdir)/bi-parser.c $(srcdir)/bi-defs.h
$(CC) $(CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
bi-lexer.c: $(srcdir)/bi-lexer.l $(srcdir)/bi-parser.h
bi-lexer.o: bi-lexer.c bi-parser.h
$(CC) $(CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $<
bc-arity.h: $(srcdir)/bytecode.def bi-arity
-rm -f $@
bi-arity <$< >$@
bc-opcode.h: $(srcdir)/bytecode.def bi-opcode
-rm -f $@
bi-opcode <$< >$@
bc-opname.h: $(srcdir)/bytecode.def bi-opname
-rm -f $@
bi-opname <$< >$@
bytecode.mostlyclean:
-rm -f bc-arity.h bc-opcode.h bc-opname.h
bytecode.distclean bytecode.clean: bytecode.mostlyclean
-rm -f bi-arity bi-opcode bi-opname bi-unparse bi-lexer
bytecode.realclean: bytecode.clean
-rm -f bi-parser.c bi-lexer.c bi-parser.h
# Remake cpp and protoize.
# Making the preprocessor
......@@ -1507,7 +1568,7 @@ $(srcdir)/INSTALL: install1.texi install.texi
# `realclean' also deletes everything that could be regenerated automatically.
mostlyclean:
mostlyclean: bytecode.mostlyclean
-rm -f $(STAGESTUFF)
# Clean the objc subdir if we created one.
if [ -d objc ]; then \
......@@ -1545,7 +1606,7 @@ mostlyclean:
# Delete all files made by compilation
# that don't exist in the distribution.
clean: mostlyclean
clean: mostlyclean bytecode.clean
# It may not be quite desirable to delete unprotoize.c here,
# but the spec for `make clean' requires it.
# Using unprotoize.c is not quite right in the first place,
......@@ -1557,7 +1618,7 @@ clean: mostlyclean
# Delete all files that users would normally create
# while building and installing GCC.
distclean: clean
distclean: clean bytecode.distclean
-rm -f tm.h aux-output.c config.h md config.status tconfig.h hconfig.h
-rm -f Makefile *.oaux
-rm -fr stage1 stage2 stage3 stage4
......@@ -1581,7 +1642,7 @@ extraclean: distclean
# Get rid of every file that's generated from some other file.
# Most of these files ARE PRESENT in the GCC distribution.
realclean: distclean
realclean: distclean bytecode.realclean
-rm -f c-parse.y objc-parse.y
-rm -f cp-parse.c cp-parse.h cp-parse.output
-rm -f objc-parse.c objc-parse.output
......
......@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "config.h"
#include "tree.h"
#include "function.h"
#ifdef HANDLE_SYSV_PRAGMA
......@@ -45,20 +46,7 @@ handle_pragma_token (string, token)
char *string;
tree token;
{
static enum pragma_state
{
ps_start,
ps_done,
ps_bad,
ps_weak,
ps_name,
ps_equals,
ps_value,
ps_pack,
ps_left,
ps_align,
ps_right
} state = ps_start, type;
static enum pragma_state state = ps_start, type;
static char *name;
static char *value;
static int align;
......@@ -76,24 +64,8 @@ handle_pragma_token (string, token)
{
#ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK)
{
if (state == ps_name || state == ps_value)
{
fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
ASM_OUTPUT_LABELREF (asm_out_file, name);
fputc ('\n', asm_out_file);
if (state == ps_value)
{
fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
ASM_OUTPUT_LABELREF (asm_out_file, name);
fputc (',', asm_out_file);
ASM_OUTPUT_LABELREF (asm_out_file, value);
fputc ('\n', asm_out_file);
}
}
else if (! (state == ps_done || state == ps_start))
warning ("malformed `#pragma weak'");
}
handle_pragma_weak (state, asm_out_file, name, value);
#endif /* HANDLE_PRAMA_WEAK */
}
......
......@@ -42,8 +42,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h"
#include "insn-config.h"
#include "real.h"
#include "obstack.h"
#include "bytecode.h"
#include "machmode.h"
#include "bc-opcode.h"
#include "bc-typecd.h"
#include "bc-optab.h"
#include "bc-emit.h"
#include <stdio.h>
/* Opcode names */
#ifdef BCDEBUG_PRINT_CODE
char *opcode_name[] =
{
#include "bc-opname.h"
"***END***"
};
#endif
/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
After rtl generation, it is 1 plus the largest register number used. */
......@@ -203,6 +224,11 @@ extern int emit_lineno;
rtx change_address ();
void init_emit ();
extern struct obstack *rtl_obstack;
extern int stack_depth;
extern int max_stack_depth;
/* rtx gen_rtx (code, mode, [element1, ..., elementn])
**
** This routine generates an RTX of the size specified by
......@@ -1216,8 +1242,12 @@ change_address (memref, mode, addr)
rtx
gen_label_rtx ()
{
register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0,
label_num++, NULL_PTR);
register rtx label;
label = output_bytecode
? bc_gen_rtx (0, 0, bc_get_bytecode_label ())
: gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR);
LABEL_NUSES (label) = 0;
return label;
}
......@@ -2559,6 +2589,13 @@ emit_line_note (file, line)
char *file;
int line;
{
if (output_bytecode)
{
/* FIXME: for now we do nothing, but eventually we will have to deal with
debugging information. */
return 0;
}
emit_filename = file;
emit_lineno = line;
......
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. */
#include "integrate.h"
#include "real.h"
#include "function.h"
#include "bytecode.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
......@@ -2850,9 +2851,16 @@ void
output_inline_function (fndecl)
tree fndecl;
{
rtx head = DECL_SAVED_INSNS (fndecl);
rtx head;
rtx last;
if (output_bytecode)
{
warning ("`inline' ignored for bytecode output");
return;
}
head = DECL_SAVED_INSNS (fndecl);
current_function_decl = fndecl;
/* This call is only used to initialize global variables. */
......
......@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "recog.h"
#include "reload.h"
#include "real.h"
#include "bytecode.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
......@@ -413,6 +414,13 @@ fix_register (name, fixed, call_used)
{
int i;
if (output_bytecode)
{
warning ("request to mark `%s' as %s ignored by bytecode compiler",
name, call_used ? "call-used" : "fixed");
return;
}
/* Decode the name and update the primary form of
the register info. */
......
......@@ -139,6 +139,22 @@ typedef struct rtx_def
The number of operands and their types are controlled
by the `code' field, according to rtl.def. */
rtunion fld[1];
/* The rest is used instead of the above if bytecode is being output */
/* For static or external objects. */
char *label;
/* From the named label, or the local variable pointer or the
argument pointer, depending on context. */
int offset;
/* For goto labels inside bytecode functions. */
struct bc_label *bc_label;
/* A unique identifier */
int uid;
} *rtx;
/* Add prototype support. */
......@@ -640,6 +656,7 @@ extern rtx gen_rtx PROTO((enum rtx_code, enum machine_mode, ...));
extern rtvec gen_rtvec PROTO((int, ...));
#else
extern rtx bc_gen_rtx ();
extern rtx gen_rtx ();
extern rtvec gen_rtvec ();
#endif
......
......@@ -49,6 +49,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h"
#include "loop.h"
#include "recog.h"
#include "machmode.h"
#include "bytecode.h"
#include "bc-typecd.h"
#include "bc-opcode.h"
#include "bc-optab.h"
#include "bc-emit.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
......@@ -181,13 +188,28 @@ static void emit_jump_if_reachable ();
static int warn_if_unused_value ();
static void expand_goto_internal ();
static void bc_expand_goto_internal ();
static int expand_fixup ();
static void bc_expand_fixup ();
void fixup_gotos ();
static void bc_fixup_gotos ();
void free_temp_slots ();
static void expand_cleanups ();
static void expand_null_return_1 ();
static int tail_recursion_args ();
static void do_jump_if_equal ();
int bc_expand_exit_loop_if_false ();
void bc_expand_start_cond ();
void bc_expand_end_cond ();
void bc_expand_start_else ();
void bc_expand_end_bindings ();
void bc_expand_start_case ();
void bc_check_for_full_enumeration_handling ();
void bc_expand_end_case ();
void bc_expand_decl ();
extern rtx bc_allocate_local ();
extern rtx bc_allocate_variable_array ();
/* Stack of control and binding constructs we are currently inside.
......@@ -250,7 +272,8 @@ struct nesting
/* Sequence number of this binding contour within the function,
in order of entry. */
int block_start_count;
/* Nonzero => value to restore stack to on exit. */
/* Nonzero => value to restore stack to on exit. Complemented by
bc_stack_level (see below) when generating bytecodes. */
rtx stack_level;
/* The NOTE that starts this contour.
Used by expand_goto to check whether the destination
......@@ -277,6 +300,8 @@ struct nesting
struct label_chain *label_chain;
/* Number of function calls seen, as of start of this block. */
int function_call_count;
/* Bytecode specific: stack level to restore stack to on exit. */
int bc_stack_level;
} block;
/* For switch (C) or case (Pascal) statements,
and also for dummies (see `expand_start_case_dummy'). */
......@@ -285,6 +310,10 @@ struct nesting
/* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */
rtx start;
/* For bytecodes, the case table is in-lined right in the code.
A label is needed for skipping over this block. It is only
used when generating bytecodes. */
rtx skip_label;
/* A list of case labels, kept in ascending order by value
as the list is built.
During expand_end_case, this list may be rearranged into a
......@@ -425,6 +454,21 @@ struct goto_fixup
time this goto was seen.
The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
tree cleanup_list_list;
/* Bytecode specific members follow */
/* The label that this jump is jumping to, or 0 for break, continue
or return. */
struct bc_label *bc_target;
/* The label we use for the fixup patch */
struct bc_label *label;
/* True (non-0) if fixup has been handled */
int bc_handled:1;
/* Like stack_level above, except refers to the interpreter stack */
int bc_stack_level;
};
static struct goto_fixup *goto_fixup_chain;
......@@ -514,11 +558,16 @@ restore_stmt_status (p)
void
emit_nop ()
{
rtx last_insn = get_last_insn ();
if (!optimize
&& (GET_CODE (last_insn) == CODE_LABEL
|| prev_real_insn (last_insn) == 0))
emit_insn (gen_nop ());
rtx last_insn;
if (!output_bytecode)
{
last_insn = get_last_insn ();
if (!optimize
&& (GET_CODE (last_insn) == CODE_LABEL
|| prev_real_insn (last_insn) == 0))
emit_insn (gen_nop ());
}
}
/* Return the rtx-label that corresponds to a LABEL_DECL,
......@@ -555,9 +604,17 @@ void
expand_computed_goto (exp)
tree exp;
{
rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
emit_queue ();
emit_indirect_jump (x);
if (output_bytecode)
{
bc_expand_expr (exp);
bc_emit_instruction (jumpP);
}
else
{
rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
emit_queue ();
emit_indirect_jump (x);
}
}
/* Handle goto statements and the labels that they can go to. */
......@@ -579,6 +636,15 @@ expand_label (label)
{
struct label_chain *p;
if (output_bytecode)
{
if (! DECL_RTL (label))
DECL_RTL (label) = bc_gen_rtx ((char *) 0, 0, bc_get_bytecode_label ());
if (! bc_emit_bytecode_labeldef (DECL_RTL (label)->bc_label))
error ("multiply defined label");
return;
}
do_pending_stack_adjust ();
emit_label (label_rtx (label));
if (DECL_NAME (label))
......@@ -620,8 +686,16 @@ void
expand_goto (label)
tree label;
{
tree context;
if (output_bytecode)
{
expand_goto_internal (label, label_rtx (label), NULL_RTX);
return;
}
/* Check for a nonlocal goto to a containing function. */
tree context = decl_function_context (label);
context = decl_function_context (label);
if (context != 0 && context != current_function_decl)
{
struct function *p = find_function_data (context);
......@@ -701,6 +775,16 @@ expand_goto_internal (body, label, last_insn)
struct nesting *block;
rtx stack_level = 0;
/* NOTICE! If a bytecode instruction other than `jump' is needed,
then the caller has to call bc_expand_goto_internal()
directly. This is rather an exceptional case, and there aren't
that many places where this is necessary. */
if (output_bytecode)
{
expand_goto_internal (body, label, last_insn);
return;
}
if (GET_CODE (label) != CODE_LABEL)
abort ();
......@@ -753,6 +837,77 @@ expand_goto_internal (body, label, last_insn)
emit_jump (label);
}
/* Generate a jump with OPCODE to the given bytecode LABEL which is
found within BODY. */
static void
bc_expand_goto_internal (opcode, label, body)
enum bytecode_opcode opcode;
struct bc_label *label;
tree body;
{
struct nesting *block;
int stack_level = -1;
/* If the label is defined, adjust the stack as necessary.
If it's not defined, we have to push the reference on the
fixup list. */
if (label->defined)
{
/* Find the innermost pending block that contains the label.
(Check containment by comparing bytecode uids.) Then restore the
outermost stack level within that block. */
for (block = block_stack; block; block = block->next)
{
if (block->data.block.first_insn->uid < label->uid)
break;
if (block->data.block.bc_stack_level)
stack_level = block->data.block.bc_stack_level;
/* Execute the cleanups for blocks we are exiting. */
if (block->data.block.cleanups != 0)
{
expand_cleanups (block->data.block.cleanups, NULL_TREE);
do_pending_stack_adjust ();
}
}
/* Restore the stack level. If we need to adjust the stack, we
must do so after the jump, since the jump may depend on
what's on the stack. Thus, any stack-modifying conditional
jumps (these are the only ones that rely on what's on the
stack) go into the fixup list. */
if (stack_level >= 0
&& stack_depth != stack_level
&& opcode != jump)
bc_expand_fixup (opcode, label, stack_level);
else
{
if (stack_level >= 0)
bc_adjust_stack (stack_depth - stack_level);
if (body && DECL_BIT_FIELD (body))
error ("jump to `%s' invalidly jumps into binding contour",
IDENTIFIER_POINTER (DECL_NAME (body)));
/* Emit immediate jump */
bc_emit_bytecode (opcode);
bc_emit_bytecode_labelref (label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
}
else
/* Put goto in the fixup list */
bc_expand_fixup (opcode, label, stack_level);
}
/* Generate if necessary a fixup for a goto
whose target label in tree structure (if any) is TREE_LABEL
and whose target in rtl is RTL_LABEL.
......@@ -884,6 +1039,37 @@ expand_fixup (tree_label, rtl_label, last_insn)
return block != 0;
}
/* Generate bytecode jump with OPCODE to a fixup routine that links to LABEL.
Make the fixup restore the stack level to STACK_LEVEL. */
static void
bc_expand_fixup (opcode, label, stack_level)
enum bytecode_opcode opcode;
struct bc_label *label;
int stack_level;
{
struct goto_fixup *fixup
= (struct goto_fixup *) oballoc (sizeof (struct goto_fixup));
fixup->label = bc_get_bytecode_label ();
fixup->bc_target = label;
fixup->bc_stack_level = stack_level;
fixup->bc_handled = FALSE;
fixup->next = goto_fixup_chain;
goto_fixup_chain = fixup;
/* Insert a jump to the fixup code */
bc_emit_bytecode (opcode);
bc_emit_bytecode_labelref (fixup->label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
/* When exiting a binding contour, process all pending gotos requiring fixups.
THISBLOCK is the structure that describes the block being exited.
STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
......@@ -907,6 +1093,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
{
register struct goto_fixup *f, *prev;
if (output_bytecode)
{
bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in);
return;
}
/* F is the fixup we are considering; PREV is the previous one. */
/* We run this loop in two passes so that cleanups of exited blocks
are run first, and blocks that are exited are marked so
......@@ -1039,6 +1231,72 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
f->stack_level = stack_level;
}
}
/* When exiting a binding contour, process all pending gotos requiring fixups.
Note: STACK_DEPTH is not altered.
The arguments are currently not used in the bytecode compiler, but we may need
them one day for languages other than C.
THISBLOCK is the structure that describes the block being exited.
STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
FIRST_INSN is the insn that began this contour.
Gotos that jump out of this contour must restore the
stack level and do the cleanups before actually jumping.
DONT_JUMP_IN nonzero means report error there is a jump into this
contour from before the beginning of the contour.
This is also done if STACK_LEVEL is nonzero. */
static void
bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
struct nesting *thisblock;
int stack_level;
tree cleanup_list;
rtx first_insn;
int dont_jump_in;
{
register struct goto_fixup *f, *prev;
int saved_stack_depth;
/* F is the fixup we are considering; PREV is the previous one. */
for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
{
/* Test for a fixup that is inactive because it is already handled. */
if (f->before_jump == 0)
{
/* Delete inactive fixup from the chain, if that is easy to do. */
if (prev)
prev->next = f->next;
}
/* Emit code to restore the stack and continue */
bc_emit_bytecode_labeldef (f->label);
/* Save stack_depth across call, since bc_adjust_stack () will alter
the perceived stack depth via the instructions generated. */
if (f->bc_stack_level >= 0)
{
saved_stack_depth = stack_depth;
bc_adjust_stack (stack_depth - f->bc_stack_level);
stack_depth = saved_stack_depth;
}
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (f->bc_target);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
goto_fixup_chain = NULL;
}
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
......@@ -1048,6 +1306,12 @@ void
expand_asm (body)
tree body;
{
if (output_bytecode)
{
error ("`asm' is illegal when generating bytecode");
return;
}
if (TREE_CODE (body) == ADDR_EXPR)
body = TREE_OPERAND (body, 0);
......@@ -1090,6 +1354,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* The insn we have emitted. */
rtx insn;
if (output_bytecode)
{
error ("`asm' is illegal when generating bytecode");
return;
}
/* Count the number of meaningful clobbered registers, ignoring what
we would ignore later. */
nclobbers = 0;
......@@ -1310,6 +1580,22 @@ void
expand_expr_stmt (exp)
tree exp;
{
if (output_bytecode)
{
int org_stack_depth = stack_depth;
bc_expand_expr (exp);
/* Restore stack depth */
if (stack_depth < org_stack_depth)
abort ();
bc_emit_instruction (drop);
last_expr_type = TREE_TYPE (exp);
return;
}
/* If -W, warn about statements with no side effects,
except for an explicit cast to void (e.g. for assert()), and
except inside a ({...}) where they may be useful. */
......@@ -1459,10 +1745,17 @@ clear_last_expr ()
tree
expand_start_stmt_expr ()
{
int momentary;
tree t;
/* When generating bytecode just note down the stack depth */
if (output_bytecode)
return (build_int_2 (stack_depth, 0));
/* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */
int momentary = suspend_momentary ();
tree t = make_node (RTL_EXPR);
momentary = suspend_momentary ();
t = make_node (RTL_EXPR);
resume_momentary (momentary);
start_sequence ();
NO_DEFER_POP;
......@@ -1486,6 +1779,38 @@ tree
expand_end_stmt_expr (t)
tree t;
{
if (output_bytecode)
{
int i;
tree t;
/* At this point, all expressions have been evaluated in order.
However, all expression values have been popped when evaluated,
which means we have to recover the last expression value. This is
the last value removed by means of a `drop' instruction. Instead
of adding code to inhibit dropping the last expression value, it
is here recovered by undoing the `drop'. Since `drop' is
equivalent to `adjustackSI [1]', it can be undone with `adjstackSI
[-1]'. */
bc_adjust_stack (-1);
if (!last_expr_type)
last_expr_type = void_type_node;
t = make_node (RTL_EXPR);
TREE_TYPE (t) = last_expr_type;
RTL_EXPR_RTL (t) = NULL;
RTL_EXPR_SEQUENCE (t) = NULL;
/* Don't consider deleting this expr or containing exprs at tree level. */
TREE_THIS_VOLATILE (t) = 1;
last_expr_type = 0;
return t;
}
OK_DEFER_POP;
if (last_expr_type == 0)
......@@ -1849,7 +2174,10 @@ expand_start_cond (cond, exitflag)
cond_stack = thiscond;
nesting_stack = thiscond;
do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
if (output_bytecode)
bc_expand_start_cond (cond, exitflag);
else
do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
}
/* Generate RTL between then-clause and the elseif-clause
......@@ -1875,6 +2203,13 @@ expand_start_else ()
{
if (cond_stack->data.cond.endif_label == 0)
cond_stack->data.cond.endif_label = gen_label_rtx ();
if (output_bytecode)
{
bc_expand_start_else ();
return;
}
emit_jump (cond_stack->data.cond.endif_label);
emit_label (cond_stack->data.cond.next_label);
cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
......@@ -1888,15 +2223,71 @@ expand_end_cond ()
{
struct nesting *thiscond = cond_stack;
do_pending_stack_adjust ();
if (thiscond->data.cond.next_label)
emit_label (thiscond->data.cond.next_label);
if (thiscond->data.cond.endif_label)
emit_label (thiscond->data.cond.endif_label);
if (output_bytecode)
bc_expand_end_cond ();
else
{
do_pending_stack_adjust ();
if (thiscond->data.cond.next_label)
emit_label (thiscond->data.cond.next_label);
if (thiscond->data.cond.endif_label)
emit_label (thiscond->data.cond.endif_label);
}
POPSTACK (cond_stack);
last_expr_type = 0;
}
/* Generate code for the start of an if-then. COND is the expression
whose truth is to be tested; if EXITFLAG is nonzero this conditional
is to be visible to exit_something. It is assumed that the caller
has pushed the previous context on the cond stack. */
void
bc_expand_start_cond (cond, exitflag)
tree cond;
int exitflag;
{
struct nesting *thiscond = cond_stack;
thiscond->data.case_stmt.nominal_type = cond;
bc_expand_expr (cond);
bc_emit_bytecode (jumpifnot);
bc_emit_bytecode_labelref (thiscond->exit_label->bc_label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
/* Generate the label for the end of an if with
no else- clause. */
void
bc_expand_end_cond ()
{
struct nesting *thiscond = cond_stack;
bc_emit_bytecode_labeldef (thiscond->exit_label->bc_label);
}
/* Generate code for the start of the else- clause of
an if-then-else. */
void
bc_expand_start_else ()
{
struct nesting *thiscond = cond_stack;
thiscond->data.cond.endif_label = thiscond->exit_label;
thiscond->exit_label = gen_label_rtx ();
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (thiscond->exit_label->bc_label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
bc_emit_bytecode_labeldef (thiscond->data.cond.endif_label->bc_label);
}
/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
loop should be exited by `exit_something'. This is a loop for which
......@@ -1923,6 +2314,12 @@ expand_start_loop (exit_flag)
loop_stack = thisloop;
nesting_stack = thisloop;
if (output_bytecode)
{
bc_emit_bytecode_labeldef (thisloop->data.loop.start_label->bc_label);
return thisloop;
}
do_pending_stack_adjust ();
emit_queue ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
......@@ -1951,21 +2348,54 @@ expand_start_loop_continue_elsewhere (exit_flag)
void
expand_loop_continue_here ()
{
if (output_bytecode)
{
bc_emit_bytecode_labeldef (loop_stack->data.loop.continue_label->bc_label);
return;
}
do_pending_stack_adjust ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
emit_label (loop_stack->data.loop.continue_label);
}
/* End a loop. */
static void
bc_expand_end_loop ()
{
struct nesting *thisloop = loop_stack;
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (thisloop->data.loop.start_label->bc_label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
bc_emit_bytecode_labeldef (thisloop->exit_label->bc_label);
POPSTACK (loop_stack);
last_expr_type = 0;
}
/* Finish a loop. Generate a jump back to the top and the loop-exit label.
Pop the block off of loop_stack. */
void
expand_end_loop ()
{
register rtx insn = get_last_insn ();
register rtx start_label = loop_stack->data.loop.start_label;
register rtx insn;
register rtx start_label;
rtx last_test_insn = 0;
int num_insns = 0;
if (output_bytecode)
{
bc_expand_end_loop ();
return;
}
insn = get_last_insn ();
start_label = loop_stack->data.loop.start_label;
/* Mark the continue-point at the top of the loop if none elsewhere. */
if (start_label == loop_stack->data.loop.continue_label)
......@@ -2113,7 +2543,15 @@ expand_exit_loop_if_false (whichloop, cond)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
if (output_bytecode)
{
bc_expand_expr (cond);
bc_expand_goto_internal (jumpifnot,
whichloop->exit_label->bc_label, NULL_RTX);
}
else
do_jump (cond, whichloop->data.loop.end_label, NULL_RTX);
return 1;
}
......@@ -2176,6 +2614,12 @@ expand_null_return ()
struct nesting *block = block_stack;
rtx last_insn = 0;
if (output_bytecode)
{
bc_emit_instruction (ret);
return;
}
/* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0)
......@@ -2298,6 +2742,15 @@ expand_return (retval)
int cleanups;
struct nesting *block;
/* Bytecode returns are quite simple, just leave the result on the
arithmetic stack. */
if (output_bytecode)
{
bc_expand_expr (retval);
bc_emit_instruction (ret);
return;
}
/* If function wants no value, give it none. */
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{
......@@ -2536,8 +2989,10 @@ expand_start_bindings (exit_flag)
int exit_flag;
{
struct nesting *thisblock = ALLOC_NESTING ();
rtx note;
rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
if (!output_bytecode)
note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
/* Make an entry on block_stack for the block we are entering. */
......@@ -2580,8 +3035,11 @@ expand_start_bindings (exit_flag)
block_stack = thisblock;
nesting_stack = thisblock;
/* Make a new level for allocating stack slots. */
push_temp_slots ();
if (!output_bytecode)
{
/* Make a new level for allocating stack slots. */
push_temp_slots ();
}
}
/* Given a pointer to a BLOCK node, save a pointer to the most recently
......@@ -2614,6 +3072,12 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
register struct nesting *thisblock = block_stack;
register tree decl;
if (output_bytecode)
{
bc_expand_end_bindings (vars, mark_ends, dont_jump_in);
return;
}
if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
......@@ -2830,6 +3294,35 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
/* Pop the stack slot nesting and free any slots at this level. */
pop_temp_slots ();
}
/* End a binding contour.
VARS is the chain of VAR_DECL nodes for the variables bound
in this contour. MARK_ENDS is nonzer if we should put a note
at the beginning and end of this binding contour.
DONT_JUMP_IN is nonzero if it is not valid to jump into this
contour. */
void
bc_expand_end_bindings (vars, mark_ends, dont_jump_in)
tree vars;
int mark_ends;
int dont_jump_in;
{
struct nesting *thisbind = nesting_stack;
tree decl;
if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
if (! TREE_USED (TREE_VALUE (decl)) && TREE_CODE (TREE_VALUE (decl)) == VAR_DECL)
warning_with_decl (decl, "unused variable `%s'");
bc_emit_bytecode_labeldef (thisbind->exit_label->bc_label);
/* Pop block/bindings off stack */
POPSTACK (nesting_stack);
POPSTACK (block_stack);
}
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.)
......@@ -2854,7 +3347,15 @@ expand_decl (decl)
register tree decl;
{
struct nesting *thisblock = block_stack;
tree type = TREE_TYPE (decl);
tree type;
if (output_bytecode)
{
bc_expand_decl (decl, 0);
return;
}
type = TREE_TYPE (decl);
/* Only automatic variables need any expansion done.
Static and external variables, and external functions,
......@@ -3046,6 +3547,52 @@ expand_decl (decl)
if (obey_regdecls)
use_variable (DECL_RTL (decl));
}
/* Generate code for the automatic variable declaration DECL. For
most variables this just means we give it a stack offset. The
compiler sometimes emits cleanups without variables and we will
have to deal with those too. */
void
bc_expand_decl (decl, cleanup)
tree decl;
tree cleanup;
{
tree type;
if (!decl)
{
/* A cleanup with no variable. */
if (!cleanup)
abort ();
return;
}
/* Only auto variables need any work. */
if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
return;
type = TREE_TYPE (decl);
if (type == error_mark_node)
DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
else if (DECL_SIZE (decl) == 0)
/* Variable with incomplete type. The stack offset herein will be
fixed later in expand_decl_init (). */
DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
else if (TREE_CONSTANT (DECL_SIZE (decl)))
{
DECL_RTL (decl) = bc_allocate_local (TREE_INT_CST_LOW (DECL_SIZE (decl)) / BITS_PER_UNIT,
DECL_ALIGN (decl));
}
else
DECL_RTL (decl) = bc_allocate_variable_array (DECL_SIZE (decl));
}
/* Emit code to perform the initialization of a declaration DECL. */
......@@ -3083,6 +3630,82 @@ expand_decl_init (decl)
free_temp_slots ();
}
/* Expand initialization for variable-sized types. Allocate array
using newlocalSI and set local variable, which is a pointer to the
storage. */
bc_expand_variable_local_init (decl)
tree decl;
{
/* Evaluate size expression and coerce to SI */
bc_expand_expr (DECL_SIZE (decl));
/* Type sizes are always (?) of TREE_CODE INTEGER_CST, so
no coercion is necessary (?) */
/* emit_typecode_conversion (preferred_typecode (TYPE_MODE (DECL_SIZE (decl)),
TREE_UNSIGNED (DECL_SIZE (decl))), SIcode); */
/* Emit code to allocate array */
bc_emit_instruction (newlocalSI);
/* Store array pointer in local variable. This is the only instance
where we actually want the address of the pointer to the
variable-size block, rather than the pointer itself. We avoid
using expand_address() since that would cause the pointer to be
pushed rather than its address. Hence the hard-coded reference;
notice also that the variable is always local (no global
variable-size type variables). */
bc_load_localaddr (DECL_RTL (decl));
bc_emit_instruction (storeP);
}
/* Emit code to initialize a declaration. */
void
bc_expand_decl_init (decl)
tree decl;
{
int org_stack_depth;
/* Statical initializers are handled elsewhere */
if (TREE_STATIC (decl))
return;
/* Memory original stack depth */
org_stack_depth = stack_depth;
/* If the type is variable-size, we first create its space (we ASSUME
it CAN'T be static). We do this regardless of whether there's an
initializer assignment or not. */
if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
bc_expand_variable_local_init (decl);
/* Expand initializer assignment */
if (DECL_INITIAL (decl) == error_mark_node)
{
enum tree_code code = TREE_CODE (TREE_TYPE (decl));
if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
|| code == POINTER_TYPE)
expand_assignment (TREE_TYPE (decl), decl,
convert (TREE_TYPE (decl), integer_zero_node));
}
else if (DECL_INITIAL (decl))
expand_assignment (TREE_TYPE (decl), decl, DECL_INITIAL (decl));
/* Restore stack depth */
if (org_stack_depth > stack_depth)
abort ();
bc_adjust_stack (stack_depth - org_stack_depth);
}
/* CLEANUP is an expression to be executed at exit from this binding contour;
for example, in C++, it might call the destructor for this variable.
......@@ -3301,6 +3924,12 @@ expand_start_case (exit_flag, expr, type, printname)
case_stack = thiscase;
nesting_stack = thiscase;
if (output_bytecode)
{
bc_expand_start_case (thiscase, expr, type, printname);
return;
}
do_pending_stack_adjust ();
/* Make sure case_stmt.start points to something that won't
......@@ -3311,6 +3940,32 @@ expand_start_case (exit_flag, expr, type, printname)
thiscase->data.case_stmt.start = get_last_insn ();
}
/* Enter a case statement. It is assumed that the caller has pushed
the current context onto the case stack. */
void
bc_expand_start_case (thiscase, expr, type, printname)
struct nesting *thiscase;
tree expr;
tree type;
char *printname;
{
bc_expand_expr (expr);
bc_expand_conversion (TREE_TYPE (expr), type);
/* For cases, the skip is a place we jump to that's emitted after
the size of the jump table is known. */
thiscase->data.case_stmt.skip_label = gen_label_rtx ();
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (thiscase->data.case_stmt.skip_label->bc_label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
/* Start a "dummy case statement" within which case labels are invalid
and are not connected to any larger real case statement.
This can be used if you don't want to let a case statement jump
......@@ -3382,6 +4037,9 @@ pushcase (value, converter, label, duplicate)
tree index_type;
tree nominal_type;
if (output_bytecode)
return bc_pushcase (value, label);
/* Fail if not inside a real case statement. */
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
......@@ -3588,6 +4246,62 @@ pushcase_range (value1, value2, converter, label, duplicate)
return 0;
}
/* Accumulate one case or default label; VALUE is the value of the
case, or nil for a default label. If not currently inside a case,
return 1 and do nothing. If VALUE is a duplicate or overlaps, return
2 and do nothing. If VALUE is out of range, return 3 and do nothing.
Return 0 on success. This function is a leftover from the earlier
bytecode compiler, which was based on gcc 1.37. It should be
merged into pushcase. */
int
bc_pushcase (value, label)
tree value;
tree label;
{
struct nesting *thiscase = case_stack;
struct case_node *case_label, *new_label;
if (! thiscase)
return 1;
/* Fail if duplicate, overlap, or out of type range. */
if (value)
{
value = convert (thiscase->data.case_stmt.nominal_type, value);
if (! int_fits_type_p (value, thiscase->data.case_stmt.nominal_type))
return 3;
for (case_label = thiscase->data.case_stmt.case_list;
case_label->left; case_label = case_label->left)
if (! tree_int_cst_lt (case_label->left->high, value))
break;
if (case_label != thiscase->data.case_stmt.case_list
&& ! tree_int_cst_lt (case_label->high, value)
|| case_label->left && ! tree_int_cst_lt (value, case_label->left->low))
return 2;
new_label = (struct case_node *) oballoc (sizeof (struct case_node));
new_label->low = new_label->high = copy_node (value);
new_label->code_label = label;
new_label->left = case_label->left;
case_label->left = new_label;
thiscase->data.case_stmt.num_ranges++;
}
else
{
if (thiscase->data.case_stmt.default_label)
return 2;
thiscase->data.case_stmt.default_label = label;
}
expand_label (label);
return 0;
}
/* Called when the index of a switch statement is an enumerated type
and there is no default label.
......@@ -3609,6 +4323,12 @@ check_for_full_enumeration_handling (type)
register tree chain;
int all_values = 1;
if (output_bytecode)
{
bc_check_for_full_enumeration_handling (type);
return;
}
/* The time complexity of this loop is currently O(N * M), with
N being the number of members in the enumerated type, and
M being the number of case expressions in the switch. */
......@@ -3707,6 +4427,46 @@ check_for_full_enumeration_handling (type)
}
#endif /* 0 */
}
/* Check that all enumeration literals are covered by the case
expressions of a switch. Also warn if there are any cases
that are not elements of the enumerated type. */
void
bc_check_for_full_enumeration_handling (type)
tree type;
{
struct nesting *thiscase = case_stack;
struct case_node *c;
tree e;
/* Check for enums not handled. */
for (e = TYPE_VALUES (type); e; e = TREE_CHAIN (e))
{
for (c = thiscase->data.case_stmt.case_list->left;
c && tree_int_cst_lt (c->high, TREE_VALUE (e));
c = c->left)
;
if (! (c && tree_int_cst_equal (c->low, TREE_VALUE (e))))
warning ("enumerated value `%s' not handled in switch",
IDENTIFIER_POINTER (TREE_PURPOSE (e)));
}
/* Check for cases not in the enumeration. */
for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
{
for (e = TYPE_VALUES (type);
e && !tree_int_cst_equal (c->low, TREE_VALUE (e));
e = TREE_CHAIN (e))
;
if (! e)
warning ("case value `%d' not in enumerated type `%s'",
TREE_INT_CST_LOW (c->low),
IDENTIFIER_POINTER (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
? TYPE_NAME (type)
: DECL_NAME (TYPE_NAME (type))));
}
}
/* Terminate a case (Pascal) or switch (C) statement
in which ORIG_INDEX is the expression to be tested.
......@@ -3721,14 +4481,24 @@ expand_end_case (orig_index)
register struct case_node *n;
int count;
rtx index;
rtx table_label = gen_label_rtx ();
rtx table_label;
int ncases;
rtx *labelvec;
register int i;
rtx before_case;
register struct nesting *thiscase = case_stack;
tree index_expr = thiscase->data.case_stmt.index_expr;
int unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
tree index_expr;
int unsignedp;
if (output_bytecode)
{
bc_expand_end_case (orig_index);
return;
}
table_label = gen_label_rtx ();
index_expr = thiscase->data.case_stmt.index_expr;
unsignedp = TREE_UNSIGNED (TREE_TYPE (index_expr));
do_pending_stack_adjust ();
......@@ -4069,6 +4839,110 @@ expand_end_case (orig_index)
free_temp_slots ();
}
/* Terminate a case statement. EXPR is the original index
expression. */
void
bc_expand_end_case (expr)
tree expr;
{
struct nesting *thiscase = case_stack;
enum bytecode_opcode opcode;
struct bc_label *jump_label;
struct case_node *c;
bc_emit_bytecode (jump);
bc_emit_bytecode_labelref (thiscase->exit_label->bc_label);
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
/* Now that the size of the jump table is known, emit the actual
indexed jump instruction. */
bc_emit_bytecode_labeldef (thiscase->data.case_stmt.skip_label->bc_label);
opcode = TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode
? TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseSU : caseSI
: TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseDU : caseDI;
bc_emit_bytecode (opcode);
/* Now emit the case instructions literal arguments, in order.
In addition to the value on the stack, it uses:
1. The address of the jump table.
2. The size of the jump table.
3. The default label. */
jump_label = bc_get_bytecode_label ();
bc_emit_bytecode_labelref (jump_label);
bc_emit_bytecode_const ((char *) &thiscase->data.case_stmt.num_ranges,
sizeof thiscase->data.case_stmt.num_ranges);
if (thiscase->data.case_stmt.default_label)
bc_emit_bytecode_labelref (DECL_RTL (thiscase->
data.case_stmt.default_label)->bc_label);
else
bc_emit_bytecode_labelref (thiscase->exit_label->bc_label);
/* Output the jump table. */
bc_align_bytecode (3 /* PTR_ALIGN */);
bc_emit_bytecode_labeldef (jump_label);
if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode)
for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
{
opcode = TREE_INT_CST_LOW (c->low);
bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
opcode = TREE_INT_CST_LOW (c->high);
bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
bc_emit_bytecode_labelref (DECL_RTL (c->code_label)->bc_label);
}
else
if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == DImode)
for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
{
bc_emit_bytecode_DI_const (c->low);
bc_emit_bytecode_DI_const (c->high);
bc_emit_bytecode_labelref (DECL_RTL (c->code_label)->bc_label);
}
else
/* Bad mode */
abort ();
bc_emit_bytecode_labeldef (thiscase->exit_label->bc_label);
/* Possibly issue enumeration warnings. */
if (!thiscase->data.case_stmt.default_label
&& TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
&& TREE_CODE (expr) != INTEGER_CST
&& warn_switch)
check_for_full_enumeration_handling (TREE_TYPE (expr));
#ifdef DEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
POPSTACK (case_stack);
}
/* Return unique bytecode ID. */
int
bc_new_uid ()
{
static int bc_uid = 0;
return (++bc_uid);
}
/* Generate code to jump to LABEL if OP1 and OP2 are equal. */
static void
......
......@@ -57,6 +57,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#include "bytecode.h"
#include "bc-emit.h"
#ifdef VMS
/* The extra parameters substantially improve the I/O performance. */
......@@ -211,6 +214,9 @@ int errorcount = 0;
int warningcount = 0;
int sorrycount = 0;
/* Flag to output bytecode instead of native assembler */
int output_bytecode = 0;
/* Pointer to function to compute the name to use to print a declaration. */
char *(*decl_printable_name) ();
......@@ -515,6 +521,7 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"inhibit-size-directive", &flag_inhibit_size_directive, 1},
{"verbose-asm", &flag_verbose_asm, 1},
{"gnu-linker", &flag_gnu_linker, 1}
{"bytecode", &output_bytecode, 1}
};
/* Table of language-specific options. */
......@@ -885,11 +892,14 @@ void
fatal_insn_not_found (insn)
rtx insn;
{
if (INSN_CODE (insn) < 0)
error ("internal error--unrecognizable insn:", 0);
else
error ("internal error--insn does not satisfy its constraints:", 0);
debug_rtx (insn);
if (!output_bytecode)
{
if (INSN_CODE (insn) < 0)
error ("internal error--unrecognizable insn:", 0);
else
error ("internal error--insn does not satisfy its constraints:", 0);
debug_rtx (insn);
}
if (asm_out_file)
fflush (asm_out_file);
if (aux_info_file)
......@@ -1585,6 +1595,8 @@ compile_file (name)
init_obstacks ();
init_tree_codes ();
init_lex ();
/* Some of these really don't need to be called when generating bytecode,
but the options would have to be parsed first to know that. -bson */
init_rtl ();
init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE);
......@@ -1813,34 +1825,51 @@ compile_file (name)
input_file_stack->next = 0;
input_file_stack->name = input_filename;
ASM_FILE_START (asm_out_file);
if (!output_bytecode)
{
ASM_FILE_START (asm_out_file);
}
/* Output something to inform GDB that this compilation was by GCC. */
/* Output something to inform GDB that this compilation was by GCC. Also
serves to tell GDB file consists of bytecodes. */
if (output_bytecode)
fprintf (asm_out_file, "bc_gcc2_compiled.:\n");
else
{
#ifndef ASM_IDENTIFY_GCC
fprintf (asm_out_file, "gcc2_compiled.:\n");
fprintf (asm_out_file, "gcc2_compiled.:\n");
#else
ASM_IDENTIFY_GCC (asm_out_file);
ASM_IDENTIFY_GCC (asm_out_file);
#endif
}
/* Output something to identify which front-end produced this file. */
#ifdef ASM_IDENTIFY_LANGUAGE
ASM_IDENTIFY_LANGUAGE (asm_out_file);
#endif
/* ??? Note: There used to be a conditional here
to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
This was to guarantee separation between gcc_compiled. and
the first function, for the sake of dbx on Suns.
However, having the extra zero here confused the Emacs
code for unexec, and might confuse other programs too.
Therefore, I took out that change.
In future versions we should find another way to solve
that dbx problem. -- rms, 23 May 93. */
/* Don't let the first function fall at the same address
as gcc_compiled., if profiling. */
if (profile_flag || profile_block_flag)
assemble_zeros (UNITS_PER_WORD);
if (output_bytecode)
{
if (profile_flag || profile_block_flag)
error ("profiling not supported in bytecode compilation");
}
else
{
/* ??? Note: There used to be a conditional here
to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
This was to guarantee separation between gcc_compiled. and
the first function, for the sake of dbx on Suns.
However, having the extra zero here confused the Emacs
code for unexec, and might confuse other programs too.
Therefore, I took out that change.
In future versions we should find another way to solve
that dbx problem. -- rms, 23 May 93. */
/* Don't let the first function fall at the same address
as gcc_compiled., if profiling. */
if (profile_flag || profile_block_flag)
assemble_zeros (UNITS_PER_WORD);
}
/* If dbx symbol table desired, initialize writing it
and output the predefined types. */
......@@ -1861,7 +1890,8 @@ compile_file (name)
/* Initialize yet another pass. */
init_final (main_input_filename);
if (!output_bytecode)
init_final (main_input_filename);
start_time = get_run_time ();
......@@ -2031,11 +2061,14 @@ compile_file (name)
/* Output some stuff at end of file if nec. */
end_final (main_input_filename);
if (!output_bytecode)
{
end_final (main_input_filename);
#ifdef ASM_FILE_END
ASM_FILE_END (asm_out_file);
ASM_FILE_END (asm_out_file);
#endif
}
after_finish_compilation:
......@@ -2113,24 +2146,28 @@ compile_file (name)
{
fprintf (stderr,"\n");
print_time ("parse", parse_time);
print_time ("integration", integration_time);
print_time ("jump", jump_time);
print_time ("cse", cse_time);
print_time ("loop", loop_time);
print_time ("cse2", cse2_time);
print_time ("flow", flow_time);
print_time ("combine", combine_time);
print_time ("sched", sched_time);
print_time ("local-alloc", local_alloc_time);
print_time ("global-alloc", global_alloc_time);
print_time ("sched2", sched2_time);
print_time ("dbranch", dbr_sched_time);
print_time ("shorten-branch", shorten_branch_time);
print_time ("stack-reg", stack_reg_time);
print_time ("final", final_time);
print_time ("varconst", varconst_time);
print_time ("symout", symout_time);
print_time ("dump", dump_time);
if (!output_bytecode)
{
print_time ("integration", integration_time);
print_time ("jump", jump_time);
print_time ("cse", cse_time);
print_time ("loop", loop_time);
print_time ("cse2", cse2_time);
print_time ("flow", flow_time);
print_time ("combine", combine_time);
print_time ("sched", sched_time);
print_time ("local-alloc", local_alloc_time);
print_time ("global-alloc", global_alloc_time);
print_time ("sched2", sched2_time);
print_time ("dbranch", dbr_sched_time);
print_time ("shorten-branch", shorten_branch_time);
print_time ("stack-reg", stack_reg_time);
print_time ("final", final_time);
print_time ("varconst", varconst_time);
print_time ("symout", symout_time);
print_time ("dump", dump_time);
}
}
}
......@@ -2236,6 +2273,9 @@ rest_of_compilation (decl)
tree saved_arguments = 0;
int failure = 0;
if (output_bytecode)
return;
/* If we are reconsidering an inline function
at the end of compilation, skip the stuff for making it inline. */
......@@ -3166,7 +3206,12 @@ main (argc, argv, envp)
error ("Invalid option `%s'", argv[i]);
}
else if (!strcmp (str, "p"))
profile_flag = 1;
{
if (!output_bytecode)
profile_flag = 1;
else
error ("profiling not supported in bytecode compilation");
}
else if (!strcmp (str, "a"))
{
#if !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER)
......@@ -3325,6 +3370,18 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
filename = argv[i];
}
/* Initialize for bytecode output. A good idea to do this as soon as
possible after the "-f" options have been parsed. */
if (output_bytecode)
{
#ifndef TARGET_SUPPORTS_BYTECODE
/* Just die with a fatal error if not supported */
fatal ("-fbytecode can not be used for this target");
#else
bc_initialize ();
#endif
}
if (optimize == 0)
{
/* Inlining does not work if not optimizing,
......@@ -3398,10 +3455,14 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
}
/* Now that register usage is specified, convert it to HARD_REG_SETs. */
init_reg_sets_1 ();
if (!output_bytecode)
init_reg_sets_1 ();
compile_file (filename);
if (output_bytecode)
bc_write_file (stdout);
#ifndef OS2
#ifndef VMS
if (flag_print_mem)
......
......@@ -38,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "regs.h"
#include "defaults.h"
#include "real.h"
#include "bytecode.h"
#include "obstack.h"
......@@ -96,9 +97,11 @@ void assemble_name ();
int output_addressed_constants ();
void output_constant ();
void output_constructor ();
void output_byte_asm ();
void text_section ();
void readonly_data_section ();
void data_section ();
static void bc_assemble_integer ();
#ifdef EXTRA_SECTIONS
static enum in_section {no_section, in_text, in_data, EXTRA_SECTIONS} in_section
......@@ -120,7 +123,11 @@ text_section ()
{
if (in_section != in_text)
{
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
if (output_bytecode)
bc_text ();
else
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
in_section = in_text;
}
}
......@@ -132,16 +139,21 @@ data_section ()
{
if (in_section != in_data)
{
if (flag_shared_data)
if (output_bytecode)
bc_data ();
else
{
if (flag_shared_data)
{
#ifdef SHARED_SECTION_ASM_OP
fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
#else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
#endif
}
else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
}
else
fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
in_section = in_data;
}
......@@ -178,6 +190,16 @@ make_function_rtl (decl)
{
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
if (output_bytecode)
{
if (DECL_RTL (decl) == 0)
DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
/* Record that at least one function has been defined. */
function_defined = 1;
return;
}
/* Rename a nested function to avoid conflicts. */
if (decl_function_context (decl) != 0
&& DECL_INITIAL (decl) != 0
......@@ -211,6 +233,48 @@ make_function_rtl (decl)
function_defined = 1;
}
/* Create the DECL_RTL for a declaration for a static or external
variable or static or external function.
ASMSPEC, if not 0, is the string which the user specified
as the assembler symbol name.
TOP_LEVEL is nonzero if this is a file-scope variable.
This is never called for PARM_DECLs. */
void
bc_make_decl_rtl (decl, asmspec, top_level)
tree decl;
char *asmspec;
int top_level;
{
register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));
if (DECL_RTL (decl) == 0)
{
/* Print an error message for register variables. */
if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
error ("function declared `register'");
else if (DECL_REGISTER (decl))
error ("global register variables not supported in the interpreter");
/* Handle ordinary static variables and functions. */
if (DECL_RTL (decl) == 0)
{
/* Can't use just the variable's own name for a variable
whose scope is less than the whole file.
Concatenate a distinguishing number. */
if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
{
char *label;
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
name = obstack_copy0 (saveable_obstack, label, strlen (label));
var_labelno++;
}
DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
}
}
}
/* Given NAME, a putative register name, discard any customary prefixes. */
static char *
......@@ -301,7 +365,15 @@ make_decl_rtl (decl, asmspec, top_level)
int top_level;
{
register char *name;
int reg_number = decode_reg_name (asmspec);
int reg_number;
if (output_bytecode)
{
bc_make_decl_rtl (decl, asmspec, top_level);
return;
}
reg_number = decode_reg_name (asmspec);
if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
......@@ -465,6 +537,12 @@ void
assemble_asm (string)
tree string;
{
if (output_bytecode)
{
error ("asm statements not allowed in interpreter");
return;
}
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
......@@ -576,7 +654,12 @@ assemble_start_function (decl, fnname)
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
{
if (output_bytecode)
BC_OUTPUT_ALIGN (asm_out_file, align);
else
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
......@@ -600,7 +683,10 @@ assemble_start_function (decl, fnname)
{
if (!first_global_object_name)
STRIP_NAME_ENCODING (first_global_object_name, fnname);
ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
if (output_bytecode)
BC_GLOBALIZE_LABEL (asm_out_file, fnname);
else
ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
}
/* Do any machine/system dependent processing of the function name */
......@@ -608,7 +694,10 @@ assemble_start_function (decl, fnname)
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else
/* Standard thing is just output label for the function. */
ASM_OUTPUT_LABEL (asm_out_file, fnname);
if (output_bytecode)
BC_OUTPUT_LABEL (asm_out_file, fnname);
else
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
}
......@@ -631,6 +720,12 @@ void
assemble_zeros (size)
int size;
{
if (output_bytecode)
{
bc_emit_const_skip (size);
return;
}
#ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */
......@@ -664,7 +759,12 @@ assemble_zeros (size)
else
#endif
if (size > 0)
ASM_OUTPUT_SKIP (asm_out_file, size);
{
if (output_bytecode)
BC_OUTPUT_SKIP (asm_out_file, size);
else
ASM_OUTPUT_SKIP (asm_out_file, size);
}
}
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
......@@ -688,6 +788,12 @@ assemble_string (p, size)
int pos = 0;
int maximum = 2000;
if (output_bytecode)
{
bc_emit (p, size);
return;
}
/* If the string is very long, split it up. */
while (pos < size)
......@@ -696,7 +802,10 @@ assemble_string (p, size)
if (thissize > maximum)
thissize = maximum;
ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
if (output_bytecode)
BC_OUTPUT_ASCII (asm_out_file, p, thissize);
else
ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
pos += thissize;
p += thissize;
......@@ -725,6 +834,9 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
int reloc = 0;
enum in_section saved_in_section;
if (output_bytecode)
return;
if (GET_CODE (DECL_RTL (decl)) == REG)
{
/* Do output symbol info for global register variables, but do nothing
......@@ -734,19 +846,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
return;
TREE_ASM_WRITTEN (decl) = 1;
if (!output_bytecode)
{
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
/* File-scope global variables are output here. */
if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
&& top_level)
dbxout_symbol (decl, 0);
/* File-scope global variables are output here. */
if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
&& top_level)
dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && top_level
/* Leave initialized global vars for end of compilation;
see comment in compile_file. */
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0);
if (write_symbols == SDB_DEBUG && top_level
/* Leave initialized global vars for end of compilation;
see comment in compile_file. */
&& (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
sdbout_symbol (decl, 0);
#endif
}
/* Don't output any DWARF debugging information for variables here.
In the case of local variables, the information for them is output
......@@ -880,12 +995,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
else
#endif
if (output_bytecode)
BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
else
{
#ifdef ASM_OUTPUT_ALIGNED_COMMON
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
DECL_ALIGN (decl));
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
#endif
}
}
else
{
......@@ -894,12 +1014,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
if (output_bytecode)
BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
else
{
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
DECL_ALIGN (decl));
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
}
}
goto finish;
}
......@@ -1017,14 +1142,22 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
DECL_ALIGN (decl) = align;
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
{
if (output_bytecode)
BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
else
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
#else
/* Standard thing is just output label for the object. */
ASM_OUTPUT_LABEL (asm_out_file, name);
if (output_bytecode)
BC_OUTPUT_LABEL (asm_out_file, name);
else
ASM_OUTPUT_LABEL (asm_out_file, name);
#endif /* ASM_DECLARE_OBJECT_NAME */
if (!dont_output_data)
......@@ -1110,6 +1243,55 @@ contains_pointers_p (type)
}
}
/* Output text storage for constructor CONSTR. Returns rtx of
storage. */
rtx
bc_output_constructor (constr)
tree constr;
{
int i;
/* Must always be a literal; non-literal constructors are handled
differently. */
if (!TREE_CONSTANT (constr))
abort ();
/* Always const */
text_section ();
/* Align */
for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
if (i > 0)
BC_OUTPUT_ALIGN (asm_out_file, i);
/* Output data */
output_constant (constr, int_size_in_bytes (TREE_TYPE (constr)));
}
/* Create storage for constructor CONSTR. */
void
bc_output_data_constructor (constr)
tree constr;
{
int i;
/* Put in data section */
data_section ();
/* Align */
for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
if (i > 0)
BC_OUTPUT_ALIGN (asm_out_file, i);
/* The constructor is filled in at runtime. */
BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
}
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */
......@@ -1118,6 +1300,9 @@ void
assemble_external (decl)
tree decl;
{
if (output_bytecode)
return;
#ifdef ASM_OUTPUT_EXTERNAL
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
&& DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
......@@ -1142,11 +1327,14 @@ assemble_external_libcall (fun)
rtx fun;
{
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
/* Declare library function name external when first used, if nec. */
if (! SYMBOL_REF_USED (fun))
if (!output_bytecode)
{
SYMBOL_REF_USED (fun) = 1;
ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
/* Declare library function name external when first used, if nec. */
if (! SYMBOL_REF_USED (fun))
{
SYMBOL_REF_USED (fun) = 1;
ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
}
}
#endif
}
......@@ -1166,7 +1354,10 @@ void
assemble_label (name)
char *name;
{
ASM_OUTPUT_LABEL (asm_out_file, name);
if (output_bytecode)
BC_OUTPUT_LABEL (asm_out_file, name);
else
ASM_OUTPUT_LABEL (asm_out_file, name);
}
/* Output to FILE a reference to the assembler name of a C-level name NAME.
......@@ -1181,9 +1372,19 @@ assemble_name (file, name)
char *name;
{
if (name[0] == '*')
fputs (&name[1], file);
{
if (output_bytecode)
bc_emit_labelref (name);
else
fputs (&name[1], file);
}
else
ASM_OUTPUT_LABELREF (file, name);
{
if (output_bytecode)
BC_OUTPUT_LABELREF (file, name);
else
ASM_OUTPUT_LABELREF (file, name);
}
}
/* Allocate SIZE bytes writable static space with a gensym name
......@@ -1214,12 +1415,21 @@ assemble_static_space (size)
strlen (name) + 2);
strcpy (namestring, name);
x = gen_rtx (SYMBOL_REF, Pmode, namestring);
if (output_bytecode)
x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0);
else
x = gen_rtx (SYMBOL_REF, Pmode, namestring);
if (output_bytecode)
BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
else
{
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
}
return x;
}
......@@ -1234,6 +1444,10 @@ assemble_trampoline_template ()
char *name;
int align;
/* Shouldn't get here */
if (output_bytecode)
abort ();
/* By default, put trampoline templates in read-only data section. */
#ifdef TRAMPOLINE_SECTION
......@@ -1683,9 +1897,13 @@ decode_addr_const (exp, value)
break;
case LABEL_DECL:
x = gen_rtx (MEM, FUNCTION_MODE,
gen_rtx (LABEL_REF, VOIDmode,
label_rtx (TREE_OPERAND (exp, 0))));
if (output_bytecode)
/* FIXME: this may not be correct, check it */
x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0);
else
x = gen_rtx (MEM, FUNCTION_MODE,
gen_rtx (LABEL_REF, VOIDmode,
label_rtx (TREE_OPERAND (exp, 0))));
break;
case REAL_CST:
......@@ -1699,9 +1917,12 @@ decode_addr_const (exp, value)
abort ();
}
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
if (!output_bytecode)
{
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
}
value->base = x;
value->offset = offset;
......@@ -2171,47 +2392,57 @@ output_constant_def (exp)
to see if any of them describes EXP. If yes, the descriptor records
the label number already assigned. */
hash = const_hash (exp) % MAX_HASH_TABLE;
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
{
found = desc->label;
break;
}
if (found == 0)
if (!output_bytecode)
{
/* No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
Assign the label number and record it in the descriptor for
future calls to this function to find. */
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
desc = record_constant (exp);
desc->next = const_hash_table[hash];
desc->label
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
const_hash_table[hash] = desc;
hash = const_hash (exp) % MAX_HASH_TABLE;
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
{
found = desc->label;
break;
}
if (found == 0)
{
/* No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
Assign the label number and record it in the descriptor for
future calls to this function to find. */
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
desc = record_constant (exp);
desc->next = const_hash_table[hash];
desc->label
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
const_hash_table[hash] = desc;
}
else
{
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
}
}
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
push_obstacks_nochange ();
if (TREE_PERMANENT (exp))
end_temporary_allocation ();
def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
TREE_CST_RTL (exp)
= gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
if (!output_bytecode)
{
def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
TREE_CST_RTL (exp)
= gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
|| TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
}
pop_obstacks ();
/* Optionally set flags or add text to the name to record information
......@@ -2283,7 +2514,12 @@ output_constant_def_contents (exp, reloc, labelno)
#endif
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
{
if (!output_bytecode)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
else
BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
}
/* Output the label itself. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
......@@ -2891,6 +3127,22 @@ output_addressed_constants (exp)
}
return reloc;
}
/* Output assembler for byte constant */
void
output_byte_asm (byte)
int byte;
{
if (output_bytecode)
bc_emit_const ((char *) &byte, sizeof (char));
#ifdef ASM_OUTPUT_BYTE
else
{
ASM_OUTPUT_BYTE (asm_out_file, byte);
}
#endif
}
/* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
......@@ -2925,7 +3177,10 @@ output_constant (exp, size)
This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
{
assemble_zeros (size);
if (output_bytecode)
bc_emit_const_skip (size);
else
assemble_zeros (size);
return;
}
......@@ -3005,6 +3260,101 @@ output_constant (exp, size)
if (size > 0)
assemble_zeros (size);
}
/* Bytecode specific code to output assembler for integer. */
void
bc_assemble_integer (exp, size)
tree exp;
int size;
{
tree const_part;
tree addr_part;
tree tmp;
/* FIXME: is this fold() business going to be as good as the
expand_expr() using EXPAND_SUM above in the RTL case? I
hate RMS.
FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
exp = fold (exp);
while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) == INTEGER_CST)
{
const_part = exp;
addr_part = 0;
}
else if (TREE_CODE (exp) == PLUS_EXPR)
{
const_part = TREE_OPERAND (exp, 0);
while (TREE_CODE (const_part) == NOP_EXPR
|| TREE_CODE (const_part) == CONVERT_EXPR)
const_part = TREE_OPERAND (const_part, 0);
addr_part = TREE_OPERAND (exp, 1);
while (TREE_CODE (addr_part) == NOP_EXPR
|| TREE_CODE (addr_part) == CONVERT_EXPR)
addr_part = TREE_OPERAND (addr_part, 0);
if (TREE_CODE (const_part) != INTEGER_CST)
tmp = const_part, const_part = addr_part, addr_part = tmp;
if (TREE_CODE (const_part) != INTEGER_CST
|| TREE_CODE (addr_part) != ADDR_EXPR)
abort (); /* FIXME: we really haven't considered
all the possible cases here. */
}
else if (TREE_CODE (exp) == ADDR_EXPR)
{
const_part = integer_zero_node;
addr_part = exp;
}
else
abort (); /* FIXME: ditto previous. */
if (addr_part == 0)
{
if (size == 1)
{
char c = TREE_INT_CST_LOW (const_part);
bc_emit (&c, 1);
size -= 1;
}
else if (size == 2)
{
short s = TREE_INT_CST_LOW (const_part);
bc_emit ((char *) &s, 2);
size -= 2;
}
else if (size == 4)
{
int i = TREE_INT_CST_LOW (const_part);
bc_emit ((char *) &i, 4);
size -= 4;
}
else if (size == 8)
{
#if WORDS_BIG_ENDIAN
int i = TREE_INT_CST_HIGH (const_part);
bc_emit ((char *) &i, 4);
i = TREE_INT_CST_LOW (const_part);
bc_emit ((char *) &i, 4);
#else
int i = TREE_INT_CST_LOW (const_part);
bc_emit ((char *) &i, 4);
i = TREE_INT_CST_HIGH (const_part);
bc_emit ((char *) &i, 4);
#endif
size -= 8;
}
}
else
if (size == 4
&& TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
bc_emit_labelref (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0)),
TREE_INT_CST_LOW (const_part));
else
abort (); /* FIXME: there may be more cases. */
}
/* Subroutine of output_constant, used for CONSTRUCTORs
(aggregate constants).
......@@ -3083,7 +3433,10 @@ output_constructor (exp, size)
if each element has the proper size. */
if ((field != 0 || index != 0) && bitpos != total_bytes)
{
assemble_zeros (bitpos - total_bytes);
if (!output_bytecode)
assemble_zeros (bitpos - total_bytes);
else
bc_emit_const_skip (bitpos - total_bytes);
total_bytes = bitpos;
}
......@@ -3254,3 +3607,42 @@ output_constructor (exp, size)
if (total_bytes < size)
assemble_zeros (size - total_bytes);
}
/* Output asm to handle ``#pragma weak'' */
void
handle_pragma_weak (what, asm_out_file, name, value)
enum pragma_state what;
FILE *asm_out_file;
char *name, *value;
{
if (what == ps_name || what == ps_value)
{
fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
if (output_bytecode)
BC_OUTPUT_LABELREF (asm_out_file, name);
else
ASM_OUTPUT_LABELREF (asm_out_file, name);
fputc ('\n', asm_out_file);
if (what == ps_value)
{
fprintf (asm_out_file, "\t%s\t", SET_ASM_OP);
if (output_bytecode)
BC_OUTPUT_LABELREF (asm_out_file, name);
else
ASM_OUTPUT_LABELREF (asm_out_file, name);
fputc (',', asm_out_file);
if (output_bytecode)
BC_OUTPUT_LABELREF (asm_out_file, value);
else
ASM_OUTPUT_LABELREF (asm_out_file, value);
fputc ('\n', asm_out_file);
}
}
else if (! (what == ps_done || what == ps_start))
warning ("malformed `#pragma weak'");
}
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