Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
ca695ac9
Commit
ca695ac9
authored
Sep 21, 1993
by
Jan Brittenson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bytecode
From-SVN: r5379
parent
86d7f2db
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1631 additions
and
201 deletions
+1631
-201
gcc/Makefile.in
+72
-11
gcc/c-pragma.c
+4
-32
gcc/emit-rtl.c
+39
-2
gcc/expr.c
+0
-0
gcc/integrate.c
+9
-1
gcc/regclass.c
+8
-0
gcc/rtl.h
+17
-0
gcc/stmt.c
+902
-28
gcc/toplev.c
+107
-46
gcc/varasm.c
+473
-81
No files found.
gcc/Makefile.in
View file @
ca695ac9
...
...
@@ -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
...
...
gcc/c-pragma.c
View file @
ca695ac9
...
...
@@ -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 */
}
...
...
gcc/emit-rtl.c
View file @
ca695ac9
...
...
@@ -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
;
...
...
gcc/expr.c
View file @
ca695ac9
This source diff could not be displayed because it is too large. You can
view the blob
instead.
gcc/integrate.c
View file @
ca695ac9
...
...
@@ -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. */
...
...
gcc/regclass.c
View file @
ca695ac9
...
...
@@ -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. */
...
...
gcc/rtl.h
View file @
ca695ac9
...
...
@@ -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
...
...
gcc/stmt.c
View file @
ca695ac9
...
...
@@ -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
();
t
ree
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
...
...
gcc/toplev.c
View file @
ca695ac9
...
...
@@ -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
)
...
...
gcc/varasm.c
View file @
ca695ac9
...
...
@@ -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'"
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment