From b93a436e6b93d31a9523e4b058edc2f1d5d8dc66 Mon Sep 17 00:00:00 2001 From: Jeffrey A Law Date: Tue, 20 Jan 1998 08:55:07 +0000 Subject: [PATCH] Makefile.in: Remove all bytecode support. * Makefile.in: Remove all bytecode support. (OBJS): Make sure last entry is a real object file, not EXTRA_OBJS. * emit-rtl.c: Remove all bytecode support. * expr.c, expr.h function.c, integrate.c: Likewise. * output.h, regclass.c, rtl.h, stmt.c, toplev.c: Likewise. * tree.h, varasm.c: Likewise. * bi-*, bc-*: Delete bytecode related files. Bytecode suppors disappears :-) From-SVN: r17432 --- gcc/ChangeLog | 11 + gcc/Makefile.in | 116 +- gcc/bc-emit.c | 1018 ------- gcc/bc-emit.h | 133 - gcc/bc-optab.c | 810 ------ gcc/bc-optab.h | 75 - gcc/bc-typecd.def | 21 - gcc/bc-typecd.h | 54 - gcc/bi-arity.c | 91 - gcc/bi-defs.h | 48 - gcc/bi-lexer.c | 167 -- gcc/bi-opcode.c | 89 - gcc/bi-opname.c | 70 - gcc/bi-parser.c | 980 ------- gcc/bi-parser.h | 12 - gcc/bi-parser.y | 169 -- gcc/bi-reverse.c | 61 - gcc/bi-run.h | 159 - gcc/emit-rtl.c | 30 +- gcc/expr.c | 7111 ++++++++++++++++++--------------------------- gcc/expr.h | 12 - gcc/function.c | 168 +- gcc/integrate.c | 7 - gcc/output.h | 25 +- gcc/regclass.c | 11 +- gcc/rtl.h | 16 - gcc/stmt.c | 942 +----- gcc/toplev.c | 160 +- gcc/tree.h | 4 - gcc/varasm.c | 467 +-- 30 files changed, 3081 insertions(+), 9956 deletions(-) delete mode 100644 gcc/bc-emit.c delete mode 100644 gcc/bc-emit.h delete mode 100644 gcc/bc-optab.c delete mode 100644 gcc/bc-optab.h delete mode 100644 gcc/bc-typecd.def delete mode 100644 gcc/bc-typecd.h delete mode 100644 gcc/bi-arity.c delete mode 100644 gcc/bi-defs.h delete mode 100644 gcc/bi-lexer.c delete mode 100644 gcc/bi-opcode.c delete mode 100644 gcc/bi-opname.c delete mode 100644 gcc/bi-parser.c delete mode 100644 gcc/bi-parser.h delete mode 100644 gcc/bi-parser.y delete mode 100644 gcc/bi-reverse.c delete mode 100644 gcc/bi-run.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dbdfde6bd98..fb97c92e72a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +Tue Jan 20 09:29:09 1998 Jeffrey A Law (law@cygnus.com) + + * Makefile.in: Remove all bytecode support. + (OBJS): Make sure last entry is a real object file, not EXTRA_OBJS. + * emit-rtl.c: Remove all bytecode support. + * expr.c, expr.h function.c, integrate.c: Likewise. + * output.h, regclass.c, rtl.h, stmt.c, toplev.c: Likewise. + * tree.h, varasm.c: Likewise. + * bi-*, bc-*: Delete bytecode related files. + + Tue Jan 20 09:02:31 1998 Gavin Koch (gavin@cygnus.com) * mips/mips.md (divsi3,divdi3,modsi3,moddi3,udivsi3,udivdi3, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 344def6fe53..71328aa97b7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -579,12 +579,6 @@ C_AND_OBJC_OBJS = c-lex.o c-pragma.o c-decl.o c-typeck.o c-convert.o \ # Language-specific object files for C. C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS) -# Files specific to the C interpreter bytecode compiler(s). -BC_OBJS = bc-emit.o bc-optab.o - -# Bytecode header files constructed at build time; vmsconfig.com wants this. -BC_ALL = bc-arity.h bc-opcode.h bc-opname.h - SCHED_PREFIX = @sched_prefix@ SCHED_CFLAGS = @sched_cflags@ @@ -597,7 +591,7 @@ OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ regclass.o local-alloc.o global.o reload.o reload1.o caller-save.o \ insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \ - profile.o insn-attrtab.o $(out_object_file) getpwd.o convert.o $(EXTRA_OBJS) + profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load @@ -620,7 +614,6 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \ genextract$(build_exeext) genflags$(build_exeext) gencodes$(build_exeext) \ genconfig$(build_exeext) genpeep$(build_exeext) genattrtab$(build_exeext) \ genattr$(build_exeext) genopinit$(build_exeext) \ - $(BC_ALL) \ stamp-bcarity stamp-bcopcode stamp-bcopname \ bi-arity$(build_exeext) bi-opcode$(build_exeext) bi-opname$(build_exeext) \ xgcc$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES) \ @@ -675,7 +668,6 @@ CONFIG_H = RTL_BASE_H = rtl.h rtl.def gansidecl.h machmode.h machmode.def RTL_H = $(RTL_BASE_H) genrtl.h TREE_H = tree.h real.h tree.def gansidecl.h machmode.h machmode.def -BYTECODE_H = bytecode.h bc-emit.h bc-optab.h BASIC_BLOCK_H = basic-block.h bitmap.h DEMANGLE_H = demangle.h gansidecl.h RECOG_H = recog.h gansidecl.h @@ -789,8 +781,8 @@ compilations: ${OBJS} # Create a list of the language-independent object files so the language # subdirectories needn't mention their names explicitly. -stamp-objlist: $(OBJS) $(BC_OBJS) - echo " $(OBJS) $(BC_OBJS)" | sed -e 's, \([a-z0-9]\), ../\1,g' -e 's/\.o/$(objext)/g' >stamp-objlist +stamp-objlist: $(OBJS) + echo " $(OBJS)" | sed -e 's, \([a-z0-9]\), ../\1,g' -e 's/\.o/$(objext)/g' >stamp-objlist # We call this executable `xgcc' rather than `gcc' # to avoid confusion if the current directory is in the path @@ -811,8 +803,8 @@ specs: xgcc gcc-cross: xgcc cp xgcc$(exeext) gcc-cross$(exeext) -cc1: $(P) $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBS) +cc1: $(P) $(C_OBJS) $(OBJS) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) $(OBJS) $(LIBS) # Copy float.h from its source. gfloat.h: $(FLOAT_H) @@ -1324,7 +1316,7 @@ tree.o : tree.c $(CONFIG_H) $(TREE_H) flags.h function.h print-tree.o : print-tree.c $(CONFIG_H) $(TREE_H) stor-layout.o : stor-layout.c $(CONFIG_H) $(TREE_H) flags.h function.h fold-const.o : fold-const.c $(CONFIG_H) $(TREE_H) flags.h -toplev.o : toplev.c $(CONFIG_H) $(TREE_H) $(RTL_H) bytecode.h bc-emit.h \ +toplev.o : toplev.c $(CONFIG_H) $(TREE_H) $(RTL_H) \ flags.h input.h insn-attr.h xcoffout.h defaults.h output.h \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ @@ -1338,21 +1330,19 @@ rtlanal.o : rtlanal.c $(CONFIG_H) $(RTL_H) varasm.o : varasm.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h function.h \ defaults.h insn-codes.h expr.h hard-reg-set.h regs.h xcoffout.h \ - output.h bytecode.h c-pragma.h + output.h c-pragma.h function.o : function.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h \ insn-flags.h insn-codes.h expr.h regs.h hard-reg-set.h insn-config.h \ - $(RECOG_H) output.h bytecode.h bc-emit.h + $(RECOG_H) output.h stmt.o : stmt.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h \ insn-flags.h insn-config.h insn-codes.h hard-reg-set.h expr.h except.h \ - loop.h $(RECOG_H) bytecode.h bc-typecd.h bc-typecd.def bc-opcode.h \ - bc-optab.h bc-emit.h + loop.h $(RECOG_H) except.o : except.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h \ insn-flags.h insn-codes.h expr.h regs.h hard-reg-set.h insn-config.h \ $(RECOG_H) output.h except.h expr.o : expr.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h regs.h \ insn-flags.h insn-codes.h expr.h insn-config.h $(RECOG_H) output.h \ - typeclass.h bytecode.h bc-opcode.h bc-typecd.h bc-typecd.def bc-optab.h \ - bc-emit.h modemap.def hard-reg-set.h + typeclass.h modemap.def hard-reg-set.h calls.o : calls.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h expr.h insn-codes.h \ insn-flags.h regs.h expmed.o : expmed.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \ @@ -1365,22 +1355,20 @@ dbxout.o : dbxout.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h regs.h \ insn-config.h reload.h gstab.h xcoffout.h defaults.h output.h sdbout.o : sdbout.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h except.h \ function.h expr.h output.h hard-reg-set.h regs.h defaults.h real.h \ - insn-config.h bytecode.h obstack.h xcoffout.h c-pragma.h + insn-config.h obstack.h xcoffout.h c-pragma.h dwarfout.o : dwarfout.c $(CONFIG_H) $(TREE_H) $(RTL_H) dwarf.h flags.h \ insn-config.h reload.h output.h defaults.h dwarf2out.o : dwarf2out.c $(CONFIG_H) $(TREE_H) $(RTL_H) dwarf2.h flags.h \ insn-config.h reload.h output.h defaults.h hard-reg-set.h regs.h expr.h xcoffout.o : xcoffout.c $(CONFIG_H) $(TREE_H) $(RTL_H) xcoffout.h flags.h emit-rtl.o : emit-rtl.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h except.h \ - function.h regs.h insn-config.h $(RECOG_H) real.h expr.h obstack.h \ - bytecode.h bc-opcode.h bc-typecd.h bc-typecd.def bc-optab.h bc-emit.h \ - bc-opname.h + function.h regs.h insn-config.h $(RECOG_H) real.h expr.h obstack.h real.o : real.c $(CONFIG_H) $(TREE_H) getpwd.o : getpwd.c $(CONFIG_H) integrate.o : integrate.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h integrate.h \ insn-flags.h insn-config.h insn-codes.h expr.h real.h regs.h function.h \ - bytecode.h output.h $(RECOG_H) except.h + output.h $(RECOG_H) except.h jump.o : jump.c $(CONFIG_H) $(RTL_H) flags.h hard-reg-set.h regs.h \ insn-config.h insn-flags.h $(RECOG_H) expr.h real.h except.h @@ -1400,7 +1388,7 @@ combine.o : combine.c $(CONFIG_H) $(RTL_H) flags.h \ insn-config.h insn-flags.h insn-codes.h insn-attr.h regs.h expr.h \ $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h regclass.o : regclass.c $(CONFIG_H) $(RTL_H) hard-reg-set.h flags.h \ - $(BASIC_BLOCK_H) regs.h insn-config.h $(RECOG_H) reload.h real.h bytecode.h + $(BASIC_BLOCK_H) regs.h insn-config.h $(RECOG_H) reload.h real.h local-alloc.o : local-alloc.c $(CONFIG_H) $(RTL_H) flags.h $(BASIC_BLOCK_H) \ regs.h hard-reg-set.h insn-config.h $(RECOG_H) output.h bitmap.o : bitmap.c $(CONFIG_H) $(RTL_H) flags.h $(BASIC_BLOCK_H) regs.h @@ -1735,74 +1723,6 @@ $(HOST_PREFIX_1)malloc.o: malloc.c # that does not need to compile alloca, malloc or whatever. $(HOST_PREFIX_1): touch $(HOST_PREFIX_1) -# -# Remake bytecode files. -BI_OBJ=bi-parser.o bi-lexer.o bi-reverse.o - -bc-emit.o : bc-emit.c $(CONFIG_H) $(RTL_H) real.h $(BYTECODE_H) \ - bc-arity.h bc-opcode.h bc-typecd.h bc-typecd.def bi-run.h bytetypes.h -bc-optab.o : bc-optab.c $(CONFIG_H) $(REAL_H) $(BYTECODE_H) \ - bc-opcode.h bc-typecd.h bc-typecd.def - -bi-arity: bi-arity.o $(BI_OBJ) $(HOST_LIBDEPS) - $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - bi-arity.o $(BI_OBJ) $(HOST_LIBS) -bi-opcode: bi-opcode.o $(BI_OBJ) $(HOST_LIBDEPS) - $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - bi-opcode.o $(BI_OBJ) $(HOST_LIBS) -bi-opname: bi-opname.o $(BI_OBJ) $(HOST_LIBDEPS) - $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - bi-opname.o $(BI_OBJ) $(HOST_LIBS) - -$(srcdir)/bi-parser.h: $(srcdir)/bi-parser.c -$(srcdir)/bi-parser.c: $(srcdir)/bi-parser.y - cd $(srcdir); $(BISON) $(BISONFLAGS) -d bi-parser.y -o bi-parser.c - -bi-parser.o: $(srcdir)/bi-parser.c bi-defs.h $(build_xm_file) - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-parser.c -bi-lexer.o: bi-lexer.c $(srcdir)/bi-parser.h $(build_xm_file) - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-lexer.c -bi-arity.o: bi-arity.c bi-defs.h $(build_xm_file) - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-arity.c -bi-opcode.o: bi-opcode.c bi-defs.h $(build_xm_file) - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-opcode.c -bi-opname.o: bi-opname.c bi-defs.h $(build_xm_file) - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-opname.c -bi-reverse.o: bi-reverse.c bi-defs.h - $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/bi-reverse.c - -bc-arity.h: stamp-bcarity ; @true -stamp-bcarity : $(srcdir)/bytecode.def bi-arity $(srcdir)/move-if-change - ./bi-arity < $(srcdir)/bytecode.def >tmp-bc-arity.h - $(srcdir)/move-if-change tmp-bc-arity.h bc-arity.h - touch stamp-bcarity - -bc-opcode.h: stamp-bcopcode ; @true -stamp-bcopcode : $(srcdir)/bytecode.def bi-opcode $(srcdir)/move-if-change - ./bi-opcode < $(srcdir)/bytecode.def >tmp-bcopcd.h - $(srcdir)/move-if-change tmp-bcopcd.h bc-opcode.h - touch stamp-bcopcode - -bc-opname.h: stamp-bcopname ; @true -stamp-bcopname : $(srcdir)/bytecode.def bi-opname $(srcdir)/move-if-change - ./bi-opname < $(srcdir)/bytecode.def >tmp-bcopnm.h - $(srcdir)/move-if-change tmp-bcopnm.h bc-opname.h - touch stamp-bcopname - -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-lexer - -bytecode.maintainer-clean: bytecode.clean - -rm -f bi-parser.c bi-parser.h # # Remake cpp and protoize. @@ -2112,7 +2032,7 @@ INSTALL: $(srcdir)/install1.texi $(srcdir)/install.texi # (less duplicated code). -mostlyclean: bytecode.mostlyclean lang.mostlyclean +mostlyclean: lang.mostlyclean -rm -f $(STAGESTUFF) # Delete the temporary source copies for cross compilation. -rm -f $(HOST_PREFIX_1)rtl.c $(HOST_PREFIX_1)rtlanal.c @@ -2153,7 +2073,7 @@ mostlyclean: bytecode.mostlyclean lang.mostlyclean # Delete all files made by compilation # that don't exist in the distribution. -clean: mostlyclean bytecode.clean lang.clean +clean: mostlyclean lang.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, @@ -2179,7 +2099,7 @@ clean: mostlyclean bytecode.clean lang.clean # Delete all files that users would normally create # while building and installing GCC. -distclean: clean bytecode.distclean lang.distclean +distclean: clean lang.distclean -rm -f tm.h config.h auto-config.h tconfig.h hconfig.h md cstamp-h -rm -f config.status config.run config.cache config.bak -rm -f Make-lang Make-hooks Make-host Make-target @@ -2214,7 +2134,7 @@ extraclean: distclean lang.extraclean maintainer-clean: @echo 'This command is intended for maintainers to use; it' @echo 'deletes files that may need special tools to rebuild.' - $(MAKE) distclean bytecode.maintainer-clean lang.maintainer-clean + $(MAKE) distclean lang.maintainer-clean -rm -f c-parse.y c-gperf.h -rm -f c-parse.c c-parse.h c-parse.output -rm -f cexp.c cexp.output TAGS diff --git a/gcc/bc-emit.c b/gcc/bc-emit.c deleted file mode 100644 index c93195df9e1..00000000000 --- a/gcc/bc-emit.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* Output bytecodes for GNU C-compiler. - Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -#include "config.h" -#ifdef __STDC__ -#include -#else -#include -#endif -#include "machmode.h" -#include "rtl.h" -#include "real.h" -#include "obstack.h" -#include "bytecode.h" -#ifdef __GNUC__ -#include "bytetypes.h" -#endif -#include "bc-emit.h" -#include "bc-opcode.h" -#include "bc-typecd.h" -#include "bi-run.h" - -#include - -extern char *xmalloc (), *xrealloc (); - -extern struct obstack *rtl_obstack; - -/* Indexed by mode class, gives the narrowest mode for each class. */ - -extern enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS]; - -/* Commonly used modes. */ -/* Mode whose width is BITS_PER_UNIT */ -extern enum machine_mode byte_mode; - -/* Mode whose width is BITS_PER_WORD */ -extern enum machine_mode word_mode; - -/* Vector indexed by opcode giving info about the args for each opcode. */ -static struct arityvec arityvec[] = { -#include "bc-arity.h" -}; - -/* How to print a symbol name for the assembler. */ - -static void -prsym (file, s) - FILE *file; - char *s; -{ - if (*s == '*') - fprintf (file, "%s", s + 1); - else - -#ifdef NAMES_HAVE_UNDERSCORES - fprintf (file, "_%s", s); -#else - fprintf (file, "%s", s); -#endif - -} - -/* Maintain a bucket hash table for symbol names. */ - -#define HASH_BITS 32 -#define HASH_SIZE 509 - -static struct bc_sym *hashtab[HASH_SIZE]; - -static unsigned int -hash (name) - char *name; -{ - unsigned int hash = 0; - - while (*name) - { - hash = hash << 3 | hash >> HASH_BITS - 3; - hash += *name++; - } - - return hash % HASH_SIZE; -} - - -/* Look up the named symbol, creating it if it doesn't exist. */ - -struct bc_sym * -sym_lookup (name) - char *name; -{ - int i; - struct bc_sym *s; - - i = hash (name); - for (s = hashtab[i]; s; s = s->next) - if (!strcmp (s->name, name)) - return s; - - s = (struct bc_sym *) xmalloc (sizeof (struct bc_sym)); - s->name = xmalloc (strlen (name) + 1); - strcpy (s->name, name); - s->defined = s->global = s->common = 0; - s->val = 0; - s->next = hashtab[i]; - hashtab[i] = s; - return s; -} - - -/* Write out .globl and common symbols to the named file. */ - -static void -bc_sym_write (file) - FILE *file; -{ - int i; - struct bc_sym *s; - - for (i = 0; i < HASH_SIZE; ++i) - for (s = hashtab[i]; s; s = s->next) - { - if (s->global) - { - fprintf (file, "\n\t.globl "); - prsym (file, s->name); - putc ('\n', file); - if (s->common) - { - fprintf (file, "\n\t.comm "); - prsym (file, s->name); - fprintf (file, ", %lu\n", s->val); - } - } - else if (s->common) - { - fprintf (file, "\n\t.lcomm "); - prsym (file, s->name); - fprintf (file, ", %lu\n", s->val); - } - } -} - - - - -/* Create and initialize a new segment. */ - -static struct bc_seg * -seg_create () -{ - struct bc_seg *result; - - result = (struct bc_seg *) xmalloc (sizeof (struct bc_seg)); - result->alloc = 256; - result->data = xmalloc (result->alloc); - result->size = 0; - result->syms = 0; - result->relocs = 0; - return result; -} - - -/* Advance the segment index to the next alignment boundary. */ - -static void -seg_align (seg, log) - struct bc_seg *seg; - int log; -{ - unsigned int oldsize = seg->size; - - seg->size = seg->size + (1 << log) - 1 & ~((1 << log) - 1); - if (seg->size > seg->alloc) - { - while (seg->size > seg->alloc) - seg->alloc *= 2; - seg->data = xrealloc (seg->data, seg->alloc); - } - bzero (seg->data + oldsize, seg->size - oldsize); -} - - -/* Append the given data to the given segment. */ - -static void -seg_data (seg, data, size) - struct bc_seg *seg; - char *data; - unsigned int size; -{ - if (seg->size + size > seg->alloc) - { - while (seg->size + size > seg->alloc) - seg->alloc *= 2; - seg->data = xrealloc (seg->data, seg->alloc); - } - - bcopy (data, seg->data + seg->size, size); - seg->size += size; -} - - -/* Append a zero-filled skip to the given segment. */ - -static void -seg_skip (seg, size) - struct bc_seg *seg; - unsigned int size; -{ - if (seg->size + size > seg->alloc) - { - while (seg->size + size > seg->alloc) - seg->alloc *= 2; - seg->data = xrealloc (seg->data, seg->alloc); - } - - memset (seg->data + seg->size, 0, size); - seg->size += size; -} - - -/* Define the given name as the current offset in the given segment. It - is an error if the name is already defined. Return 0 or 1 indicating - failure or success respectively. */ - -static int -seg_defsym (seg, name) - struct bc_seg *seg; - char *name; -{ - struct bc_sym *sym; - struct bc_segsym *segsym; - - sym = sym_lookup (name); - if (sym->defined) - return 0; - - sym->defined = 1; - sym->val = seg->size; - segsym = (struct bc_segsym *) xmalloc (sizeof (struct bc_segsym)); - segsym->sym = sym; - segsym->next = seg->syms; - seg->syms = segsym; - return 1; -} - - -/* Generate in seg's data a reference to the given sym, adjusted by - the given offset. */ - -static void -seg_refsym (seg, name, offset) - struct bc_seg *seg; - char *name; - int offset; -{ - struct bc_sym *sym; - struct bc_segreloc *segreloc; - - sym = sym_lookup (name); - segreloc = (struct bc_segreloc *) xmalloc (sizeof (struct bc_segreloc)); - segreloc->offset = seg->size; - segreloc->sym = sym; - segreloc->next = seg->relocs; - seg->relocs = segreloc; - seg_data (seg, (char *) &offset, sizeof offset); -} - - -/* Concatenate the contents of given segments into the first argument. */ - -static void -seg_concat (result, seg) - struct bc_seg *result, *seg; -{ - unsigned int fix; - struct bc_segsym *segsym; - struct bc_segreloc *segreloc; - - seg_align (result, MACHINE_SEG_ALIGN); - fix = result->size; - seg_data (result, seg->data, seg->size); - free (seg->data); - - /* Go through the symbols and relocs of SEG, adjusting their offsets - for their new location in RESULT. */ - if (seg->syms) - { - segsym = seg->syms; - do - segsym->sym->val += fix; - while (segsym->next && (segsym = segsym->next)); - segsym->next = result->syms; - result->syms = seg->syms; - } - if (seg->relocs) - { - segreloc = seg->relocs; - do - segreloc->offset += fix; - while (segreloc->next && (segreloc = segreloc->next)); - segreloc->next = result->relocs; - result->relocs = seg->relocs; - } - - free ((char *) seg); -} - -/* Write a segment to a file. */ - -static void -bc_seg_write (seg, file) - struct bc_seg *seg; - FILE *file; -{ - struct bc_segsym *segsym, *nsegsym, *psegsym; - struct bc_segreloc *segreloc, *nsegreloc, *psegreloc; - int i, offset, flag; - - /* Reverse the list of symbols. */ - for (psegsym = 0, segsym = seg->syms; segsym; segsym = nsegsym) - { - nsegsym = segsym->next; - segsym->next = psegsym; - psegsym = segsym; - } - seg->syms = psegsym; - - /* Reverse the list of relocs. */ - for (psegreloc = 0, segreloc = seg->relocs; segreloc; segreloc = nsegreloc) - { - nsegreloc = segreloc->next; - segreloc->next = psegreloc; - psegreloc = segreloc; - } - seg->relocs = psegreloc; - - /* Output each byte of the segment. */ - for (i = 0, segsym = seg->syms, segreloc = seg->relocs; i < seg->size; ++i) - { - while (segsym && segsym->sym->val == i) - { - if (i % 8 != 0) - putc ('\n', file); - - BC_WRITE_SEGSYM (segsym, file); - segsym = segsym->next; - flag = 1; - } - if (segreloc && segreloc->offset == i) - { - if (i % 8 != 0) - putc ('\n', file); - - bcopy (seg->data + i, (char *) &offset, sizeof (int)); - i += sizeof (int) - 1; - - BC_WRITE_RELOC_ENTRY (segreloc, file, offset); - segreloc = segreloc->next; - flag = 1; - } - else - { - if (i % 8 == 0 || flag) - BC_START_BYTECODE_LINE (file); - - BC_WRITE_BYTECODE (i % 8 == 0 || flag ? ' ' : ',', - seg->data[i] & 0xFF, - file); - flag = 0; - if (i % 8 == 7) - putc ('\n', file); - } - } - - /* Paranoia check--we should have visited all syms and relocs during - the output pass. */ - - if (segsym || segreloc) - abort (); -} - - - -/* Text and data segments of the object file in making. */ -static struct bc_seg *bc_text_seg; -static struct bc_seg *bc_data_seg; - -/* Called before anything else in this module. */ - -void -bc_initialize () -{ - int min_class_size[(int) MAX_MODE_CLASS]; - enum machine_mode mode; - int i; - - bc_init_mode_to_code_map (); - - bc_text_seg = seg_create (); - bc_data_seg = seg_create (); - - dconst0 = REAL_VALUE_ATOF ("0", DFmode); - dconst1 = REAL_VALUE_ATOF ("1", DFmode); - dconst2 = REAL_VALUE_ATOF ("2", DFmode); - dconstm1 = REAL_VALUE_ATOF ("-1", DFmode); - - /* Find the narrowest mode for each class and compute the word and byte - modes. */ - - for (i = 0; i < (int) MAX_MODE_CLASS; i++) - min_class_size[i] = 1000; - - for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; - mode = (enum machine_mode) ((int) mode + 1)) - { - if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)]) - { - class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode; - min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode); - } - if (GET_MODE_CLASS (mode) == MODE_INT - && GET_MODE_BITSIZE (mode) == BITS_PER_UNIT) - byte_mode = mode; - - if (GET_MODE_CLASS (mode) == MODE_INT - && GET_MODE_BITSIZE (mode) == BITS_PER_WORD) - word_mode = mode; - } -} - - -/* External addresses referenced in a function. Rather than trying to - work relocatable address directly into bytecoded functions (which would - require us to provide hairy location info and possibly obey alignment - rules imposed by the architecture) we build an auxiliary table of - pointer constants, and encode just offsets into this table into the - actual bytecode. */ -static struct bc_seg *ptrconsts; - -/* Trampoline code for the function entry. */ -struct bc_seg *trampoline; - -/* Actual byte code of the function. */ -struct bc_seg *bytecode; - -/* List of labels defined in the function. */ -struct bc_label *labels; - -/* List of label references in the function. */ -struct bc_labelref *labelrefs; - - -/* Add symbol to pointer table. Return offset into table where - pointer was stored. The offset usually goes into the bytecode - stream as a constP literal. */ - -int -bc_define_pointer (p) - char *p; -{ - int offset = ptrconsts->size; - - seg_refsym (ptrconsts, p, 0); - return offset; -} - - -/* Begin a bytecoded function. */ - -int -bc_begin_function (name) - char *name; -{ - ptrconsts = seg_create (); - trampoline = seg_create (); - bytecode = seg_create (); - return seg_defsym (trampoline, name); -} - - -/* Force alignment in inline bytecode. */ - -void -bc_align_bytecode (align) - int align; -{ - seg_align (bytecode, align); -} - - -/* Emit data inline into bytecode. */ - -void -bc_emit_bytecode_const (data, size) - char *data; - unsigned int size; -{ - if (bytecode) - seg_data (bytecode, data, size); -} - - -/* Create a new "bytecode label", to have its value defined later. - Bytecode labels have nothing to do with the object file symbol table, - and are purely local to a given bytecoded function. */ - -struct bc_label * -bc_get_bytecode_label () -{ - struct bc_label *result; - - result = (struct bc_label *) xmalloc (sizeof (struct bc_label)); - result->defined = 0; - result->next = labels; - result->uid = 0; - labels = result; - return result; -} - - -/* Define the given label with the current location counter. */ - -int -bc_emit_bytecode_labeldef (label) - struct bc_label *label; -{ - extern int bc_new_uid (); - - if (!label || label->defined) - return 0; - - label->offset = bytecode->size; - label->defined = 1; - label->uid = bc_new_uid (); - -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, "$%lx:\n", label); -#endif - - return 1; -} - - -/* Generate a location-relative reference to the given bytecode label. - It need not be defined yet; label references will be backpatched later. */ - -void -bc_emit_bytecode_labelref (label) - struct bc_label *label; -{ - struct bc_labelref *labelref; - static int zero; - - labelref = (struct bc_labelref *) xmalloc (sizeof (struct bc_labelref)); - labelref->label = label; - labelref->offset = bytecode->size; - labelref->next = labelrefs; - labelrefs = labelref; - -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, " $%lx", label); -#endif - - seg_data (bytecode, (char *) &zero, sizeof zero); -} - - -/* Emit a reference to an external address; generate the reference in the - ptrconst area, and emit an offset in the bytecode. */ - -void -bc_emit_code_labelref (name, offset) - char *name; - int offset; -{ - int ptroff; - - ptroff = ptrconsts->size / sizeof (char *); - seg_data (bytecode, (char *) &ptroff, sizeof ptroff); - seg_refsym (ptrconsts, name, offset); - -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, " [external <%x> %s]", ptroff, name); -#endif -} - - -/* Backpatch label references in the byte code, and concatenate the bytecode - and pointer constant segments to the cumulative text for the object file. - Return a label name for the pointer constants region. */ - -char * -bc_end_function () -{ - int addr; - struct bc_label *label, *next; - struct bc_labelref *ref, *nextref; - char ptrconsts_label[20]; - static int nlab; - - /* Backpatch bytecode label references. */ - for (ref = labelrefs; ref; ref = ref->next) - if (ref->label->defined) - { - addr = ref->label->offset; - bcopy ((char *) &addr, bytecode->data + ref->offset, sizeof addr); - } - - /* Free the chains of labelrefs and labeldefs. */ - for (ref = labelrefs; ref; ref = nextref) - { - nextref = ref->next; - free ((char *) ref); - } - - for (label = labels; label; label = next) - { - next = label->next; - free ((char *) label); - } - - seg_concat (trampoline, bytecode); - seg_align (trampoline, MACHINE_SEG_ALIGN); - sprintf (ptrconsts_label, "*LP%d", nlab++); - seg_defsym (trampoline, ptrconsts_label); - seg_concat (trampoline, ptrconsts); - seg_concat (bc_text_seg, trampoline); - - labels = 0; - labelrefs = 0; - trampoline = 0; - bytecode = 0; - ptrconsts = 0; - - return sym_lookup (ptrconsts_label)->name; -} - -/* Force alignment in const data. */ - -void -bc_align_const (align) - int align; -{ - seg_align (bc_text_seg, align); -} - -/* Emit const data. */ - -void -bc_emit_const (data, size) - char *data; - unsigned int size; -{ - seg_data (bc_text_seg, data, size); -} - -/* Emit a zero-filled constant skip. */ - -void -bc_emit_const_skip (size) - unsigned int size; -{ - seg_skip (bc_text_seg, size); -} - -/* Emit a label definition in const data. */ - -int -bc_emit_const_labeldef (name) - char *name; -{ - return seg_defsym (bc_text_seg, name); -} - -/* Emit a label reference in const data. */ - -void -bc_emit_const_labelref (name, offset) - char *name; - int offset; -{ - seg_refsym (bc_text_seg, name, offset); -} - -/* Force alignment in data. */ - -void -bc_align_data (align) - int align; -{ - seg_align (bc_data_seg, align); -} - -/* Emit data. */ - -void -bc_emit_data (data, size) - char *data; - unsigned int size; -{ - seg_data (bc_data_seg, data, size); -} - -/* Emit a zero-filled data skip. */ - -void -bc_emit_data_skip (size) - unsigned int size; -{ - seg_skip (bc_data_seg, size); -} - -/* Emit label definition in data. */ - -int -bc_emit_data_labeldef (name) - char *name; -{ - return seg_defsym (bc_data_seg, name); -} - -/* Emit label reference in data. */ - -void -bc_emit_data_labelref (name, offset) - char *name; - int offset; -{ - seg_refsym (bc_data_seg, name, offset); -} - -/* Emit a common block of the given name and size. Note that - when the .o file is actually written non-global "common" - blocks will have to be turned into space in the data section. */ - -int -bc_emit_common (name, size) - char *name; - unsigned int size; -{ - struct bc_sym *sym; - - sym = sym_lookup (name); - if (sym->defined) - return 0; - - sym->defined = 1; - sym->common = 1; - sym->val = size; - return 1; -} - -/* Globalize the given label. */ - -void -bc_globalize_label (name) - char *name; -{ - struct bc_sym *sym; - - sym = sym_lookup (name); - sym->global = 1; -} - -static enum { in_text, in_data } section = in_text; - -void -bc_text () -{ - section = in_text; -} - -void -bc_data () -{ - section = in_data; -} - -void -bc_align (align) - int align; -{ - if (section == in_text) - bc_align_const (align); - else - bc_align_data (align); -} - -void -bc_emit (data, size) - char *data; - unsigned int size; -{ - if (section == in_text) - bc_emit_const (data, size); - else - bc_emit_data (data, size); -} - -void -bc_emit_skip (size) - unsigned int size; -{ - if (section == in_text) - bc_emit_const_skip (size); - else - bc_emit_data_skip (size); -} - -int -bc_emit_labeldef (name) - char *name; -{ - if (section == in_text) - return bc_emit_const_labeldef (name); - else - return bc_emit_data_labeldef (name); -} - -void -bc_emit_labelref (name, offset) - char *name; - int offset; -{ - if (section == in_text) - bc_emit_const_labelref (name, offset); - else - bc_emit_data_labelref (name, offset); -} - -void -bc_write_file (file) - FILE *file; -{ - BC_WRITE_FILE (file); -} - - -/* Allocate a new bytecode rtx. - If you supply a null BC_LABEL, we generate one. */ - -rtx -bc_gen_rtx (label, offset, bc_label) - char *label; - int offset; - struct bc_label *bc_label; -{ - rtx r; - - if (bc_label == 0) - bc_label = (struct bc_label *) xmalloc (sizeof (struct bc_label)); - - r = gen_rtx (CODE_LABEL, VOIDmode, label, bc_label); - bc_label->offset = offset; - - return r; -} - - -/* Print bytecode rtx */ - -void -bc_print_rtl (fp, r) - FILE *fp; - rtx r; -{ -#if 0 /* This needs to get fixed to really work again. */ - /* BC_WRITE_RTL has a definition - that doesn't even make sense for this use. */ - BC_WRITE_RTL (r, fp); -#endif -} - - -/* Emit a bytecode, keeping a running tally of the stack depth. */ - -void -bc_emit_bytecode (bytecode) - enum bytecode_opcode bytecode; -{ - char byte; - static int prev_lineno = -1; - - byte = (char) bytecode; - -#ifdef BCDEBUG_PRINT_CODE - if (lineno != prev_lineno) - { - fprintf (stderr, "\n", lineno); - prev_lineno = lineno; - } - - fputs (opcode_name[(unsigned int) bytecode], stderr); -#endif - - /* Due to errors we are often requested to output bytecodes that - will cause an interpreter stack undeflow when executed. Instead of - dumping core on such occasions, we omit the bytecode. Erroneous code - should not be executed, regardless. This makes life much easier, since - we don't have to deceive ourselves about the known stack depth. */ - - bc_emit_bytecode_const (&byte, 1); - - if ((stack_depth -= arityvec[(int) bytecode].ninputs) >= 0) - { - if ((stack_depth += arityvec[(int) bytecode].noutputs) > max_stack_depth) - max_stack_depth = stack_depth; - } - -#ifdef VALIDATE_STACK_FOR_BC - VALIDATE_STACK_FOR_BC (); -#endif -} - - -#ifdef BCDEBUG_PRINT_CODE -#define PRLIT(TYPE, PTR) fprintf (stderr, " [%x]", *(TYPE *) PTR) -#else -#define PRLIT(X,Y) -#endif - -/* Emit a complete bytecode instruction, expecting the correct number - of literal values in the call. First argument is the instruction, the - remaining arguments are literals of size HOST_WIDE_INT or smaller. */ - -void -bc_emit_instruction VPROTO((enum bytecode_opcode opcode, ...)) -{ -#ifndef __STDC__ - enum bytecode_opcode opcode; -#endif - va_list arguments; - int nliteral, instruction; - - VA_START (arguments, opcode); - -#ifndef __STDC__ - opcode = va_arg (arguments, enum bytecode_opcode); -#endif - - /* Emit instruction bytecode */ - bc_emit_bytecode (opcode); - instruction = (int) opcode; - - /* Loop literals and emit as bytecode constants */ - for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++) - { - switch (arityvec[instruction].literals[nliteral]) - { -/* This conditional is a kludge, but it's necessary - because TYPE might be long long. */ -#ifdef __GNUC__ - /* Expand definitions into case statements */ -#define DEFTYPECODE(CODE, NAME, MODE, TYPE) \ - case CODE: \ - { \ - TYPE temp = va_arg (arguments, TYPE); \ - bc_emit_bytecode_const ((void *) &temp, sizeof temp); \ - PRLIT (TYPE, &temp); } \ - break; - -#include "bc-typecd.def" - -#undef DEFTYPECODE -#endif /* __GNUC__ */ - - default: - abort (); - } - } - - va_end (arguments); - -#ifdef BCDEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif -} - -/* Emit the machine-code interface trampoline at the beginning of a byte - coded function. The argument is a label name of the interpreter - bytecode callinfo structure; the return value is a label name for - the beginning of the actual bytecode. */ - -char * -bc_emit_trampoline (callinfo) - char *callinfo; -{ - char mylab[20]; - static int n; - - sprintf (mylab, "*LB%d", n++); - - BC_EMIT_TRAMPOLINE (trampoline, callinfo); - - seg_defsym (bytecode, mylab); - return sym_lookup (mylab)->name; -} diff --git a/gcc/bc-emit.h b/gcc/bc-emit.h deleted file mode 100644 index c00da5b3539..00000000000 --- a/gcc/bc-emit.h +++ /dev/null @@ -1,133 +0,0 @@ -/* bc-emit.h - declare entry points for producing object files of bytecodes. */ - -/* Internal format of symbol table for the object file. */ -struct bc_sym -{ - /* Private copy separately malloc'd. */ - char *name; - - /* Symbol has a defined value. */ - unsigned int defined:1; - - /* Symbol has been globalized. */ - unsigned int global:1; - - /* Symbol is common. */ - unsigned int common:1; - - /* Value if defined. */ - unsigned long int val; - - /* Used in internal symbol table structure. */ - struct bc_sym *next; -}; - - -/* List of symbols defined in a particular segment. */ -struct bc_segsym -{ - struct bc_sym *sym; - struct bc_segsym *next; -}; - - -/* List of relocations needed in a particular segment. */ -struct bc_segreloc -{ - /* Offset of datum to be relocated. */ - unsigned int offset; - - /* Symbol to be relocated by. */ - struct bc_sym *sym; - - struct bc_segreloc *next; -}; - - -/* Segment of an object file. */ -struct bc_seg -{ - /* Size allocated to contents. */ - unsigned int alloc; - - /* Pointer to base of contents. */ - char *data; - - /* Actual size of contents. */ - unsigned int size; - - /* List of symbols defined in this segment. */ - struct bc_segsym *syms; - - /* List of relocations for this segment. */ - struct bc_segreloc *relocs; -}; - - -/* Anonymous bytecode label within a single function. */ -struct bc_label -{ - /* Offset of label from start of segment. */ - unsigned int offset; - - /* True when offset is valid. */ - unsigned int defined:1; - - /* Unique bytecode ID, used to determine innermost - block containment */ - int uid; - - /* Next node in list */ - struct bc_label *next; -}; - - -/* Reference to a bc_label; a list of all such references is kept for - the function, then when it is finished they are backpatched to - contain the correct values. */ - -struct bc_labelref -{ - /* Label referenced. */ - struct bc_label *label; - - /* Code offset of reference. */ - unsigned int offset; - - /* Next labelref in list */ - struct bc_labelref *next; -}; - - - -extern void bc_initialize(); -extern int bc_begin_function(); -extern char *bc_emit_trampoline(); -extern void bc_emit_bytecode(); -extern void bc_emit_bytecode_const(); -extern struct bc_label *bc_get_bytecode_label(); -extern int bc_emit_bytecode_labeldef(); -extern void bc_emit_bytecode_labelref(); -extern void bc_emit_code_labelref(); -extern char *bc_end_function(); -extern void bc_align_const(); -extern void bc_emit_const(); -extern void bc_emit_const_skip(); -extern int bc_emit_const_labeldef(); -extern void bc_emit_const_labelref(); -extern void bc_align_data(); -extern void bc_emit_data(); -extern void bc_emit_data_skip(); -extern int bc_emit_data_labeldef(); -extern void bc_emit_data_labelref(); -extern int bc_define_pointer (); -extern int bc_emit_common(); -extern void bc_globalize_label(); -extern void bc_text(); -extern void bc_data(); -extern void bc_align(); -extern void bc_emit(); -extern void bc_emit_skip(); -extern int bc_emit_labeldef(); -extern void bc_emit_labelref(); -extern void bc_write_file(); diff --git a/gcc/bc-optab.c b/gcc/bc-optab.c deleted file mode 100644 index dd134d5f0b3..00000000000 --- a/gcc/bc-optab.c +++ /dev/null @@ -1,810 +0,0 @@ -/* Bytecode conversion definitions for GNU C-compiler. - Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -#include "config.h" -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#include "tree.h" -#include "rtl.h" -#include "machmode.h" -#include "obstack.h" -#include "bytecode.h" -#include "bc-typecd.h" -#include "bc-opcode.h" -#include "bc-optab.h" - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef NEED_DECLARATION_FREE -extern void free PROTO((void *)); -#endif - -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -extern char *xmalloc (); - -/* Table relating interpreter typecodes to machine modes. */ -#define GET_TYPECODE_MODE(CODE) (typecode_mode[((int) CODE)]) -enum machine_mode typecode_mode[] = { -#define DEFTYPECODE(CODE, NAME, MODE, TYPE) MODE, -#include "bc-typecd.def" -#undef DEFTYPECODE -}; - -/* Machine mode to type code map */ -static enum typecode signed_mode_to_code_map[MAX_MACHINE_MODE+1]; -static enum typecode unsigned_mode_to_code_map[MAX_MACHINE_MODE+1]; - -#define GET_TYPECODE_SIZE(CODE) GET_MODE_SIZE (GET_TYPECODE_MODE (CODE)) - -#define BIG_ARBITRARY_NUMBER 100000 - -/* Table of recipes for conversions among scalar types, to be filled - in as needed at run time. */ -static struct conversion_recipe -{ - unsigned char *opcodes; /* Bytecodes to emit in order. */ - int nopcodes; /* Count of bytecodes. */ - int cost; /* A rather arbitrary cost function. */ -} conversion_recipe[NUM_TYPECODES][NUM_TYPECODES]; - -/* Binary operator tables. */ -struct binary_operator optab_plus_expr[] = { - { addSI, SIcode, SIcode, SIcode }, - { addDI, DIcode, DIcode, DIcode }, - { addSF, SFcode, SFcode, SFcode }, - { addDF, DFcode, DFcode, DFcode }, - { addXF, XFcode, XFcode, XFcode }, - { addPSI, Pcode, Pcode, SIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_minus_expr[] = { - { subSI, SIcode, SIcode, SIcode }, - { subDI, DIcode, DIcode, DIcode }, - { subSF, SFcode, SFcode, SFcode }, - { subDF, DFcode, DFcode, DFcode }, - { subXF, XFcode, XFcode, XFcode }, - { subPP, SIcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -/* The ordering of the tables for multiplicative operators - is such that unsigned operations will be preferred to signed - operations when one argument is unsigned. */ - -struct binary_operator optab_mult_expr[] = { - { mulSU, SUcode, SUcode, SUcode }, - { mulDU, DUcode, DUcode, DUcode }, - { mulSI, SIcode, SIcode, SIcode }, - { mulDI, DIcode, DIcode, DIcode }, - { mulSF, SFcode, SFcode, SFcode }, - { mulDF, DFcode, DFcode, DFcode }, - { mulXF, XFcode, XFcode, XFcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_trunc_div_expr[] = { - { divSU, SUcode, SUcode, SUcode }, - { divDU, DUcode, DUcode, DUcode }, - { divSI, SIcode, SIcode, SIcode }, - { divDI, DIcode, DIcode, DIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_trunc_mod_expr[] = { - { modSU, SUcode, SUcode, SUcode }, - { modDU, DUcode, DUcode, DUcode }, - { modSI, SIcode, SIcode, SIcode }, - { modDI, DIcode, DIcode, DIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_rdiv_expr[] = { - { divSF, SFcode, SFcode, SFcode }, - { divDF, DFcode, DFcode, DFcode }, - { divXF, XFcode, XFcode, XFcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_bit_and_expr[] = { - { andSI, SIcode, SIcode, SIcode }, - { andDI, DIcode, DIcode, DIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_bit_ior_expr[] = { - { iorSI, SIcode, SIcode, SIcode }, - { iorDI, DIcode, DIcode, DIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_bit_xor_expr[] = { - { xorSI, SIcode, SIcode, SIcode }, - { xorDI, DIcode, DIcode, DIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_lshift_expr[] = { - { lshiftSI, SIcode, SIcode, SIcode }, - { lshiftSU, SUcode, SUcode, SIcode }, - { lshiftDI, DIcode, DIcode, SIcode }, - { lshiftDU, DUcode, DUcode, SIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_rshift_expr[] = { - { rshiftSI, SIcode, SIcode, SIcode }, - { rshiftSU, SUcode, SUcode, SIcode }, - { rshiftDI, DIcode, DIcode, SIcode }, - { rshiftDU, DUcode, DUcode, SIcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_truth_and_expr[] = { - { andSI, SIcode, Tcode, Tcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_truth_or_expr[] = { - { iorSI, SIcode, Tcode, Tcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_lt_expr[] = { - { ltSI, Tcode, SIcode, SIcode }, - { ltSU, Tcode, SUcode, SUcode }, - { ltDI, Tcode, DIcode, DIcode }, - { ltDU, Tcode, DUcode, DUcode }, - { ltSF, Tcode, SFcode, SFcode }, - { ltDF, Tcode, DFcode, DFcode }, - { ltXF, Tcode, XFcode, XFcode }, - { ltP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_le_expr[] = { - { leSI, Tcode, SIcode, SIcode }, - { leSU, Tcode, SUcode, SUcode }, - { leDI, Tcode, DIcode, DIcode }, - { leDU, Tcode, DUcode, DUcode }, - { leSF, Tcode, SFcode, SFcode }, - { leDF, Tcode, DFcode, DFcode }, - { leXF, Tcode, XFcode, XFcode }, - { leP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_ge_expr[] = { - { geSI, Tcode, SIcode, SIcode }, - { geSU, Tcode, SUcode, SUcode }, - { geDI, Tcode, DIcode, DIcode }, - { geDU, Tcode, DUcode, DUcode }, - { geSF, Tcode, SFcode, SFcode }, - { geDF, Tcode, DFcode, DFcode }, - { geXF, Tcode, XFcode, XFcode }, - { geP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_gt_expr[] = { - { gtSI, Tcode, SIcode, SIcode }, - { gtSU, Tcode, SUcode, SUcode }, - { gtDI, Tcode, DIcode, DIcode }, - { gtDU, Tcode, DUcode, DUcode }, - { gtSF, Tcode, SFcode, SFcode }, - { gtDF, Tcode, DFcode, DFcode }, - { gtXF, Tcode, XFcode, XFcode }, - { gtP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_eq_expr[] = { - { eqSI, Tcode, SIcode, SIcode }, - { eqDI, Tcode, DIcode, DIcode }, - { eqSF, Tcode, SFcode, SFcode }, - { eqDF, Tcode, DFcode, DFcode }, - { eqXF, Tcode, XFcode, XFcode }, - { eqP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -struct binary_operator optab_ne_expr[] = { - { neSI, Tcode, SIcode, SIcode }, - { neDI, Tcode, DIcode, DIcode }, - { neSF, Tcode, SFcode, SFcode }, - { neDF, Tcode, DFcode, DFcode }, - { neXF, Tcode, XFcode, XFcode }, - { neP, Tcode, Pcode, Pcode }, - { -1, -1, -1, -1 }, -}; - -/* Unary operator tables. */ -struct unary_operator optab_negate_expr[] = { - { negSI, SIcode, SIcode }, - { negDI, DIcode, DIcode }, - { negSF, SFcode, SFcode }, - { negDF, DFcode, DFcode }, - { negXF, XFcode, XFcode }, - { -1, -1, -1 }, -}; - -struct unary_operator optab_bit_not_expr[] = { - { notSI, SIcode, SIcode }, - { notDI, DIcode, DIcode }, - { -1, -1, -1 }, -}; - -struct unary_operator optab_truth_not_expr[] = { - { notT, SIcode, SIcode }, - { -1, -1, -1 }, -}; - -/* Increment operator tables. */ -struct increment_operator optab_predecrement_expr[] = { - { predecQI, QIcode }, - { predecQI, QUcode }, - { predecHI, HIcode }, - { predecHI, HUcode }, - { predecSI, SIcode }, - { predecSI, SUcode }, - { predecDI, DIcode }, - { predecDI, DUcode }, - { predecP, Pcode }, - { predecSF, SFcode }, - { predecDF, DFcode }, - { predecXF, XFcode }, - { -1, -1 }, -}; - -struct increment_operator optab_preincrement_expr[] = { - { preincQI, QIcode }, - { preincQI, QUcode }, - { preincHI, HIcode }, - { preincHI, HUcode }, - { preincSI, SIcode }, - { preincSI, SUcode }, - { preincDI, DIcode }, - { preincDI, DUcode }, - { preincP, Pcode }, - { preincSF, SFcode }, - { preincDF, DFcode }, - { preincXF, XFcode }, - { -1, -1 }, -}; - -struct increment_operator optab_postdecrement_expr[] = { - { postdecQI, QIcode }, - { postdecQI, QUcode }, - { postdecHI, HIcode }, - { postdecHI, HUcode }, - { postdecSI, SIcode }, - { postdecSI, SUcode }, - { postdecDI, DIcode }, - { postdecDI, DUcode }, - { postdecP, Pcode }, - { postdecSF, SFcode }, - { postdecDF, DFcode }, - { postdecXF, XFcode }, - { -1, -1 }, -}; - -struct increment_operator optab_postincrement_expr[] = { - { postincQI, QIcode }, - { postincQI, QUcode }, - { postincHI, HIcode }, - { postincHI, HUcode }, - { postincSI, SIcode }, - { postincSI, SUcode }, - { postincDI, DIcode }, - { postincDI, DUcode }, - { postincP, Pcode }, - { postincSF, SFcode }, - { postincDF, DFcode }, - { postincXF, XFcode }, - { -1, -1 }, -}; - -/* Table of conversions supported by the interpreter. */ -static struct conversion_info -{ - enum bytecode_opcode opcode; /* here indicates the conversion needs no opcode. */ - enum typecode from; - enum typecode to; - int cost; /* 1 for no-op conversions, 2 for widening conversions, - 4 for int/float conversions, 8 for narrowing conversions. */ -} conversion_info[] = { - { -1, QIcode, QUcode, 1 }, - { -1, HIcode, HUcode, 1 }, - { -1, SIcode, SUcode, 1 }, - { -1, DIcode, DUcode, 1 }, - { -1, QUcode, QIcode, 1 }, - { -1, HUcode, HIcode, 1 }, - { -1, SUcode, SIcode, 1 }, - { -1, DUcode, DIcode, 1 }, - { -1, Tcode, SIcode, 1 }, - { convertQIHI, QIcode, HIcode, 2 }, - { convertQUHU, QUcode, HUcode, 2 }, - { convertQUSU, QUcode, SUcode, 2 }, - { convertHISI, HIcode, SIcode, 2 }, - { convertHUSU, HUcode, SUcode, 2 }, - { convertSIDI, SIcode, DIcode, 2 }, - { convertSUDU, SUcode, DUcode, 2 }, - { convertSFDF, SFcode, DFcode, 2 }, - { convertDFXF, DFcode, XFcode, 2 }, - { convertHIQI, HIcode, QIcode, 8 }, - { convertSIQI, SIcode, QIcode, 8 }, - { convertSIHI, SIcode, HIcode, 8 }, - { convertSUQU, SUcode, QUcode, 8 }, - { convertDISI, DIcode, SIcode, 8 }, - { convertDFSF, DFcode, SFcode, 8 }, - { convertXFDF, XFcode, DFcode, 8 }, - { convertPSI, Pcode, SIcode, 2 }, - { convertSIP, SIcode, Pcode, 2 }, - { convertSIT, SIcode, Tcode, 2 }, - { convertDIT, DIcode, Tcode, 2 }, - { convertSFT, SFcode, Tcode, 2 }, - { convertDFT, DFcode, Tcode, 2 }, - { convertXFT, XFcode, Tcode, 2 }, - { convertQISI, QIcode, SIcode, 2 }, - { convertPT, Pcode, Tcode, 2 }, - { convertSISF, SIcode, SFcode, 4 }, - { convertSIDF, SIcode, DFcode, 4 }, - { convertSIXF, SIcode, XFcode, 4 }, - { convertSUSF, SUcode, SFcode, 4 }, - { convertSUDF, SUcode, DFcode, 4 }, - { convertSUXF, SUcode, XFcode, 4 }, - { convertDISF, DIcode, SFcode, 4 }, - { convertDIDF, DIcode, DFcode, 4 }, - { convertDIXF, DIcode, XFcode, 4 }, - { convertDUSF, DUcode, SFcode, 4 }, - { convertDUDF, DUcode, DFcode, 4 }, - { convertDUXF, DUcode, XFcode, 4 }, - { convertSFSI, SFcode, SIcode, 4 }, - { convertDFSI, DFcode, SIcode, 4 }, - { convertXFSI, XFcode, SIcode, 4 }, - { convertSFSU, SFcode, SUcode, 4 }, - { convertDFSU, DFcode, SUcode, 4 }, - { convertXFSU, XFcode, SUcode, 4 }, - { convertSFDI, SFcode, DIcode, 4 }, - { convertDFDI, DFcode, DIcode, 4 }, - { convertXFDI, XFcode, DIcode, 4 }, - { convertSFDU, SFcode, DUcode, 4 }, - { convertDFDU, DFcode, DUcode, 4 }, - { convertXFDU, XFcode, DUcode, 4 }, - { convertSIQI, SIcode, QIcode, 8 }, -}; - -#define NUM_CONVERSIONS (sizeof conversion_info / sizeof (struct conversion_info)) - -/* List form of a conversion recipe. */ -struct conversion_list -{ - enum bytecode_opcode opcode; - enum typecode to; - int cost; - struct conversion_list *prev; -}; - -/* Determine if it is "reasonable" to add a given conversion to - a given list of conversions. The following criteria define - "reasonable" conversion lists: - * No typecode appears more than once in the sequence (no loops). - * At most one conversion from integer to float or vice versa is present. - * Either sign extensions or zero extensions may be present, but not both. - * No widening conversions occur after a signed/unsigned conversion. - * The sequence of sizes must be strict nonincreasing or nondecreasing. */ - -static int -conversion_reasonable_p (conversion, list) - struct conversion_info *conversion; - struct conversion_list *list; -{ - struct conversion_list *curr; - int curr_size, prev_size; - int has_int_float, has_float_int; - int has_sign_extend, has_zero_extend; - int has_signed_unsigned, has_unsigned_signed; - - has_int_float = 0; - has_float_int = 0; - has_sign_extend = 0; - has_zero_extend = 0; - has_signed_unsigned = 0; - has_unsigned_signed = 0; - - /* Make sure the destination typecode doesn't already appear in - the list. */ - for (curr = list; curr; curr = curr->prev) - if (conversion->to == curr->to) - return 0; - - /* Check for certain kinds of conversions. */ - if (TYPECODE_INTEGER_P (conversion->from) - && TYPECODE_FLOAT_P (conversion->to)) - has_int_float = 1; - if (TYPECODE_FLOAT_P (conversion->from) - && TYPECODE_INTEGER_P (conversion->to)) - has_float_int = 1; - if (TYPECODE_SIGNED_P (conversion->from) - && TYPECODE_SIGNED_P (conversion->to) - && GET_TYPECODE_SIZE (conversion->from) - < GET_TYPECODE_SIZE (conversion->to)) - has_sign_extend = 1; - if (TYPECODE_UNSIGNED_P (conversion->from) - && TYPECODE_UNSIGNED_P (conversion->to) - && GET_TYPECODE_SIZE (conversion->from) - < GET_TYPECODE_SIZE (conversion->to)) - has_zero_extend = 1; - - for (curr = list; curr && curr->prev; curr = curr->prev) - { - if (TYPECODE_INTEGER_P (curr->prev->to) - && TYPECODE_FLOAT_P (curr->to)) - has_int_float = 1; - if (TYPECODE_FLOAT_P (curr->prev->to) - && TYPECODE_INTEGER_P (curr->to)) - has_float_int = 1; - if (TYPECODE_SIGNED_P (curr->prev->to) - && TYPECODE_SIGNED_P (curr->to) - && GET_TYPECODE_SIZE (curr->prev->to) - < GET_TYPECODE_SIZE (curr->to)) - has_sign_extend = 1; - if (TYPECODE_UNSIGNED_P (curr->prev->to) - && TYPECODE_UNSIGNED_P (curr->to) - && GET_TYPECODE_SIZE (curr->prev->to) - < GET_TYPECODE_SIZE (curr->to)) - has_zero_extend = 1; - if (TYPECODE_SIGNED_P (curr->prev->to) - && TYPECODE_UNSIGNED_P (curr->to)) - has_signed_unsigned = 1; - if (TYPECODE_UNSIGNED_P (curr->prev->to) - && TYPECODE_SIGNED_P (curr->to)) - has_unsigned_signed = 1; - } - - if (TYPECODE_INTEGER_P (conversion->from) - && TYPECODE_INTEGER_P (conversion->to) - && GET_TYPECODE_SIZE (conversion->to) - > GET_TYPECODE_SIZE (conversion->from) - && (has_signed_unsigned || has_unsigned_signed)) - return 0; - - if (has_float_int && has_int_float || has_sign_extend && has_zero_extend) - return 0; - - /* Make sure the sequence of destination typecode sizes is - strictly nondecreasing or strictly nonincreasing. */ - prev_size = GET_TYPECODE_SIZE (conversion->to); - for (curr = list; curr; curr = curr->prev) - { - curr_size = GET_TYPECODE_SIZE (curr->to); - if (curr_size != prev_size) - break; - } - if (!curr) - return 1; - - if (curr_size < prev_size) - for (prev_size = curr_size; curr; curr = curr->prev) - { - curr_size = GET_TYPECODE_SIZE (curr->to); - if (curr_size > prev_size) - return 0; - prev_size = curr_size; - } - else - for (prev_size = curr_size; curr; curr = curr->prev) - { - curr_size = GET_TYPECODE_SIZE (curr->to); - if (curr_size < prev_size) - return 0; - prev_size = curr_size; - } - return 1; -} - - -/* Exhaustively search all reasonable conversions to find one to - convert the given types. */ - -static struct conversion_recipe -deduce_conversion (from, to) - enum typecode from, to; -{ - struct rl - { - struct conversion_list *list; - struct rl *next; - } *prev, curr, *good, *temp; - struct conversion_list *conv, *best; - int i, cost, bestcost; - struct conversion_recipe result; - struct obstack recipe_obstack; - - - obstack_init (&recipe_obstack); - curr.next = (struct rl *) obstack_alloc (&recipe_obstack, sizeof (struct rl)); - curr.next->list - = (struct conversion_list *) obstack_alloc (&recipe_obstack, - sizeof (struct conversion_list)); - curr.next->list->opcode = -1; - curr.next->list->to = from; - curr.next->list->cost = 0; - curr.next->list->prev = 0; - curr.next->next = 0; - good = 0; - - while (curr.next) - { - /* Remove successful conversions from further consideration. */ - for (prev = &curr; prev; prev = prev->next) - if (prev->next && prev->next->list->to == to) - { - temp = prev->next->next; - prev->next->next = good; - good = prev->next; - prev->next = temp; - } - - /* Go through each of the pending conversion chains, trying - all possible candidate conversions on them. */ - for (prev = curr.next, curr.next = 0; prev; prev = prev->next) - for (i = 0; i < NUM_CONVERSIONS; ++i) - if (conversion_info[i].from == prev->list->to - && conversion_reasonable_p (&conversion_info[i], prev->list)) - { - temp = (struct rl *) obstack_alloc (&recipe_obstack, - sizeof (struct rl)); - temp->list = (struct conversion_list *) - obstack_alloc (&recipe_obstack, - sizeof (struct conversion_list)); - temp->list->opcode = conversion_info[i].opcode; - temp->list->to = conversion_info[i].to; - temp->list->cost = conversion_info[i].cost; - temp->list->prev = prev->list; - temp->next = curr.next; - curr.next = temp; - } - } - - bestcost = BIG_ARBITRARY_NUMBER; - best = 0; - for (temp = good; temp; temp = temp->next) - { - for (conv = temp->list, cost = 0; conv; conv = conv->prev) - cost += conv->cost; - if (cost < bestcost) - { - bestcost = cost; - best = temp->list; - } - } - - if (!best) - abort (); - - for (i = 0, conv = best; conv; conv = conv->prev) - if (conv->opcode != -1) - ++i; - - result.opcodes = (unsigned char *) xmalloc (i); - result.nopcodes = i; - for (conv = best; conv; conv = conv->prev) - if (conv->opcode != -1) - result.opcodes[--i] = conv->opcode; - result.cost = bestcost; - obstack_free (&recipe_obstack, 0); - return result; -} - -#define DEDUCE_CONVERSION(FROM, TO) \ - (conversion_recipe[(int) FROM][(int) TO].opcodes ? 0 \ - : (conversion_recipe[(int) FROM][(int) TO] \ - = deduce_conversion (FROM, TO), 0)) - - -/* Emit a conversion between the given scalar types. */ - -void -emit_typecode_conversion (from, to) - enum typecode from, to; -{ - int i; - - DEDUCE_CONVERSION (from, to); - for (i = 0; i < conversion_recipe[(int) from][(int) to].nopcodes; ++i) - bc_emit_instruction (conversion_recipe[(int) from][(int) to].opcodes[i]); -} - - -/* Initialize mode_to_code_map[] */ - -void -bc_init_mode_to_code_map () -{ - int mode; - - for (mode = 0; mode < MAX_MACHINE_MODE + 1; mode++) - { - signed_mode_to_code_map[mode] - = unsigned_mode_to_code_map[mode] - = LAST_AND_UNUSED_TYPECODE; - } - -#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \ - { signed_mode_to_code_map[(int) SYM] = CODE; \ - unsigned_mode_to_code_map[(int) SYM] = UCODE; } -#include "modemap.def" -#undef DEF_MODEMAP - - /* Initialize opcode maps for const, load, and store */ - bc_init_mode_to_opcode_maps (); -} - -/* Given a machine mode return the preferred typecode. */ - -enum typecode -preferred_typecode (mode, unsignedp) - enum machine_mode mode; - int unsignedp; -{ - enum typecode code = (unsignedp - ? unsigned_mode_to_code_map - : signed_mode_to_code_map) [MIN ((int) mode, - (int) MAX_MACHINE_MODE)]; - - if (code == LAST_AND_UNUSED_TYPECODE) - abort (); - - return code; -} - - -/* Expand a conversion between the given types. */ - -void -bc_expand_conversion (from, to) - tree from, to; -{ - enum typecode fcode, tcode; - - fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from)); - tcode = preferred_typecode (TYPE_MODE (to), TREE_UNSIGNED (to)); - - emit_typecode_conversion (fcode, tcode); -} - -/* Expand a conversion of the given type to a truth value. */ - -void -bc_expand_truth_conversion (from) - tree from; -{ - enum typecode fcode; - - fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from)); - emit_typecode_conversion (fcode, Tcode); -} - -/* Emit an appropriate binary operation. */ - -void -bc_expand_binary_operation (optab, resulttype, arg0, arg1) - struct binary_operator optab[]; - tree resulttype, arg0, arg1; -{ - int i, besti, cost, bestcost; - enum typecode resultcode, arg0code, arg1code; - - resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype)); - arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (resulttype)); - arg1code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg1)), TREE_UNSIGNED (resulttype)); - - besti = -1; - bestcost = BIG_ARBITRARY_NUMBER; - - for (i = 0; optab[i].opcode != -1; ++i) - { - cost = 0; - DEDUCE_CONVERSION (arg0code, optab[i].arg0); - cost += conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost; - DEDUCE_CONVERSION (arg1code, optab[i].arg1); - cost += conversion_recipe[(int) arg1code][(int) optab[i].arg1].cost; - if (cost < bestcost) - { - besti = i; - bestcost = cost; - } - } - - if (besti == -1) - abort (); - - expand_expr (arg1, 0, VOIDmode, 0); - emit_typecode_conversion (arg1code, optab[besti].arg1); - expand_expr (arg0, 0, VOIDmode, 0); - emit_typecode_conversion (arg0code, optab[besti].arg0); - bc_emit_instruction (optab[besti].opcode); - emit_typecode_conversion (optab[besti].result, resultcode); -} - -/* Emit an appropriate unary operation. */ - -void -bc_expand_unary_operation (optab, resulttype, arg0) - struct unary_operator optab[]; - tree resulttype, arg0; -{ - int i, besti, cost, bestcost; - enum typecode resultcode, arg0code; - - resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype)); - arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (TREE_TYPE (arg0))); - - besti = -1; - bestcost = BIG_ARBITRARY_NUMBER; - - for (i = 0; optab[i].opcode != -1; ++i) - { - DEDUCE_CONVERSION (arg0code, optab[i].arg0); - cost = conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost; - if (cost < bestcost) - { - besti = i; - bestcost = cost; - } - } - - if (besti == -1) - abort (); - - expand_expr (arg0, 0, VOIDmode, 0); - emit_typecode_conversion (arg0code, optab[besti].arg0); - bc_emit_instruction (optab[besti].opcode); - emit_typecode_conversion (optab[besti].result, resultcode); -} - - -/* Emit an appropriate increment. */ - -void -bc_expand_increment (optab, type) - struct increment_operator optab[]; - tree type; -{ - enum typecode code; - int i; - - code = preferred_typecode (TYPE_MODE (type), TREE_UNSIGNED (type)); - for (i = 0; (int) optab[i].opcode >= 0; ++i) - if (code == optab[i].arg) - { - bc_emit_instruction (optab[i].opcode); - return; - } - abort (); -} diff --git a/gcc/bc-optab.h b/gcc/bc-optab.h deleted file mode 100644 index 6ad0b8592f6..00000000000 --- a/gcc/bc-optab.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Bytecode token definitions for GNU C-compiler. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -extern void bc_expand_conversion (); -extern void bc_expand_truth_conversion (); -extern void bc_expand_binary_operation (); -extern void bc_expand_unary_operation (); - -struct binary_operator -{ - enum bytecode_opcode opcode; - enum typecode result; - enum typecode arg0; - enum typecode arg1; -}; - -extern struct binary_operator optab_plus_expr[]; -extern struct binary_operator optab_minus_expr[]; -extern struct binary_operator optab_mult_expr[]; -extern struct binary_operator optab_trunc_div_expr[]; -extern struct binary_operator optab_trunc_mod_expr[]; -extern struct binary_operator optab_rdiv_expr[]; -extern struct binary_operator optab_bit_and_expr[]; -extern struct binary_operator optab_bit_ior_expr[]; -extern struct binary_operator optab_bit_xor_expr[]; -extern struct binary_operator optab_lshift_expr[]; -extern struct binary_operator optab_rshift_expr[]; -extern struct binary_operator optab_truth_and_expr[]; -extern struct binary_operator optab_truth_or_expr[]; -extern struct binary_operator optab_lt_expr[]; -extern struct binary_operator optab_le_expr[]; -extern struct binary_operator optab_ge_expr[]; -extern struct binary_operator optab_gt_expr[]; -extern struct binary_operator optab_eq_expr[]; -extern struct binary_operator optab_ne_expr[]; - -struct unary_operator -{ - enum bytecode_opcode opcode; - enum typecode result; - enum typecode arg0; -}; - -extern struct unary_operator optab_negate_expr[]; -extern struct unary_operator optab_bit_not_expr[]; -extern struct unary_operator optab_truth_not_expr[]; - -struct increment_operator -{ - enum bytecode_opcode opcode; - enum typecode arg; -}; - -extern struct increment_operator optab_predecrement_expr[]; -extern struct increment_operator optab_preincrement_expr[]; -extern struct increment_operator optab_postdecrement_expr[]; -extern struct increment_operator optab_postincrement_expr[]; diff --git a/gcc/bc-typecd.def b/gcc/bc-typecd.def deleted file mode 100644 index fd92cdd9282..00000000000 --- a/gcc/bc-typecd.def +++ /dev/null @@ -1,21 +0,0 @@ -/* Typecodes used by the interpreter and their related - machine modes and types. - - The last argument is used for retrieving the given - type from a varargs list. Due to a bug in varargs, - the type has to be the generic machine type of - larger. */ - -DEFTYPECODE (QIcode, "QI", QImode, SItype) -DEFTYPECODE (QUcode, "QU", QImode, SUtype) -DEFTYPECODE (HIcode, "HI", HImode, SItype) -DEFTYPECODE (HUcode, "HU", HImode, SUtype) -DEFTYPECODE (SIcode, "SI", SImode, SItype) -DEFTYPECODE (SUcode, "SU", SImode, SUtype) -DEFTYPECODE (DIcode, "DI", DImode, DItype) -DEFTYPECODE (DUcode, "DU", DImode, DUtype) -DEFTYPECODE (SFcode, "SF", SFmode, SFtype) -DEFTYPECODE (DFcode, "DF", DFmode, DFtype) -DEFTYPECODE (XFcode, "XF", XFmode, XFtype) -DEFTYPECODE (Pcode, "P", PSImode, Ptype) -DEFTYPECODE (Tcode, "T", SImode, SItype) diff --git a/gcc/bc-typecd.h b/gcc/bc-typecd.h deleted file mode 100644 index 2dcea0e08f5..00000000000 --- a/gcc/bc-typecd.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Typecode definitions for Bytecode Interpreter. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#ifndef TYPECODE_H -#define TYPECODE_H - -enum typecode -{ -#define DEFTYPECODE(CODE, NAME, MACHMODE, TYPE) CODE, -#include "bc-typecd.def" -#undef DEFTYPECODE - - LAST_AND_UNUSED_TYPECODE -}; - -/* Determine if a given type is integer. */ -#define TYPECODE_INTEGER_P(TYPECODE) ((int) (TYPECODE) < (int) SFcode) - -/* Determine if a given type is unsigned. */ -#define TYPECODE_UNSIGNED_P(TYPECODE) \ - (TYPECODE_INTEGER_P(TYPECODE) && (int) (TYPECODE) & 1) - -/* Determine if a given type is signed. */ -#define TYPECODE_SIGNED_P(TYPECODE) \ - (TYPECODE_INTEGER_P(TYPECODE) && !((int) (TYPECODE) & 1)) - -/* Determine if a given type is floating. */ -#define TYPECODE_FLOAT_P(TYPECODE) \ - ((int) (TYPECODE) < (int) Pcode && !TYPECODE_INTEGER_P(TYPECODE)) - -/* Determine if the given type is arithmetic. */ -#define TYPECODE_ARITH_P(TYPECODE) \ - (TYPECODE_INTEGER_P(TYPECODE) || TYPECODE_FLOAT_P(TYPECODE)) - -#define NUM_TYPECODES ((int) LAST_AND_UNUSED_TYPECODE) - -#endif diff --git a/gcc/bi-arity.c b/gcc/bi-arity.c deleted file mode 100644 index ea1f3e1de08..00000000000 --- a/gcc/bi-arity.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Bytecode Interpreter utility to generate arity table. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -#include -#include "hconfig.h" -#include "bi-defs.h" - -int -length (n) - struct node *n; -{ - int k; - - for (k = 0; n; n = n->next) - ++k; - return k; -} - -int -main () -{ - struct def *d; - struct variation *v; - struct node *n; - - yyparse (); - reverse (); - - for (d = defs; d; d = d->next) - for (v = d->variations; v; v = v->next) - { - printf ("{ %d, %d, %d, {", length (v->inputs), - length (v->outputs), length (v->literals)); - for (n = v->literals; n; n = n->next) - printf ("(char) %scode, ", n->text); - if (v->literals == 0) - printf ("0"); - printf ("}},\n"); - } - - fflush (stdout); - exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); - /* NOTREACHED */ - return 0; -} - -/* Safely allocate NBYTES bytes of memory. Returns pointer to block of - memory. */ - -char * -xmalloc (nbytes) - int nbytes; -{ - char *tmp = (char *) malloc (nbytes); - - if (!tmp) - { - fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes); - exit (FATAL_EXIT_CODE); - } - - return tmp; -} - -/* More 'friendly' abort that prints the line and file. - config.h can #define abort fancy_abort if you like that sort of thing. */ - -void -fancy_abort () -{ - fprintf (stderr, "Internal gcc abort.\n"); - exit (FATAL_EXIT_CODE); -} diff --git a/gcc/bi-defs.h b/gcc/bi-defs.h deleted file mode 100644 index 868312a847d..00000000000 --- a/gcc/bi-defs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Definitions for Bytecode Interpreter. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -struct node -{ - char *text; - struct node *next; -}; - -struct variation -{ - char *name; - int code; - struct node *inputs; - struct node *outputs; - struct node *literals; - struct variation *next; -}; - -struct def -{ - char *basename; - char *template; - struct variation *variations; - struct def *next; -}; - -extern struct def *defs; -extern int ndefs; -extern void reverse(); diff --git a/gcc/bi-lexer.c b/gcc/bi-lexer.c deleted file mode 100644 index 0ec0b1d56d3..00000000000 --- a/gcc/bi-lexer.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Lexer for scanner of bytecode definition file. - Copyright (C) 1993, 1995 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include -#include "hconfig.h" -#include "bi-parser.h" - - -/* Safely allocate NBYTES bytes of memory. Returns pointer to block of - memory. */ - -static char * -xmalloc (nbytes) - int nbytes; -{ - char *tmp = (char *) malloc (nbytes); - - if (!tmp) - { - fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes); - exit (FATAL_EXIT_CODE); - } - - return tmp; -} - - -/* Safely reallocate BLOCK so its size becomes NBYTES. - The block returned may be different from the one supplied. */ - -static char * -xrealloc (block, nbytes) - char *block; - int nbytes; -{ - char *tmp = (block - ? (char *) realloc (block, nbytes) - : (char *) malloc (nbytes)); - - if (!tmp) - { - fprintf (stderr, "can't reallocate %d bytes (out of virtual memory)\n", nbytes); - exit (FATAL_EXIT_CODE); - } - - return tmp; -} - - -/* Scan for string token on standard input. A string is, for our - purposes here, a sequence of characters that starts with the regexp - ``[^ #\t\n(),]'' and is then followed by the regexp ``[^#(),]*''. Any - character is accepted if preceded by a backslash, "\\". It is assumed - that the first character has already been checked by the main loop. */ - -static char * -scan_string () -{ - char *buffer = NULL; - char *point = NULL; - int buffer_size = 0; - int c; - - while ((c = getc (stdin)) != EOF - && c != '#' && c != '(' && c != ')' && c != ',') - { - /* Extend buffer, if necessary (minus two so there's room for the NUL - trailer as well as another character if this one is a backslash). */ - if (!buffer_size || (point - buffer >= buffer_size-2)) - { - int previous_point_index = point - buffer; - - buffer_size = (!buffer_size ? 32 : buffer_size * 2); - if (!buffer) - buffer = xmalloc (buffer_size); - else - buffer = xrealloc (buffer, buffer_size); - - point = buffer + previous_point_index; - } - *point++ = c & 0xff; - - if (c == '\\') - { - c = getc (stdin); - - /* Catch special case: backslash at end of file */ - if (c == EOF) - break; - - *point++ = c; - } - } - *point = 0; - - if (c != EOF) - ungetc (c, stdin); - - return buffer; -} - - -int -yylex () -{ - int c; - char *token; - - - /* First char determines what token we're looking at */ - for (;;) - { - c = getc (stdin); - - switch (c) - { - case EOF: - return 0; - - case ' ': - case '\t': - case '\n': - /* Ignore whitespace */ - continue; - - case '#': - /* Comments advance to next line */ - while ((c = getc (stdin)) != '\n' && c != EOF); - continue; - - default: - if (c != '(' && c != ')' && c != '\\' && c != ',') - { - ungetc (c, stdin); - yylval.string = scan_string (); - - /* Check if string is "define_operator"; if so, return - a DEFOP token instead. */ - if (!strcmp (yylval.string, "define_operator")) - { - free (yylval.string); - yylval.string = 0; - return DEFOP; - } - return STRING; - } - return c & 0xff; - } - } -} diff --git a/gcc/bi-opcode.c b/gcc/bi-opcode.c deleted file mode 100644 index 795bb6fb275..00000000000 --- a/gcc/bi-opcode.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Utility to generate opcode list from bytecode definition. - Copyright (C) 1993, 1994 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include -#include "hconfig.h" -#include "bi-defs.h" - -int -main(argc, argv) - int argc; - char **argv; -{ - struct def *d; - struct variation *v; - int i; - - yyparse(); - reverse(); - - - printf ("/* This file is automatically generated from bytecode.def,\n"); - printf ("do not make any changes here. Instead edit bytecode.def. */\n\n"); - printf ("enum bytecode_opcode\n{"); - - i = 0; - for (d = defs; d; d = d->next) - for (v = d->variations; v; v = v->next) - { - printf (" %s%s,\n", d->basename, v->name); - ++i; - } - - puts (" LAST_AND_UNUSED_OPCODE\n};"); - - if (i > 256) - fprintf (stderr, "%s: warning, number of opcodes is %d\n", *argv, i); - else - fprintf (stderr, "(Number of opcodes is %d)\n", i); - - fflush (stdout); - exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); - /* NOTREACHED */ - return 0; -} - -/* Safely allocate NBYTES bytes of memory. Returns pointer to block of - memory. */ - -char * -xmalloc (nbytes) - int nbytes; -{ - char *tmp = (char *) malloc (nbytes); - - if (!tmp) - { - fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes); - exit (FATAL_EXIT_CODE); - } - - return tmp; -} - -/* More 'friendly' abort that prints the line and file. - config.h can #define abort fancy_abort if you like that sort of thing. */ - -void -fancy_abort () -{ - fprintf (stderr, "Internal gcc abort.\n"); - exit (FATAL_EXIT_CODE); -} diff --git a/gcc/bi-opname.c b/gcc/bi-opname.c deleted file mode 100644 index 2f41dd27dbc..00000000000 --- a/gcc/bi-opname.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Utility to generate opcode name list from bytecode definition file. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include -#include "hconfig.h" -#include "bi-defs.h" - -int -main() -{ - struct def *d; - struct variation *v; - - yyparse(); - reverse(); - - for (d = defs; d; d = d->next) - for (v = d->variations; v; v = v->next) - printf("\"%s%s\",\n", d->basename, v->name); - - fflush (stdout); - exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); - /* NOTREACHED */ - return 0; -} - -/* Safely allocate NBYTES bytes of memory. Returns pointer to block of - memory. */ - -char * -xmalloc (nbytes) - int nbytes; -{ - char *tmp = (char *) malloc (nbytes); - - if (!tmp) - { - fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes); - exit (FATAL_EXIT_CODE); - } - - return tmp; -} - -/* More 'friendly' abort that prints the line and file. - config.h can #define abort fancy_abort if you like that sort of thing. */ - -void -fancy_abort () -{ - fprintf (stderr, "Internal gcc abort.\n"); - exit (FATAL_EXIT_CODE); -} diff --git a/gcc/bi-parser.c b/gcc/bi-parser.c deleted file mode 100644 index 9f6f2b02e3c..00000000000 --- a/gcc/bi-parser.c +++ /dev/null @@ -1,980 +0,0 @@ - -/* A Bison parser, made from bi-parser.y with Bison version GNU Bison version 1.24 - */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define DEFOP 258 -#define STRING 259 - -#line 22 "bi-parser.y" - - -#include -#include "hconfig.h" -#include "bi-defs.h" - -extern char yytext[]; -extern int yyleng; - - -/* Chain of all defs built by the parser. */ -struct def *defs; -int ndefs; - -static struct node *makenode (); -static struct variation *makevar (); -static struct def *makedef (); - -void yyerror (); - - -#line 44 "bi-parser.y" -typedef union -{ - char *string; - struct def *def; - struct variation *variation; - struct node *node; -} YYSTYPE; - -#ifndef YYLTYPE -typedef - struct yyltype - { - int timestamp; - int first_line; - int first_column; - int last_line; - int last_column; - char *text; - } - yyltype; - -#define YYLTYPE yyltype -#endif - -#include - -#ifndef __cplusplus -#ifndef __STDC__ -#define const -#endif -#endif - - - -#define YYFINAL 39 -#define YYFLAG -32768 -#define YYNTBASE 8 - -#define YYTRANSLATE(x) ((unsigned)(x) <= 259 ? yytranslate[x] : 17) - -static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, - 7, 2, 2, 6, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 2, 3, 4 -}; - -#if YYDEBUG != 0 -static const short yyprhs[] = { 0, - 0, 2, 4, 7, 18, 20, 24, 28, 34, 42, - 52, 53, 55, 59, 60, 62, 66 -}; - -static const short yyrhs[] = { 9, - 0, 10, 0, 9, 10, 0, 3, 5, 4, 6, - 13, 6, 5, 11, 7, 7, 0, 12, 0, 11, - 6, 12, 0, 5, 13, 7, 0, 5, 13, 6, - 14, 7, 0, 5, 13, 6, 14, 6, 14, 7, - 0, 5, 13, 6, 14, 6, 14, 6, 14, 7, - 0, 0, 4, 0, 5, 15, 7, 0, 0, 16, - 0, 16, 6, 15, 0, 4, 0 -}; - -#endif - -#if YYDEBUG != 0 -static const short yyrline[] = { 0, - 60, 65, 67, 71, 76, 78, 82, 85, 87, 89, - 93, 95, 98, 101, 105, 108, 112 -}; - -static const char * const yytname[] = { "$","error","$undefined.","DEFOP", -"STRING","'('","','","')'","top","defs","def","variations","variation","opt_string", -"list","items","item","" -}; -#endif - -static const short yyr1[] = { 0, - 8, 9, 9, 10, 11, 11, 12, 12, 12, 12, - 13, 13, 14, 14, 15, 15, 16 -}; - -static const short yyr2[] = { 0, - 1, 1, 2, 10, 1, 3, 3, 5, 7, 9, - 0, 1, 3, 0, 1, 3, 1 -}; - -static const short yydefact[] = { 0, - 0, 1, 2, 0, 3, 0, 11, 12, 0, 0, - 0, 11, 0, 5, 0, 0, 0, 14, 7, 6, - 4, 0, 0, 17, 0, 15, 14, 8, 13, 0, - 0, 16, 14, 9, 0, 10, 0, 0, 0 -}; - -static const short yydefgoto[] = { 37, - 2, 3, 13, 14, 9, 23, 25, 26 -}; - -static const short yypact[] = { 2, - 6, 2,-32768, 8,-32768, 7, 10,-32768, 9, 11, - 12, 10, -5,-32768, -3, 12, 13, 14,-32768,-32768, --32768, 17, 1,-32768, 15, 18, 14,-32768,-32768, 17, - 3,-32768, 14,-32768, 16,-32768, 25, 26,-32768 -}; - -static const short yypgoto[] = {-32768, --32768, 27,-32768, 19, 20, -27, -12,-32768 -}; - - -#define YYLAST 35 - - -static const short yytable[] = { 31, - 16, 17, 18, 19, 1, 35, 27, 28, 33, 34, - 4, 6, 7, 8, 10, 11, 12, 32, 22, 21, - 24, 29, 36, 30, 38, 39, 0, 0, 5, 0, - 0, 15, 0, 0, 20 -}; - -static const short yycheck[] = { 27, - 6, 7, 6, 7, 3, 33, 6, 7, 6, 7, - 5, 4, 6, 4, 6, 5, 5, 30, 5, 7, - 4, 7, 7, 6, 0, 0, -1, -1, 2, -1, - -1, 12, -1, -1, 16 -}; -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/local/share/bison.simple" - -/* Skeleton output parser for bison, - Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -#ifndef alloca -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not GNU C. */ -#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) -#include -#else /* not sparc */ -#if defined (MSDOS) && !defined (__TURBOC__) -#include -#else /* not MSDOS, or __TURBOC__ */ -#if defined(_AIX) -#include - #pragma alloca -#else /* not MSDOS, __TURBOC__, or _AIX */ -#ifdef __hpux -#ifdef __cplusplus -extern "C" { -void *alloca (unsigned int); -}; -#else /* not __cplusplus */ -void *alloca (); -#endif /* not __cplusplus */ -#endif /* __hpux */ -#endif /* not _AIX */ -#endif /* not MSDOS, or __TURBOC__ */ -#endif /* not sparc. */ -#endif /* not GNU C. */ -#endif /* alloca not defined. */ - -/* This is the parser code that is written into each bison parser - when the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* Note: there must be only one dollar sign in this file. - It is replaced by the list of actions, each action - as one case of the switch. */ - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT return(0) -#define YYABORT return(1) -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. - This remains here temporarily to ease the - transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(token, value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { yychar = (token), yylval = (value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { yyerror ("syntax error: cannot back up"); YYERROR; } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -#ifndef YYPURE -#define YYLEX yylex() -#endif - -#ifdef YYPURE -#ifdef YYLSP_NEEDED -#ifdef YYLEX_PARAM -#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) -#else -#define YYLEX yylex(&yylval, &yylloc) -#endif -#else /* not YYLSP_NEEDED */ -#ifdef YYLEX_PARAM -#define YYLEX yylex(&yylval, YYLEX_PARAM) -#else -#define YYLEX yylex(&yylval) -#endif -#endif /* not YYLSP_NEEDED */ -#endif - -/* If nonreentrant, generate the variables here */ - -#ifndef YYPURE - -int yychar; /* the lookahead symbol */ -YYSTYPE yylval; /* the semantic value of the */ - /* lookahead symbol */ - -#ifdef YYLSP_NEEDED -YYLTYPE yylloc; /* location data for the lookahead */ - /* symbol */ -#endif - -int yynerrs; /* number of parse errors so far */ -#endif /* not YYPURE */ - -#if YYDEBUG != 0 -int yydebug; /* nonzero means print parse trace */ -/* Since this is uninitialized, it does not stop multiple parsers - from coexisting. */ -#endif - -/* YYINITDEPTH indicates the initial size of the parser's stacks */ - -#ifndef YYINITDEPTH -#define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH is the maximum size the stacks can grow to - (effective only if the built-in stack extension method is used). */ - -#if YYMAXDEPTH == 0 -#undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -#define YYMAXDEPTH 10000 -#endif - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -int yyparse (void); -#endif - -#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ -#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) -#else /* not GNU C or C++ */ -#ifndef __cplusplus - -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_memcpy (from, to, count) - char *from; - char *to; - int count; -{ - register char *f = from; - register char *t = to; - register int i = count; - - while (i-- > 0) - *t++ = *f++; -} - -#else /* __cplusplus */ - -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_memcpy (char *from, char *to, int count) -{ - register char *f = from; - register char *t = to; - register int i = count; - - while (i-- > 0) - *t++ = *f++; -} - -#endif -#endif - -#line 192 "/usr/local/share/bison.simple" - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -#else -#define YYPARSE_PARAM -#define YYPARSE_PARAM_DECL -#endif - -int -yyparse(YYPARSE_PARAM) - YYPARSE_PARAM_DECL -{ - register int yystate; - register int yyn; - register short *yyssp; - register YYSTYPE *yyvsp; - int yyerrstatus; /* number of tokens to shift before error messages enabled */ - int yychar1 = 0; /* lookahead token as an internal (translated) token number */ - - short yyssa[YYINITDEPTH]; /* the state stack */ - YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ - - short *yyss = yyssa; /* refer to the stacks thru separate pointers */ - YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ - -#ifdef YYLSP_NEEDED - YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; - -#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -#define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - int yystacksize = YYINITDEPTH; - -#ifdef YYPURE - int yychar; - YYSTYPE yylval; - int yynerrs; -#ifdef YYLSP_NEEDED - YYLTYPE yylloc; -#endif -#endif - - YYSTYPE yyval; /* the variable used to return */ - /* semantic values from the action */ - /* routines */ - - int yylen; - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Starting parse\n"); -#endif - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss - 1; - yyvsp = yyvs; -#ifdef YYLSP_NEEDED - yylsp = yyls; -#endif - -/* Push a new state, which is found in yystate . */ -/* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. */ -yynewstate: - - *++yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Give user a chance to reallocate the stack */ - /* Use copies of these so that the &'s don't force the real ones into memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; -#ifdef YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; -#endif - - /* Get the current used size of the three stacks, in elements. */ - int size = yyssp - yyss + 1; - -#ifdef yyoverflow - /* Each stack pointer address is followed by the size of - the data in use in that stack, in bytes. */ -#ifdef YYLSP_NEEDED - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yyls1, size * sizeof (*yylsp), - &yystacksize); -#else - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yystacksize); -#endif - - yyss = yyss1; yyvs = yyvs1; -#ifdef YYLSP_NEEDED - yyls = yyls1; -#endif -#else /* no yyoverflow */ - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - { - yyerror("parser stack overflow"); - return 2; - } - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); - __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); - yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); - __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); -#ifdef YYLSP_NEEDED - yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); - __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); -#endif -#endif /* no yyoverflow */ - - yyssp = yyss + size - 1; - yyvsp = yyvs + size - 1; -#ifdef YYLSP_NEEDED - yylsp = yyls + size - 1; -#endif - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Stack size increased to %d\n", yystacksize); -#endif - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Entering state %d\n", yystate); -#endif - - goto yybackup; - yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Reading a token: "); -#endif - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Now at end of input.\n"); -#endif - } - else - { - yychar1 = YYTRANSLATE(yychar); - -#if YYDEBUG != 0 - if (yydebug) - { - fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise meaning - of a token, for further debugging info. */ -#ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -#endif - fprintf (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); -#endif - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* count tokens shifted since error; after three, turn off error status. */ - if (yyerrstatus) yyerrstatus--; - - yystate = yyn; - goto yynewstate; - -/* Do the default action for the current state. */ -yydefault: - - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - -/* Do a reduction. yyn is the number of a rule to reduce with. */ -yyreduce: - yylen = yyr2[yyn]; - if (yylen > 0) - yyval = yyvsp[1-yylen]; /* implement default value of the action */ - -#if YYDEBUG != 0 - if (yydebug) - { - int i; - - fprintf (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) - fprintf (stderr, "%s ", yytname[yyrhs[i]]); - fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - - switch (yyn) { - -case 1: -#line 62 "bi-parser.y" -{ defs = yyvsp[0].def; ; - break;} -case 3: -#line 68 "bi-parser.y" -{ yyvsp[0].def->next = yyvsp[-1].def; yyval.def = yyvsp[0].def; ; - break;} -case 4: -#line 73 "bi-parser.y" -{ yyval.def = makedef (yyvsp[-7].string, yyvsp[-5].string, yyvsp[-2].variation); ; - break;} -case 6: -#line 79 "bi-parser.y" -{ yyvsp[0].variation->next = yyvsp[-2].variation; yyval.variation = yyvsp[0].variation; ; - break;} -case 7: -#line 84 "bi-parser.y" -{ yyval.variation = makevar (yyvsp[-1].string, (struct node *) NULL, (struct node *) NULL, (struct node *) NULL); ; - break;} -case 8: -#line 86 "bi-parser.y" -{ yyval.variation = makevar (yyvsp[-3].string, yyvsp[-1].node, (struct node *) NULL, (struct node *) NULL); ; - break;} -case 9: -#line 88 "bi-parser.y" -{ yyval.variation = makevar (yyvsp[-5].string, yyvsp[-3].node, yyvsp[-1].node, (struct node *) NULL); ; - break;} -case 10: -#line 90 "bi-parser.y" -{ yyval.variation = makevar (yyvsp[-7].string, yyvsp[-5].node, yyvsp[-3].node, yyvsp[-1].node); ; - break;} -case 11: -#line 94 "bi-parser.y" -{ yyval.string = ""; ; - break;} -case 12: -#line 95 "bi-parser.y" -{ yyval.string = yyvsp[0].string; ; - break;} -case 13: -#line 100 "bi-parser.y" -{ yyval.node = yyvsp[-1].node; ; - break;} -case 14: -#line 102 "bi-parser.y" -{ yyval.node = NULL; ; - break;} -case 16: -#line 109 "bi-parser.y" -{ yyvsp[-2].node->next = yyvsp[0].node; yyval.node = yyvsp[-2].node; ; - break;} -case 17: -#line 114 "bi-parser.y" -{ yyval.node = makenode (yyvsp[0].string); ; - break;} -} - /* the action file gets copied in in place of this dollarsign */ -#line 487 "/usr/local/share/bison.simple" - - yyvsp -= yylen; - yyssp -= yylen; -#ifdef YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG != 0 - if (yydebug) - { - short *ssp1 = yyss - 1; - fprintf (stderr, "state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; - -#ifdef YYLSP_NEEDED - yylsp++; - if (yylen == 0) - { - yylsp->first_line = yylloc.first_line; - yylsp->first_column = yylloc.first_column; - yylsp->last_line = (yylsp-1)->last_line; - yylsp->last_column = (yylsp-1)->last_column; - yylsp->text = 0; - } - else - { - yylsp->last_line = (yylsp+yylen-1)->last_line; - yylsp->last_column = (yylsp+yylen-1)->last_column; - } -#endif - - /* Now "shift" the result of the reduction. - Determine what state that goes to, - based on the state we popped back to - and the rule number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - -yyerrlab: /* here on detecting error */ - - if (! yyerrstatus) - /* If not already recovering from an error, report this error. */ - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - int size = 0; - char *msg; - int x, count; - - count = 0; - /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - size += strlen(yytname[x]) + 15, count++; - msg = (char *) malloc(size + 15); - if (msg != 0) - { - strcpy(msg, "parse error"); - - if (count < 5) - { - count = 0; - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - { - strcat(msg, count == 0 ? ", expecting `" : " or `"); - strcat(msg, yytname[x]); - strcat(msg, "'"); - count++; - } - } - yyerror(msg); - free(msg); - } - else - yyerror ("parse error; also virtual memory exceeded"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror("parse error"); - } - - goto yyerrlab1; -yyerrlab1: /* here on error raised explicitly by an action */ - - if (yyerrstatus == 3) - { - /* if just tried and failed to reuse lookahead token after an error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); -#endif - - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token - after shifting the error token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - -yyerrdefault: /* current state does not do anything special for the error token. */ - -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ - if (yyn) goto yydefault; -#endif - -yyerrpop: /* pop the current state because it cannot handle the error token */ - - if (yyssp == yyss) YYABORT; - yyvsp--; - yystate = *--yyssp; -#ifdef YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG != 0 - if (yydebug) - { - short *ssp1 = yyss - 1; - fprintf (stderr, "Error: state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif - -yyerrhandle: - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting error token, "); -#endif - - *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; -} -#line 117 "bi-parser.y" - - -static struct node * -makenode (s) - char *s; -{ - struct node *n; - - n = (struct node *) malloc (sizeof (struct node)); - n->text = s; - n->next = NULL; - return n; -} - -static struct variation * -makevar (name, inputs, outputs, literals) - char *name; - struct node *inputs, *outputs, *literals; -{ - struct variation *v; - - v = (struct variation *) malloc (sizeof (struct variation)); - v->name = name; - v->code = ndefs++; - v->inputs = inputs; - v->outputs = outputs; - v->literals = literals; - v->next = NULL; - return v; -} - -static struct def * -makedef (name, template, vars) - char *name, *template; - struct variation *vars; -{ - struct def *d; - - d = (struct def *) malloc (sizeof (struct def)); - d->basename = name; - d->template = template; - d->variations = vars; - d->next = NULL; - return d; -} - -void -yyerror (s) - char *s; -{ - fprintf (stderr, "syntax error in input\n"); - exit (FATAL_EXIT_CODE); -} diff --git a/gcc/bi-parser.h b/gcc/bi-parser.h deleted file mode 100644 index 5beb8628f08..00000000000 --- a/gcc/bi-parser.h +++ /dev/null @@ -1,12 +0,0 @@ -typedef union -{ - char *string; - struct def *def; - struct variation *variation; - struct node *node; -} YYSTYPE; -#define DEFOP 258 -#define STRING 259 - - -extern YYSTYPE yylval; diff --git a/gcc/bi-parser.y b/gcc/bi-parser.y deleted file mode 100644 index 0a03d0f05ad..00000000000 --- a/gcc/bi-parser.y +++ /dev/null @@ -1,169 +0,0 @@ -/* Bytecode definition file parser. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -%{ - -#include -#include "hconfig.h" -#include "bi-defs.h" - -extern char yytext[]; -extern int yyleng; - - -/* Chain of all defs built by the parser. */ -struct def *defs; -int ndefs; - -static struct node *makenode (); -static struct variation *makevar (); -static struct def *makedef (); - -void yyerror (); - -%} - -%union -{ - char *string; - struct def *def; - struct variation *variation; - struct node *node; -} - -%token DEFOP STRING -%type opt_string -%type defs def -%type variations variation -%type list items item - -%% - -top: - defs - { defs = $1; } - ; - -defs: - def - | defs def - { $2->next = $1; $$ = $2; } - ; - -def: - DEFOP '(' STRING ',' opt_string ',' '(' variations ')' ')' - { $$ = makedef ($3, $5, $8); } - ; - -variations: - variation - | variations ',' variation - { $3->next = $1; $$ = $3; } - ; - -variation: - '(' opt_string ')' - { $$ = makevar ($2, (struct node *) NULL, (struct node *) NULL, (struct node *) NULL); } - | '(' opt_string ',' list ')' - { $$ = makevar ($2, $4, (struct node *) NULL, (struct node *) NULL); } - | '(' opt_string ',' list ',' list ')' - { $$ = makevar ($2, $4, $6, (struct node *) NULL); } - | '(' opt_string ',' list ',' list ',' list ')' - { $$ = makevar ($2, $4, $6, $8); } - ; - -opt_string: - /* empty */ { $$ = ""; } - | STRING { $$ = $1; } - ; - -list: - '(' items ')' - { $$ = $2; } - | /* empty */ - { $$ = NULL; } - ; - -items: - item - /* Note right recursion. */ - | item ',' items - { $1->next = $3; $$ = $1; } - ; - -item: - STRING - { $$ = makenode ($1); } - ; - -%% - -static struct node * -makenode (s) - char *s; -{ - struct node *n; - - n = (struct node *) malloc (sizeof (struct node)); - n->text = s; - n->next = NULL; - return n; -} - -static struct variation * -makevar (name, inputs, outputs, literals) - char *name; - struct node *inputs, *outputs, *literals; -{ - struct variation *v; - - v = (struct variation *) malloc (sizeof (struct variation)); - v->name = name; - v->code = ndefs++; - v->inputs = inputs; - v->outputs = outputs; - v->literals = literals; - v->next = NULL; - return v; -} - -static struct def * -makedef (name, template, vars) - char *name, *template; - struct variation *vars; -{ - struct def *d; - - d = (struct def *) malloc (sizeof (struct def)); - d->basename = name; - d->template = template; - d->variations = vars; - d->next = NULL; - return d; -} - -void -yyerror (s) - char *s; -{ - fprintf (stderr, "syntax error in input\n"); - exit (FATAL_EXIT_CODE); -} diff --git a/gcc/bi-reverse.c b/gcc/bi-reverse.c deleted file mode 100644 index 6a84f827e73..00000000000 --- a/gcc/bi-reverse.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Reverse order of definitions obtained from bytecode definition file. - Copyright (C) 1993 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -#include "hconfig.h" -#include "bi-defs.h" - -void -reverse() -{ - struct def *dp, *d, *dn; - struct variation *vp, *v, *vn; - - dp = defs; - if (dp) - { - vp = dp->variations; - if (vp) - { - for (v = vp->next, vp->next = 0; v; vp = v, v = vn) - { - vn = v->next; - v->next = vp; - } - dp->variations = vp; - } - for (d = dp->next, dp->next = 0; d; dp = d, d = dn) - { - vp = d->variations; - if (vp) - { - for (v = vp->next, vp->next = 0; v; vp = v, v = vn) - { - vn = v->next; - v->next = vp; - } - d->variations = vp; - } - dn = d->next; - d->next = dp; - } - defs = dp; - } -} diff --git a/gcc/bi-run.h b/gcc/bi-run.h deleted file mode 100644 index dc9192f78b8..00000000000 --- a/gcc/bi-run.h +++ /dev/null @@ -1,159 +0,0 @@ -/* Definitions for Bytecode Interpreter. - Copyright (C) 1993, 1994 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#define MAXLITERALS 5 - -struct arityvec -{ - char ninputs; - char noutputs; - char nliterals; - char literals[MAXLITERALS]; -}; - -struct argtype -{ - int modealign; /* Argument mode:alignment */ - int size; /* Argument size, in bytes */ -}; - -struct callinfo -{ - int nargs; /* Number of arguments in call */ - struct argtype retvaltype; /* Type of return value */ - struct argtype argtypes[1]; /* Argument types */ -}; - -/* Structure describing a bytecode function. If this changes, we also - need to change expand_function_end () in bc-trans.c */ -struct bytecode -{ - int stacksize; /* Depth required of evaluation stack. */ - int localsize; /* Size in bytes of local variables. */ - unsigned char *pc0; /* Initial program counter. */ - void **ptrlit; /* Vector of (relocatable) pointer literals. */ - struct callinfo *callinfo; /* Vector of procedure call type info. */ -}; - - -#define INTERP_BPC 8 /* Bits per char */ -#define INTERP_BPI \ - (sizeof (int) * INTERP_BPC) /* Bits per int */ - - -#ifndef min -#define min(L, R) ((L) < (R) ? (L) : (R)) -#endif - - -/* bit field operations. */ - -/* Low (high) mask: int with low (high) N bits set */ - -#define LM(N) ((1 << (N)) - 1) -#define HM(N) ((~LM (INTERP_BPI - (N)))) - - -/* Sign-extend SIZE low bits of VALUE to integer (typeof VALUE) - Signed bitfields are loaded from memory by the sxloadBI instruction, - which first retrieves the bitfield with XFIELD and then sign extends - it to an SItype. */ - -#define EXTEND(SIZE, VALUE) \ - ({ SUtype value = (SUtype) (VALUE); \ - (value & (1 << ((SIZE) - 1)) ? value | ~LM (SIZE) : value); }) - - -/* Given OFFSET:SIZE for a bitfield, calculate: - - [1] BYTE_OFFSET = the byte offset of the bit field. - [2] BIT_OFFSET = the bit offset of the bit field (less than INTERP_BPC). - [3] NBYTES = the number of integral bytes in the bit field. - [4] TRAILING_BITS= the number of trailing bits (less than INTERP_BPC). - - - , , , , , (memory bytes) - ---------------- (bitfield) - | | || | | (divisions) - ^ ^ ^ ^ - | | | |__ [4] (bits) - | | |_________ [3] (bytes) - | |_________________ [2] (bits) - |___________________________ [1] (bytes) - - - The above applies to BYTE_LOW_ENDIAN machines. In BYTE_BIG_ENDIAN machines, the - bit numbering is reversed (i.e. bit 0 is the sign bit). - - (All right, so I drew this to keep my tongue in cheek while writing the code below, - not because I'm into ASCII art.) */ - - -#define BI_PARAMS(OFFSET, SIZE, BYTE_OFFSET, BIT_OFFSET, NBYTES, TRAILING_BITS) \ - { BYTE_OFFSET = (OFFSET) / (INTERP_BPC); \ - BIT_OFFSET = (OFFSET) % (INTERP_BPC); \ - NBYTES = ((SIZE) - (INTERP_BPC - (BIT_OFFSET))) / INTERP_BPC; \ - if ((NBYTES) < 0 || ((NBYTES) > 64)) \ - NBYTES = 0; \ - if ((SIZE) + (BIT_OFFSET) <= INTERP_BPC) \ - TRAILING_BITS = 0; \ - else \ - TRAILING_BITS = ((SIZE) - (INTERP_BPC - (BIT_OFFSET))) % INTERP_BPC; } - - -/* SHIFT_IN_BITS retrieves NBITS bits from SOURCE and shifts into - DEST. The bit field starts OFFSET bits into SOURCE. - - OR_IN_BITS copies the NBITS low bits from VALUE into a the bitfield in - DEST offset by OFFSET bits. */ - - -#define SHIFT_IN_BITS(DEST, SOURCE, OFFSET, NBITS) \ - (DEST = ((DEST) << (NBITS)) \ - | (LM ((NBITS)) \ - & ((SOURCE) \ - >> (BYTES_BIG_ENDIAN \ - ? (INTERP_BPC - (OFFSET) - (NBITS)) \ - : (OFFSET))))) - -#define OR_IN_BITS(DEST, VALUE, OFFSET, NBITS) \ - (DEST = ((DEST) & ~(LM ((NBITS)) \ - << (BIG_ENDIAN \ - ? (INTERP_BPC - (OFFSET) - (NBITS)) \ - : (OFFSET))) \ - | (((VALUE) & LM ((NBITS))) \ - << (BIG_ENDIAN \ - ? (INTERP_BPC - (OFFSET) - (NBITS)) \ - : (OFFSET))))) - -/* Procedure call; arguments are a pointer to the function to be called, - a pointer to a place to store the return value, a pointer to a vector - describing the type of procedure call, and the interpreter's stack pointer, - which will point to the first of the arguments at this point. */ - -#define CALL(FUNC, CALLDESC, RETVAL, SP) __call(FUNC, CALLDESC, RETVAL, SP) - - -/* Procedure return; arguments are a pointer to the calldesc for this - function, and a pointer to the place where the value to be returned - may be found. Generally the MACHARGS above contain a machine dependent - cookie that is used to determine where to jump to. */ - -#define PROCRET(CALLDESC, RETVAL) return diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index ad661245641..3a2ba295587 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -53,23 +53,7 @@ Boston, MA 02111-1307, USA. */ #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" - -/* Opcode names */ -#ifdef BCDEBUG_PRINT_CODE -char *opcode_name[] = -{ -#include "bc-opname.h" - -"***END***" -}; -#endif - /* Commonly used modes. */ @@ -1451,11 +1435,8 @@ gen_label_rtx () { register rtx label; - label = (output_bytecode - ? gen_rtx_CODE_LABEL (VOIDmode, 0, bc_get_bytecode_label (), - NULL_RTX, 0, NULL_PTR) - : gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, - NULL_RTX, label_num++, NULL_PTR)); + label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, + NULL_RTX, label_num++, NULL_PTR); LABEL_NUSES (label) = 0; return label; @@ -2937,13 +2918,6 @@ emit_line_note (file, line) char *file; int line; { - if (output_bytecode) - { - /* FIXME: for now we do nothing, but eventually we will have to deal with - debugging information. */ - return 0; - } - emit_filename = file; emit_lineno = line; diff --git a/gcc/expr.c b/gcc/expr.c index 05af3dac724..ef2666877a9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -39,13 +39,6 @@ Boston, MA 02111-1307, USA. */ #include "typeclass.h" #include "defaults.h" -#include "bytecode.h" -#include "bc-opcode.h" -#include "bc-typecd.h" -#include "bc-optab.h" -#include "bc-emit.h" - - #define CEIL(x,y) (((x) + (y) - 1) / (y)) /* Decide whether a function's arguments should be processed @@ -197,19 +190,6 @@ static rtx expand_builtin_apply_args PROTO((void)); static rtx expand_builtin_apply PROTO((rtx, rtx, rtx)); static void expand_builtin_return PROTO((rtx)); static rtx expand_increment PROTO((tree, int, int)); -void bc_expand_increment PROTO((struct increment_operator *, tree)); -rtx bc_allocate_local PROTO((int, int)); -void bc_store_memory PROTO((tree, tree)); -tree bc_expand_component_address PROTO((tree)); -tree bc_expand_address PROTO((tree)); -void bc_expand_constructor PROTO((tree)); -void bc_adjust_stack PROTO((int)); -tree bc_canonicalize_array_ref PROTO((tree)); -void bc_load_memory PROTO((tree, tree)); -void bc_load_externaddr PROTO((rtx)); -void bc_load_externaddr_id PROTO((tree, int)); -void bc_load_localaddr PROTO((rtx)); -void bc_load_parmaddr PROTO((rtx)); static void preexpand_calls PROTO((tree)); static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx)); void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx)); @@ -260,33 +240,6 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES]; #define OUTGOING_REGNO(IN) (IN) #endif -/* Maps used to convert modes to const, load, and store bytecodes. */ -enum bytecode_opcode mode_to_const_map[MAX_MACHINE_MODE]; -enum bytecode_opcode mode_to_load_map[MAX_MACHINE_MODE]; -enum bytecode_opcode mode_to_store_map[MAX_MACHINE_MODE]; - -/* Initialize maps used to convert modes to const, load, and store - bytecodes. */ - -void -bc_init_mode_to_opcode_maps () -{ - int mode; - - for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++) - mode_to_const_map[mode] - = mode_to_load_map[mode] - = mode_to_store_map[mode] = neverneverland; - -#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \ - mode_to_const_map[(int) SYM] = CONST; \ - mode_to_load_map[(int) SYM] = LOAD; \ - mode_to_store_map[(int) SYM] = STORE; - -#include "modemap.def" -#undef DEF_MODEMAP -} - /* This is run once per compilation to set up which modes can be used directly in memory and to initialize the block move optab. */ @@ -2899,22 +2852,6 @@ expand_assignment (to, from, want_value, suggest_reg) return want_value ? result : NULL_RTX; } - if (output_bytecode) - { - tree dest_innermost; - - bc_expand_expr (from); - bc_emit_instruction (duplicate); - - dest_innermost = bc_expand_address (to); - - /* Can't deduce from TYPE that we're dealing with a bitfield, so - take care of it here. */ - - bc_store_memory (TREE_TYPE (to), dest_innermost); - return NULL; - } - /* Assignment of a structure component needs special treatment if the structure component's rtx is not simply a MEM. Assignment of an array element at a constant index, and assignment of @@ -4901,7 +4838,6 @@ expand_expr (exp, target, tmode, modifier) /* Use subtarget as the target for operand 0 of a binary operation. */ rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); rtx original_target = target; - /* Maybe defer this until sure not doing bytecode? */ int ignore = (target == const0_rtx || ((code == NON_LVALUE_EXPR || code == NOP_EXPR || code == CONVERT_EXPR || code == REFERENCE_EXPR @@ -4918,12 +4854,6 @@ expand_expr (exp, target, tmode, modifier) else ro_modifier = EXPAND_NORMAL; - if (output_bytecode && modifier != EXPAND_INITIALIZER) - { - bc_expand_expr (exp); - return NULL; - } - /* Don't use hard regs as subtargets, because the combiner can only handle pseudo regs. */ if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER) @@ -7430,4647 +7360,3394 @@ expand_expr (exp, target, tmode, modifier) } -/* Emit bytecode to evaluate the given expression EXP to the stack. */ + +/* Return the alignment in bits of EXP, a pointer valued expression. + But don't return more than MAX_ALIGN no matter what. + The alignment returned is, by default, the alignment of the thing that + EXP points to (if it is not a POINTER_TYPE, 0 is returned). + + Otherwise, look at the expression to see if we can do better, i.e., if the + expression is actually pointing at an object whose alignment is tighter. */ -void -bc_expand_expr (exp) - tree exp; +static int +get_pointer_alignment (exp, max_align) + tree exp; + unsigned max_align; { - enum tree_code code; - tree type, arg0; - rtx r; - struct binary_operator *binoptab; - struct unary_operator *unoptab; - struct increment_operator *incroptab; - struct bc_label *lab, *lab1; - enum bytecode_opcode opcode; - - - code = TREE_CODE (exp); - - switch (code) + unsigned align, inner; + + if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) + return 0; + + align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); + align = MIN (align, max_align); + + while (1) { - case PARM_DECL: - - if (DECL_RTL (exp) == 0) + switch (TREE_CODE (exp)) { - error_with_decl (exp, "prior parameter's size depends on `%s'"); - return; - } - - bc_load_parmaddr (DECL_RTL (exp)); - bc_load_memory (TREE_TYPE (exp), exp); - - return; - - case VAR_DECL: - - if (DECL_RTL (exp) == 0) - abort (); - -#if 0 - if (BYTECODE_LABEL (DECL_RTL (exp))) - bc_load_externaddr (DECL_RTL (exp)); - else - bc_load_localaddr (DECL_RTL (exp)); -#endif - if (TREE_PUBLIC (exp)) - bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), - BYTECODE_BC_LABEL (DECL_RTL (exp))->offset); - else - bc_load_localaddr (DECL_RTL (exp)); - - bc_load_memory (TREE_TYPE (exp), exp); - return; - - case INTEGER_CST: - -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, " [%x]\n", TREE_INT_CST_LOW (exp)); -#endif - bc_emit_instruction (mode_to_const_map[(int) (DECL_BIT_FIELD (exp) - ? SImode - : TYPE_MODE (TREE_TYPE (exp)))], - (HOST_WIDE_INT) TREE_INT_CST_LOW (exp)); - return; - - case REAL_CST: - -#if 0 -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, " [%g]\n", (double) TREE_INT_CST_LOW (exp)); -#endif - /* FIX THIS: find a better way to pass real_cst's. -bson */ - bc_emit_instruction (mode_to_const_map[TYPE_MODE (TREE_TYPE (exp))], - (double) TREE_REAL_CST (exp)); -#else - abort (); + case NOP_EXPR: + case CONVERT_EXPR: + case NON_LVALUE_EXPR: + exp = TREE_OPERAND (exp, 0); + if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) + return align; + inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); + align = MIN (inner, max_align); + break; + + case PLUS_EXPR: + /* If sum of pointer + int, restrict our maximum alignment to that + imposed by the integer. If not, we can't do any better than + ALIGN. */ + if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST) + return align; + + while (((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT) + & (max_align - 1)) + != 0) + max_align >>= 1; + + exp = TREE_OPERAND (exp, 0); + break; + + case ADDR_EXPR: + /* See what we are pointing at and look at its alignment. */ + exp = TREE_OPERAND (exp, 0); + if (TREE_CODE (exp) == FUNCTION_DECL) + align = FUNCTION_BOUNDARY; + else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd') + align = DECL_ALIGN (exp); +#ifdef CONSTANT_ALIGNMENT + else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c') + align = CONSTANT_ALIGNMENT (exp, align); #endif + return MIN (align, max_align); - return; - - case CALL_EXPR: - - /* We build a call description vector describing the type of - the return value and of the arguments; this call vector, - together with a pointer to a location for the return value - and the base of the argument list, is passed to the low - level machine dependent call subroutine, which is responsible - for putting the arguments wherever real functions expect - them, as well as getting the return value back. */ - { - tree calldesc = 0, arg; - int nargs = 0, i; - rtx retval; - - /* Push the evaluated args on the evaluation stack in reverse - order. Also make an entry for each arg in the calldesc - vector while we're at it. */ - - TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1)); - - for (arg = TREE_OPERAND (exp, 1); arg; arg = TREE_CHAIN (arg)) - { - ++nargs; - bc_expand_expr (TREE_VALUE (arg)); - - calldesc = tree_cons ((tree) 0, - size_in_bytes (TREE_TYPE (TREE_VALUE (arg))), - calldesc); - calldesc = tree_cons ((tree) 0, - bc_runtime_type_code (TREE_TYPE (TREE_VALUE (arg))), - calldesc); - } - - TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1)); - - /* Allocate a location for the return value and push its - address on the evaluation stack. Also make an entry - at the front of the calldesc for the return value type. */ - - type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))); - retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type)); - bc_load_localaddr (retval); - - calldesc = tree_cons ((tree) 0, size_in_bytes (type), calldesc); - calldesc = tree_cons ((tree) 0, bc_runtime_type_code (type), calldesc); - - /* Prepend the argument count. */ - calldesc = tree_cons ((tree) 0, - build_int_2 (nargs, 0), - calldesc); - - /* Push the address of the call description vector on the stack. */ - calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc); - TREE_TYPE (calldesc) = build_array_type (integer_type_node, - build_index_type (build_int_2 (nargs * 2, 0))); - r = output_constant_def (calldesc); - bc_load_externaddr (r); - - /* Push the address of the function to be called. */ - bc_expand_expr (TREE_OPERAND (exp, 0)); - - /* Call the function, popping its address and the calldesc vector - address off the evaluation stack in the process. */ - bc_emit_instruction (call); - - /* Pop the arguments off the stack. */ - bc_adjust_stack (nargs); - - /* Load the return value onto the stack. */ - bc_load_localaddr (retval); - bc_load_memory (type, TREE_OPERAND (exp, 0)); - } - return; - - case SAVE_EXPR: - - if (!SAVE_EXPR_RTL (exp)) + default: + return align; + } + } +} + +/* Return the tree node and offset if a given argument corresponds to + a string constant. */ + +static tree +string_constant (arg, ptr_offset) + tree arg; + tree *ptr_offset; +{ + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST) + { + *ptr_offset = integer_zero_node; + return TREE_OPERAND (arg, 0); + } + else if (TREE_CODE (arg) == PLUS_EXPR) + { + tree arg0 = TREE_OPERAND (arg, 0); + tree arg1 = TREE_OPERAND (arg, 1); + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST) { - /* First time around: copy to local variable */ - SAVE_EXPR_RTL (exp) = bc_allocate_local (int_size_in_bytes (TREE_TYPE (exp)), - TYPE_ALIGN (TREE_TYPE(exp))); - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_emit_instruction (duplicate); - - bc_load_localaddr (SAVE_EXPR_RTL (exp)); - bc_store_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0)); + *ptr_offset = arg1; + return TREE_OPERAND (arg0, 0); } - else + else if (TREE_CODE (arg1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST) { - /* Consecutive reference: use saved copy */ - bc_load_localaddr (SAVE_EXPR_RTL (exp)); - bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0)); + *ptr_offset = arg0; + return TREE_OPERAND (arg1, 0); } - return; - -#if 0 - /* FIXME: the XXXX_STMT codes have been removed in GCC2, but - how are they handled instead? */ - case LET_STMT: - - TREE_USED (exp) = 1; - bc_expand_expr (STMT_BODY (exp)); - return; -#endif - - case NOP_EXPR: - case CONVERT_EXPR: - - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)), TREE_TYPE (exp)); - return; - - case MODIFY_EXPR: - - expand_assignment (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), 0, 0); - return; - - case ADDR_EXPR: - - bc_expand_address (TREE_OPERAND (exp, 0)); - return; - - case INDIRECT_REF: - - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0)); - return; - - case ARRAY_REF: - - bc_expand_expr (bc_canonicalize_array_ref (exp)); - return; - - case COMPONENT_REF: - - bc_expand_component_address (exp); - - /* If we have a bitfield, generate a proper load */ - bc_load_memory (TREE_TYPE (TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1)); - return; - - case COMPOUND_EXPR: - - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_emit_instruction (drop); - bc_expand_expr (TREE_OPERAND (exp, 1)); - return; - - case COND_EXPR: - - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0))); - lab = bc_get_bytecode_label (); - bc_emit_bytecode (xjumpifnot); - bc_emit_bytecode_labelref (lab); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - bc_expand_expr (TREE_OPERAND (exp, 1)); - lab1 = bc_get_bytecode_label (); - bc_emit_bytecode (jump); - bc_emit_bytecode_labelref (lab1); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - - bc_emit_bytecode_labeldef (lab); - bc_expand_expr (TREE_OPERAND (exp, 2)); - bc_emit_bytecode_labeldef (lab1); - return; - - case TRUTH_ANDIF_EXPR: - - opcode = xjumpifnot; - goto andorif; - - case TRUTH_ORIF_EXPR: - - opcode = xjumpif; - goto andorif; - - case PLUS_EXPR: - - binoptab = optab_plus_expr; - goto binop; - - case MINUS_EXPR: - - binoptab = optab_minus_expr; - goto binop; - - case MULT_EXPR: - - binoptab = optab_mult_expr; - goto binop; - - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: - case CEIL_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - - binoptab = optab_trunc_div_expr; - goto binop; - - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: - case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: - - binoptab = optab_trunc_mod_expr; - goto binop; - - case FIX_ROUND_EXPR: - case FIX_FLOOR_EXPR: - case FIX_CEIL_EXPR: - abort (); /* Not used for C. */ - - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - case MAX_EXPR: - case MIN_EXPR: - case FFS_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - abort (); /* FIXME */ - - case RDIV_EXPR: - - binoptab = optab_rdiv_expr; - goto binop; - - case BIT_AND_EXPR: - - binoptab = optab_bit_and_expr; - goto binop; - - case BIT_IOR_EXPR: - - binoptab = optab_bit_ior_expr; - goto binop; - - case BIT_XOR_EXPR: - - binoptab = optab_bit_xor_expr; - goto binop; - - case LSHIFT_EXPR: - - binoptab = optab_lshift_expr; - goto binop; - - case RSHIFT_EXPR: - - binoptab = optab_rshift_expr; - goto binop; - - case TRUTH_AND_EXPR: - - binoptab = optab_truth_and_expr; - goto binop; - - case TRUTH_OR_EXPR: - - binoptab = optab_truth_or_expr; - goto binop; - - case LT_EXPR: - - binoptab = optab_lt_expr; - goto binop; - - case LE_EXPR: - - binoptab = optab_le_expr; - goto binop; - - case GE_EXPR: - - binoptab = optab_ge_expr; - goto binop; - - case GT_EXPR: - - binoptab = optab_gt_expr; - goto binop; - - case EQ_EXPR: - - binoptab = optab_eq_expr; - goto binop; - - case NE_EXPR: - - binoptab = optab_ne_expr; - goto binop; - - case NEGATE_EXPR: - - unoptab = optab_negate_expr; - goto unop; - - case BIT_NOT_EXPR: - - unoptab = optab_bit_not_expr; - goto unop; - - case TRUTH_NOT_EXPR: - - unoptab = optab_truth_not_expr; - goto unop; - - case PREDECREMENT_EXPR: - - incroptab = optab_predecrement_expr; - goto increment; - - case PREINCREMENT_EXPR: - - incroptab = optab_preincrement_expr; - goto increment; - - case POSTDECREMENT_EXPR: - - incroptab = optab_postdecrement_expr; - goto increment; - - case POSTINCREMENT_EXPR: - - incroptab = optab_postincrement_expr; - goto increment; - - case CONSTRUCTOR: - - bc_expand_constructor (exp); - return; - - case ERROR_MARK: - case RTL_EXPR: - - return; - - case BIND_EXPR: - { - tree vars = TREE_OPERAND (exp, 0); - int vars_need_expansion = 0; - - /* Need to open a binding contour here because - if there are any cleanups they most be contained here. */ - expand_start_bindings (0); - - /* Mark the corresponding BLOCK for output. */ - if (TREE_OPERAND (exp, 2) != 0) - TREE_USED (TREE_OPERAND (exp, 2)) = 1; - - /* If VARS have not yet been expanded, expand them now. */ - while (vars) - { - if (DECL_RTL (vars) == 0) - { - vars_need_expansion = 1; - expand_decl (vars); - } - expand_decl_init (vars); - vars = TREE_CHAIN (vars); - } - - bc_expand_expr (TREE_OPERAND (exp, 1)); - - expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0); - - return; - } - - default: - abort (); - } - - abort (); - - binop: - - bc_expand_binary_operation (binoptab, TREE_TYPE (exp), - TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1)); - return; - - - unop: - - bc_expand_unary_operation (unoptab, TREE_TYPE (exp), TREE_OPERAND (exp, 0)); - return; - - - andorif: - - bc_expand_expr (TREE_OPERAND (exp, 0)); - bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0))); - lab = bc_get_bytecode_label (); - - bc_emit_instruction (duplicate); - bc_emit_bytecode (opcode); - bc_emit_bytecode_labelref (lab); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - - bc_emit_instruction (drop); - - bc_expand_expr (TREE_OPERAND (exp, 1)); - bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 1))); - bc_emit_bytecode_labeldef (lab); - return; - - - increment: - - type = TREE_TYPE (TREE_OPERAND (exp, 0)); - - /* Push the quantum. */ - bc_expand_expr (TREE_OPERAND (exp, 1)); - - /* Convert it to the lvalue's type. */ - bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)), type); - - /* Push the address of the lvalue */ - bc_expand_expr (build1 (ADDR_EXPR, TYPE_POINTER_TO (type), TREE_OPERAND (exp, 0))); - - /* Perform actual increment */ - bc_expand_increment (incroptab, type); - return; -} - -/* Return the alignment in bits of EXP, a pointer valued expression. - But don't return more than MAX_ALIGN no matter what. - The alignment returned is, by default, the alignment of the thing that - EXP points to (if it is not a POINTER_TYPE, 0 is returned). - - Otherwise, look at the expression to see if we can do better, i.e., if the - expression is actually pointing at an object whose alignment is tighter. */ - -static int -get_pointer_alignment (exp, max_align) - tree exp; - unsigned max_align; -{ - unsigned align, inner; - - if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) - return 0; - - align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); - align = MIN (align, max_align); - - while (1) - { - switch (TREE_CODE (exp)) - { - case NOP_EXPR: - case CONVERT_EXPR: - case NON_LVALUE_EXPR: - exp = TREE_OPERAND (exp, 0); - if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE) - return align; - inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); - align = MIN (inner, max_align); - break; - - case PLUS_EXPR: - /* If sum of pointer + int, restrict our maximum alignment to that - imposed by the integer. If not, we can't do any better than - ALIGN. */ - if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST) - return align; - - while (((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT) - & (max_align - 1)) - != 0) - max_align >>= 1; - - exp = TREE_OPERAND (exp, 0); - break; - - case ADDR_EXPR: - /* See what we are pointing at and look at its alignment. */ - exp = TREE_OPERAND (exp, 0); - if (TREE_CODE (exp) == FUNCTION_DECL) - align = FUNCTION_BOUNDARY; - else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd') - align = DECL_ALIGN (exp); -#ifdef CONSTANT_ALIGNMENT - else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c') - align = CONSTANT_ALIGNMENT (exp, align); -#endif - return MIN (align, max_align); - - default: - return align; - } - } -} - -/* Return the tree node and offset if a given argument corresponds to - a string constant. */ - -static tree -string_constant (arg, ptr_offset) - tree arg; - tree *ptr_offset; -{ - STRIP_NOPS (arg); - - if (TREE_CODE (arg) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST) - { - *ptr_offset = integer_zero_node; - return TREE_OPERAND (arg, 0); - } - else if (TREE_CODE (arg) == PLUS_EXPR) - { - tree arg0 = TREE_OPERAND (arg, 0); - tree arg1 = TREE_OPERAND (arg, 1); - - STRIP_NOPS (arg0); - STRIP_NOPS (arg1); - - if (TREE_CODE (arg0) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST) - { - *ptr_offset = arg1; - return TREE_OPERAND (arg0, 0); - } - else if (TREE_CODE (arg1) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST) - { - *ptr_offset = arg0; - return TREE_OPERAND (arg1, 0); - } - } - - return 0; -} - -/* Compute the length of a C string. TREE_STRING_LENGTH is not the right - way, because it could contain a zero byte in the middle. - TREE_STRING_LENGTH is the size of the character array, not the string. - - Unfortunately, string_constant can't access the values of const char - arrays with initializers, so neither can we do so here. */ - -static tree -c_strlen (src) - tree src; -{ - tree offset_node; - int offset, max; - char *ptr; - - src = string_constant (src, &offset_node); - if (src == 0) - return 0; - max = TREE_STRING_LENGTH (src); - ptr = TREE_STRING_POINTER (src); - if (offset_node && TREE_CODE (offset_node) != INTEGER_CST) - { - /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't - compute the offset to the following null if we don't know where to - start searching for it. */ - int i; - for (i = 0; i < max; i++) - if (ptr[i] == 0) - return 0; - /* We don't know the starting offset, but we do know that the string - has no internal zero bytes. We can assume that the offset falls - within the bounds of the string; otherwise, the programmer deserves - what he gets. Subtract the offset from the length of the string, - and return that. */ - /* This would perhaps not be valid if we were dealing with named - arrays in addition to literal string constants. */ - return size_binop (MINUS_EXPR, size_int (max), offset_node); - } - - /* We have a known offset into the string. Start searching there for - a null character. */ - if (offset_node == 0) - offset = 0; - else - { - /* Did we get a long long offset? If so, punt. */ - if (TREE_INT_CST_HIGH (offset_node) != 0) - return 0; - offset = TREE_INT_CST_LOW (offset_node); - } - /* If the offset is known to be out of bounds, warn, and call strlen at - runtime. */ - if (offset < 0 || offset > max) - { - warning ("offset outside bounds of constant string"); - return 0; - } - /* Use strlen to search for the first zero byte. Since any strings - constructed with build_string will have nulls appended, we win even - if we get handed something like (char[4])"abcd". - - Since OFFSET is our starting index into the string, no further - calculation is needed. */ - return size_int (strlen (ptr + offset)); -} - -rtx -expand_builtin_return_addr (fndecl_code, count, tem) - enum built_in_function fndecl_code; - int count; - rtx tem; -{ - int i; - - /* Some machines need special handling before we can access - arbitrary frames. For example, on the sparc, we must first flush - all register windows to the stack. */ -#ifdef SETUP_FRAME_ADDRESSES - if (count > 0) - SETUP_FRAME_ADDRESSES (); -#endif - - /* On the sparc, the return address is not in the frame, it is in a - register. There is no way to access it off of the current frame - pointer, but it can be accessed off the previous frame pointer by - reading the value from the register window save area. */ -#ifdef RETURN_ADDR_IN_PREVIOUS_FRAME - if (fndecl_code == BUILT_IN_RETURN_ADDRESS) - count--; -#endif - - /* Scan back COUNT frames to the specified frame. */ - for (i = 0; i < count; i++) - { - /* Assume the dynamic chain pointer is in the word that the - frame address points to, unless otherwise specified. */ -#ifdef DYNAMIC_CHAIN_ADDRESS - tem = DYNAMIC_CHAIN_ADDRESS (tem); -#endif - tem = memory_address (Pmode, tem); - tem = copy_to_reg (gen_rtx_MEM (Pmode, tem)); - } - - /* For __builtin_frame_address, return what we've got. */ - if (fndecl_code == BUILT_IN_FRAME_ADDRESS) - return tem; - - /* For __builtin_return_address, Get the return address from that - frame. */ -#ifdef RETURN_ADDR_RTX - tem = RETURN_ADDR_RTX (count, tem); -#else - tem = memory_address (Pmode, - plus_constant (tem, GET_MODE_SIZE (Pmode))); - tem = gen_rtx_MEM (Pmode, tem); -#endif - return tem; -} - -/* __builtin_setjmp is passed a pointer to an array of five words (not - all will be used on all machines). It operates similarly to the C - library function of the same name, but is more efficient. Much of - the code below (and for longjmp) is copied from the handling of - non-local gotos. - - NOTE: This is intended for use by GNAT and the exception handling - scheme in the compiler and will only work in the method used by - them. */ - -rtx -expand_builtin_setjmp (buf_addr, target) - rtx buf_addr; - rtx target; -{ - rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx (); - enum machine_mode sa_mode = Pmode, value_mode; - rtx stack_save; - int old_inhibit_defer_pop = inhibit_defer_pop; - int return_pops - = RETURN_POPS_ARGS (get_identifier ("__dummy"), - build_function_type (void_type_node, NULL_TREE), - 0); - rtx next_arg_reg; - CUMULATIVE_ARGS args_so_far; - rtx op0; - int i; - - value_mode = TYPE_MODE (integer_type_node); - -#ifdef POINTERS_EXTEND_UNSIGNED - buf_addr = convert_memory_address (Pmode, buf_addr); -#endif - - buf_addr = force_reg (Pmode, buf_addr); - - if (target == 0 || GET_CODE (target) != REG - || REGNO (target) < FIRST_PSEUDO_REGISTER) - target = gen_reg_rtx (value_mode); - - emit_queue (); - - /* We store the frame pointer and the address of lab1 in the buffer - and use the rest of it for the stack save area, which is - machine-dependent. */ - emit_move_insn (gen_rtx_MEM (Pmode, buf_addr), - virtual_stack_vars_rtx); - emit_move_insn - (validize_mem (gen_rtx_MEM (Pmode, - plus_constant (buf_addr, - GET_MODE_SIZE (Pmode)))), - gen_rtx_LABEL_REF (Pmode, lab1)); - -#ifdef HAVE_save_stack_nonlocal - if (HAVE_save_stack_nonlocal) - sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0]; -#endif - - stack_save = gen_rtx_MEM (sa_mode, - plus_constant (buf_addr, - 2 * GET_MODE_SIZE (Pmode))); - emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX); - -#ifdef HAVE_setjmp - if (HAVE_setjmp) - emit_insn (gen_setjmp ()); -#endif - - /* Set TARGET to zero and branch around the other case. */ - emit_move_insn (target, const0_rtx); - emit_jump_insn (gen_jump (lab2)); - emit_barrier (); - emit_label (lab1); - - /* Note that setjmp clobbers FP when we get here, so we have to make - sure it's marked as used by this function. */ - emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - - /* Mark the static chain as clobbered here so life information - doesn't get messed up for it. */ - emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx)); - - /* Now put in the code to restore the frame pointer, and argument - pointer, if needed. The code below is from expand_end_bindings - in stmt.c; see detailed documentation there. */ -#ifdef HAVE_nonlocal_goto - if (! HAVE_nonlocal_goto) -#endif - emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx); - - current_function_has_nonlocal_label = 1; - -#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM - if (fixed_regs[ARG_POINTER_REGNUM]) - { -#ifdef ELIMINABLE_REGS - static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS; - - for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++) - if (elim_regs[i].from == ARG_POINTER_REGNUM - && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM) - break; - - if (i == sizeof elim_regs / sizeof elim_regs [0]) -#endif - { - /* Now restore our arg pointer from the address at which it - was saved in our stack frame. - If there hasn't be space allocated for it yet, make - some now. */ - if (arg_pointer_save_area == 0) - arg_pointer_save_area - = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); - emit_move_insn (virtual_incoming_args_rtx, - copy_to_reg (arg_pointer_save_area)); - } - } -#endif - -#ifdef HAVE_nonlocal_goto_receiver - if (HAVE_nonlocal_goto_receiver) - emit_insn (gen_nonlocal_goto_receiver ()); -#endif - /* The static chain pointer contains the address of dummy function. - We need to call it here to handle some PIC cases of restoring a - global pointer. Then return 1. */ - op0 = copy_to_mode_reg (Pmode, static_chain_rtx); - - /* We can't actually call emit_library_call here, so do everything - it does, which isn't much for a libfunc with no args. */ - op0 = memory_address (FUNCTION_MODE, op0); - - INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, - gen_rtx_SYMBOL_REF (Pmode, "__dummy"), 1); - next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1); - -#ifndef ACCUMULATE_OUTGOING_ARGS -#ifdef HAVE_call_pop - if (HAVE_call_pop) - emit_call_insn (gen_call_pop (gen_rtx_MEM (FUNCTION_MODE, op0), - const0_rtx, next_arg_reg, - GEN_INT (return_pops))); - else -#endif -#endif - -#ifdef HAVE_call - if (HAVE_call) - emit_call_insn (gen_call (gen_rtx_MEM (FUNCTION_MODE, op0), - const0_rtx, next_arg_reg, const0_rtx)); - else -#endif - abort (); - -#ifdef HAVE_builtin_setjmp_receiver - if (HAVE_builtin_setjmp_receiver) - emit_insn (gen_builtin_setjmp_receiver ()); -#endif - - emit_move_insn (target, const1_rtx); - emit_label (lab2); - return target; -} - - -/* Expand an expression EXP that calls a built-in function, - with result going to TARGET if that's convenient - (and in mode MODE if that's convenient). - SUBTARGET may be used as the target for computing one of EXP's operands. - IGNORE is nonzero if the value is to be ignored. */ - -#define CALLED_AS_BUILT_IN(NODE) \ - (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10)) - -static rtx -expand_builtin (exp, target, subtarget, mode, ignore) - tree exp; - rtx target; - rtx subtarget; - enum machine_mode mode; - int ignore; -{ - tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); - tree arglist = TREE_OPERAND (exp, 1); - rtx op0; - rtx lab1, insns; - enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp)); - optab builtin_optab; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_ABS: - case BUILT_IN_LABS: - case BUILT_IN_FABS: - /* build_function_call changes these into ABS_EXPR. */ - abort (); - - case BUILT_IN_SIN: - case BUILT_IN_COS: - /* Treat these like sqrt, but only if the user asks for them. */ - if (! flag_fast_math) - break; - case BUILT_IN_FSQRT: - /* If not optimizing, call the library function. */ - if (! optimize) - break; - - if (arglist == 0 - /* Arg could be wrong type if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE) - break; - - /* Stabilize and compute the argument. */ - if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL - && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL) - { - exp = copy_node (exp); - arglist = copy_node (arglist); - TREE_OPERAND (exp, 1) = arglist; - TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist)); - } - op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); - - /* Make a suitable register to place result in. */ - target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); - - emit_queue (); - start_sequence (); - - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_SIN: - builtin_optab = sin_optab; break; - case BUILT_IN_COS: - builtin_optab = cos_optab; break; - case BUILT_IN_FSQRT: - builtin_optab = sqrt_optab; break; - default: - abort (); - } - - /* Compute into TARGET. - Set TARGET to wherever the result comes back. */ - target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), - builtin_optab, op0, target, 0); - - /* If we were unable to expand via the builtin, stop the - sequence (without outputting the insns) and break, causing - a call the the library function. */ - if (target == 0) - { - end_sequence (); - break; - } - - /* Check the results by default. But if flag_fast_math is turned on, - then assume sqrt will always be called with valid arguments. */ - - if (! flag_fast_math) - { - /* Don't define the builtin FP instructions - if your machine is not IEEE. */ - if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT) - abort (); - - lab1 = gen_label_rtx (); - - /* Test the result; if it is NaN, set errno=EDOM because - the argument was not in the domain. */ - emit_cmp_insn (target, target, EQ, 0, GET_MODE (target), 0, 0); - emit_jump_insn (gen_beq (lab1)); - -#ifdef TARGET_EDOM - { -#ifdef GEN_ERRNO_RTX - rtx errno_rtx = GEN_ERRNO_RTX; -#else - rtx errno_rtx - = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno")); -#endif - - emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM)); - } -#else - /* We can't set errno=EDOM directly; let the library call do it. - Pop the arguments right away in case the call gets deleted. */ - NO_DEFER_POP; - expand_call (exp, target, 0); - OK_DEFER_POP; -#endif - - emit_label (lab1); - } - - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insns (insns); - - return target; - - case BUILT_IN_FMOD: - break; - - /* __builtin_apply_args returns block of memory allocated on - the stack into which is stored the arg pointer, structure - value address, static chain, and all the registers that might - possibly be used in performing a function call. The code is - moved to the start of the function so the incoming values are - saved. */ - case BUILT_IN_APPLY_ARGS: - /* Don't do __builtin_apply_args more than once in a function. - Save the result of the first call and reuse it. */ - if (apply_args_value != 0) - return apply_args_value; - { - /* When this function is called, it means that registers must be - saved on entry to this function. So we migrate the - call to the first insn of this function. */ - rtx temp; - rtx seq; - - start_sequence (); - temp = expand_builtin_apply_args (); - seq = get_insns (); - end_sequence (); - - apply_args_value = temp; - - /* Put the sequence after the NOTE that starts the function. - If this is inside a SEQUENCE, make the outer-level insn - chain current, so the code is placed at the start of the - function. */ - push_topmost_sequence (); - emit_insns_before (seq, NEXT_INSN (get_insns ())); - pop_topmost_sequence (); - return temp; - } - - /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes - FUNCTION with a copy of the parameters described by - ARGUMENTS, and ARGSIZE. It returns a block of memory - allocated on the stack into which is stored all the registers - that might possibly be used for returning the result of a - function. ARGUMENTS is the value returned by - __builtin_apply_args. ARGSIZE is the number of bytes of - arguments that must be copied. ??? How should this value be - computed? We'll also need a safe worst case value for varargs - functions. */ - case BUILT_IN_APPLY: - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE - || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE) - return const0_rtx; - else - { - int i; - tree t; - rtx ops[3]; - - for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++) - ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0); - - return expand_builtin_apply (ops[0], ops[1], ops[2]); - } - - /* __builtin_return (RESULT) causes the function to return the - value described by RESULT. RESULT is address of the block of - memory returned by __builtin_apply. */ - case BUILT_IN_RETURN: - if (arglist - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE) - expand_builtin_return (expand_expr (TREE_VALUE (arglist), - NULL_RTX, VOIDmode, 0)); - return const0_rtx; - - case BUILT_IN_SAVEREGS: - /* Don't do __builtin_saveregs more than once in a function. - Save the result of the first call and reuse it. */ - if (saveregs_value != 0) - return saveregs_value; - { - /* When this function is called, it means that registers must be - saved on entry to this function. So we migrate the - call to the first insn of this function. */ - rtx temp; - rtx seq; - - /* Now really call the function. `expand_call' does not call - expand_builtin, so there is no danger of infinite recursion here. */ - start_sequence (); - -#ifdef EXPAND_BUILTIN_SAVEREGS - /* Do whatever the machine needs done in this case. */ - temp = EXPAND_BUILTIN_SAVEREGS (arglist); -#else - /* The register where the function returns its value - is likely to have something else in it, such as an argument. - So preserve that register around the call. */ - - if (value_mode != VOIDmode) - { - rtx valreg = hard_libcall_value (value_mode); - rtx saved_valreg = gen_reg_rtx (value_mode); - - emit_move_insn (saved_valreg, valreg); - temp = expand_call (exp, target, ignore); - emit_move_insn (valreg, saved_valreg); - } - else - /* Generate the call, putting the value in a pseudo. */ - temp = expand_call (exp, target, ignore); -#endif - - seq = get_insns (); - end_sequence (); - - saveregs_value = temp; - - /* Put the sequence after the NOTE that starts the function. - If this is inside a SEQUENCE, make the outer-level insn - chain current, so the code is placed at the start of the - function. */ - push_topmost_sequence (); - emit_insns_before (seq, NEXT_INSN (get_insns ())); - pop_topmost_sequence (); - return temp; - } - - /* __builtin_args_info (N) returns word N of the arg space info - for the current function. The number and meanings of words - is controlled by the definition of CUMULATIVE_ARGS. */ - case BUILT_IN_ARGS_INFO: - { - int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int); - int i; - int *word_ptr = (int *) ¤t_function_args_info; - tree type, elts, result; - - if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0) - fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d", - __FILE__, __LINE__); - - if (arglist != 0) - { - tree arg = TREE_VALUE (arglist); - if (TREE_CODE (arg) != INTEGER_CST) - error ("argument of `__builtin_args_info' must be constant"); - else - { - int wordnum = TREE_INT_CST_LOW (arg); - - if (wordnum < 0 || wordnum >= nwords || TREE_INT_CST_HIGH (arg)) - error ("argument of `__builtin_args_info' out of range"); - else - return GEN_INT (word_ptr[wordnum]); - } - } - else - error ("missing argument in `__builtin_args_info'"); - - return const0_rtx; - -#if 0 - for (i = 0; i < nwords; i++) - elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0)); - - type = build_array_type (integer_type_node, - build_index_type (build_int_2 (nwords, 0))); - result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts)); - TREE_CONSTANT (result) = 1; - TREE_STATIC (result) = 1; - result = build (INDIRECT_REF, build_pointer_type (type), result); - TREE_CONSTANT (result) = 1; - return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD); -#endif - } - - /* Return the address of the first anonymous stack arg. */ - case BUILT_IN_NEXT_ARG: - { - tree fntype = TREE_TYPE (current_function_decl); - - if ((TYPE_ARG_TYPES (fntype) == 0 - || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) - == void_type_node)) - && ! current_function_varargs) - { - error ("`va_start' used in function with fixed args"); - return const0_rtx; - } - - if (arglist) - { - tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl)); - tree arg = TREE_VALUE (arglist); - - /* Strip off all nops for the sake of the comparison. This - is not quite the same as STRIP_NOPS. It does more. - We must also strip off INDIRECT_EXPR for C++ reference - parameters. */ - while (TREE_CODE (arg) == NOP_EXPR - || TREE_CODE (arg) == CONVERT_EXPR - || TREE_CODE (arg) == NON_LVALUE_EXPR - || TREE_CODE (arg) == INDIRECT_REF) - arg = TREE_OPERAND (arg, 0); - if (arg != last_parm) - warning ("second parameter of `va_start' not last named argument"); - } - else if (! current_function_varargs) - /* Evidently an out of date version of ; can't validate - va_start's second argument, but can still work as intended. */ - warning ("`__builtin_next_arg' called without an argument"); - } - - return expand_binop (Pmode, add_optab, - current_function_internal_arg_pointer, - current_function_arg_offset_rtx, - NULL_RTX, 0, OPTAB_LIB_WIDEN); - - case BUILT_IN_CLASSIFY_TYPE: - if (arglist != 0) - { - tree type = TREE_TYPE (TREE_VALUE (arglist)); - enum tree_code code = TREE_CODE (type); - if (code == VOID_TYPE) - return GEN_INT (void_type_class); - if (code == INTEGER_TYPE) - return GEN_INT (integer_type_class); - if (code == CHAR_TYPE) - return GEN_INT (char_type_class); - if (code == ENUMERAL_TYPE) - return GEN_INT (enumeral_type_class); - if (code == BOOLEAN_TYPE) - return GEN_INT (boolean_type_class); - if (code == POINTER_TYPE) - return GEN_INT (pointer_type_class); - if (code == REFERENCE_TYPE) - return GEN_INT (reference_type_class); - if (code == OFFSET_TYPE) - return GEN_INT (offset_type_class); - if (code == REAL_TYPE) - return GEN_INT (real_type_class); - if (code == COMPLEX_TYPE) - return GEN_INT (complex_type_class); - if (code == FUNCTION_TYPE) - return GEN_INT (function_type_class); - if (code == METHOD_TYPE) - return GEN_INT (method_type_class); - if (code == RECORD_TYPE) - return GEN_INT (record_type_class); - if (code == UNION_TYPE || code == QUAL_UNION_TYPE) - return GEN_INT (union_type_class); - if (code == ARRAY_TYPE) - { - if (TYPE_STRING_FLAG (type)) - return GEN_INT (string_type_class); - else - return GEN_INT (array_type_class); - } - if (code == SET_TYPE) - return GEN_INT (set_type_class); - if (code == FILE_TYPE) - return GEN_INT (file_type_class); - if (code == LANG_TYPE) - return GEN_INT (lang_type_class); - } - return GEN_INT (no_type_class); - - case BUILT_IN_CONSTANT_P: - if (arglist == 0) - return const0_rtx; - else - { - tree arg = TREE_VALUE (arglist); - - STRIP_NOPS (arg); - return (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c' - || (TREE_CODE (arg) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST) - ? const1_rtx : const0_rtx); - } - - case BUILT_IN_FRAME_ADDRESS: - /* The argument must be a nonnegative integer constant. - It counts the number of frames to scan up the stack. - The value is the address of that frame. */ - case BUILT_IN_RETURN_ADDRESS: - /* The argument must be a nonnegative integer constant. - It counts the number of frames to scan up the stack. - The value is the return address saved in that frame. */ - if (arglist == 0) - /* Warning about missing arg was already issued. */ - return const0_rtx; - else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST - || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0) - { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - error ("invalid arg to `__builtin_frame_address'"); - else - error ("invalid arg to `__builtin_return_address'"); - return const0_rtx; - } - else - { - rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), - TREE_INT_CST_LOW (TREE_VALUE (arglist)), - hard_frame_pointer_rtx); - - /* Some ports cannot access arbitrary stack frames. */ - if (tem == NULL) - { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - warning ("unsupported arg to `__builtin_frame_address'"); - else - warning ("unsupported arg to `__builtin_return_address'"); - return const0_rtx; - } - - /* For __builtin_frame_address, return what we've got. */ - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - return tem; - - if (GET_CODE (tem) != REG) - tem = copy_to_reg (tem); - return tem; - } - - /* Returns the address of the area where the structure is returned. - 0 otherwise. */ - case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: - if (arglist != 0 - || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))) - || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM) - return const0_rtx; - else - return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); - - case BUILT_IN_ALLOCA: - if (arglist == 0 - /* Arg could be non-integer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) - break; - - /* Compute the argument. */ - op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); - - /* Allocate the desired space. */ - return allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT); - - case BUILT_IN_FFS: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; - - if (arglist == 0 - /* Arg could be non-integer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) - break; - - /* Compute the argument. */ - op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); - /* Compute ffs, into TARGET if possible. - Set TARGET to wherever the result comes back. */ - target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), - ffs_optab, op0, target, 1); - if (target == 0) - abort (); - return target; - - case BUILT_IN_STRLEN: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; - - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) - break; - else - { - tree src = TREE_VALUE (arglist); - tree len = c_strlen (src); - - int align - = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - - rtx result, src_rtx, char_rtx; - enum machine_mode insn_mode = value_mode, char_mode; - enum insn_code icode; - - /* If the length is known, just return it. */ - if (len != 0) - return expand_expr (len, target, mode, EXPAND_MEMORY_USE_BAD); - - /* If SRC is not a pointer type, don't do this operation inline. */ - if (align == 0) - break; - - /* Call a function if we can't compute strlen in the right mode. */ - - while (insn_mode != VOIDmode) - { - icode = strlen_optab->handlers[(int) insn_mode].insn_code; - if (icode != CODE_FOR_nothing) - break; - - insn_mode = GET_MODE_WIDER_MODE (insn_mode); - } - if (insn_mode == VOIDmode) - break; - - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && GET_CODE (result) == REG - && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - - /* Make sure the operands are acceptable to the predicates. */ - - if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode)) - result = gen_reg_rtx (insn_mode); - src_rtx = memory_address (BLKmode, - expand_expr (src, NULL_RTX, ptr_mode, - EXPAND_NORMAL)); - - if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode)) - src_rtx = copy_to_mode_reg (Pmode, src_rtx); - - /* Check the string is readable and has an end. */ - if (flag_check_memory_usage) - emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2, - src_rtx, ptr_mode, - GEN_INT (MEMORY_USE_RO), - TYPE_MODE (integer_type_node)); - - char_rtx = const0_rtx; - char_mode = insn_operand_mode[(int)icode][2]; - if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode)) - char_rtx = copy_to_mode_reg (char_mode, char_rtx); + } - emit_insn (GEN_FCN (icode) (result, - gen_rtx_MEM (BLKmode, src_rtx), - char_rtx, GEN_INT (align))); + return 0; +} - /* Return the value in the proper mode for this function. */ - if (GET_MODE (result) == value_mode) - return result; - else if (target != 0) - { - convert_move (target, result, 0); - return target; - } - else - return convert_to_mode (value_mode, result, 0); - } +/* Compute the length of a C string. TREE_STRING_LENGTH is not the right + way, because it could contain a zero byte in the middle. + TREE_STRING_LENGTH is the size of the character array, not the string. - case BUILT_IN_STRCPY: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; + Unfortunately, string_constant can't access the values of const char + arrays with initializers, so neither can we do so here. */ - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE) - break; - else - { - tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); +static tree +c_strlen (src) + tree src; +{ + tree offset_node; + int offset, max; + char *ptr; - if (len == 0) - break; + src = string_constant (src, &offset_node); + if (src == 0) + return 0; + max = TREE_STRING_LENGTH (src); + ptr = TREE_STRING_POINTER (src); + if (offset_node && TREE_CODE (offset_node) != INTEGER_CST) + { + /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't + compute the offset to the following null if we don't know where to + start searching for it. */ + int i; + for (i = 0; i < max; i++) + if (ptr[i] == 0) + return 0; + /* We don't know the starting offset, but we do know that the string + has no internal zero bytes. We can assume that the offset falls + within the bounds of the string; otherwise, the programmer deserves + what he gets. Subtract the offset from the length of the string, + and return that. */ + /* This would perhaps not be valid if we were dealing with named + arrays in addition to literal string constants. */ + return size_binop (MINUS_EXPR, size_int (max), offset_node); + } - len = size_binop (PLUS_EXPR, len, integer_one_node); + /* We have a known offset into the string. Start searching there for + a null character. */ + if (offset_node == 0) + offset = 0; + else + { + /* Did we get a long long offset? If so, punt. */ + if (TREE_INT_CST_HIGH (offset_node) != 0) + return 0; + offset = TREE_INT_CST_LOW (offset_node); + } + /* If the offset is known to be out of bounds, warn, and call strlen at + runtime. */ + if (offset < 0 || offset > max) + { + warning ("offset outside bounds of constant string"); + return 0; + } + /* Use strlen to search for the first zero byte. Since any strings + constructed with build_string will have nulls appended, we win even + if we get handed something like (char[4])"abcd". - chainon (arglist, build_tree_list (NULL_TREE, len)); - } + Since OFFSET is our starting index into the string, no further + calculation is needed. */ + return size_int (strlen (ptr + offset)); +} - /* Drops in. */ - case BUILT_IN_MEMCPY: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; +rtx +expand_builtin_return_addr (fndecl_code, count, tem) + enum built_in_function fndecl_code; + int count; + rtx tem; +{ + int i; - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) - != POINTER_TYPE) - || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 - || (TREE_CODE (TREE_TYPE (TREE_VALUE - (TREE_CHAIN (TREE_CHAIN (arglist))))) - != INTEGER_TYPE)) - break; - else - { - tree dest = TREE_VALUE (arglist); - tree src = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - tree type; + /* Some machines need special handling before we can access + arbitrary frames. For example, on the sparc, we must first flush + all register windows to the stack. */ +#ifdef SETUP_FRAME_ADDRESSES + if (count > 0) + SETUP_FRAME_ADDRESSES (); +#endif - int src_align - = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int dest_align - = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - rtx dest_rtx, dest_mem, src_mem, src_rtx, dest_addr, len_rtx; + /* On the sparc, the return address is not in the frame, it is in a + register. There is no way to access it off of the current frame + pointer, but it can be accessed off the previous frame pointer by + reading the value from the register window save area. */ +#ifdef RETURN_ADDR_IN_PREVIOUS_FRAME + if (fndecl_code == BUILT_IN_RETURN_ADDRESS) + count--; +#endif - /* If either SRC or DEST is not a pointer type, don't do - this operation in-line. */ - if (src_align == 0 || dest_align == 0) - { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCPY) - TREE_CHAIN (TREE_CHAIN (arglist)) = 0; - break; - } + /* Scan back COUNT frames to the specified frame. */ + for (i = 0; i < count; i++) + { + /* Assume the dynamic chain pointer is in the word that the + frame address points to, unless otherwise specified. */ +#ifdef DYNAMIC_CHAIN_ADDRESS + tem = DYNAMIC_CHAIN_ADDRESS (tem); +#endif + tem = memory_address (Pmode, tem); + tem = copy_to_reg (gen_rtx_MEM (Pmode, tem)); + } - dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM); - dest_mem = gen_rtx_MEM (BLKmode, - memory_address (BLKmode, dest_rtx)); - /* There could be a void* cast on top of the object. */ - while (TREE_CODE (dest) == NOP_EXPR) - dest = TREE_OPERAND (dest, 0); - type = TREE_TYPE (TREE_TYPE (dest)); - MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type); - src_rtx = expand_expr (src, NULL_RTX, ptr_mode, EXPAND_SUM); - src_mem = gen_rtx_MEM (BLKmode, - memory_address (BLKmode, src_rtx)); - len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + /* For __builtin_frame_address, return what we've got. */ + if (fndecl_code == BUILT_IN_FRAME_ADDRESS) + return tem; - /* Just copy the rights of SRC to the rights of DEST. */ - if (flag_check_memory_usage) - emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3, - dest_rtx, ptr_mode, - src_rtx, ptr_mode, - len_rtx, TYPE_MODE (sizetype)); + /* For __builtin_return_address, Get the return address from that + frame. */ +#ifdef RETURN_ADDR_RTX + tem = RETURN_ADDR_RTX (count, tem); +#else + tem = memory_address (Pmode, + plus_constant (tem, GET_MODE_SIZE (Pmode))); + tem = gen_rtx_MEM (Pmode, tem); +#endif + return tem; +} - /* There could be a void* cast on top of the object. */ - while (TREE_CODE (src) == NOP_EXPR) - src = TREE_OPERAND (src, 0); - type = TREE_TYPE (TREE_TYPE (src)); - MEM_IN_STRUCT_P (src_mem) = AGGREGATE_TYPE_P (type); +/* __builtin_setjmp is passed a pointer to an array of five words (not + all will be used on all machines). It operates similarly to the C + library function of the same name, but is more efficient. Much of + the code below (and for longjmp) is copied from the handling of + non-local gotos. - /* Copy word part most expediently. */ - dest_addr - = emit_block_move (dest_mem, src_mem, len_rtx, - MIN (src_align, dest_align)); + NOTE: This is intended for use by GNAT and the exception handling + scheme in the compiler and will only work in the method used by + them. */ - if (dest_addr == 0) - dest_addr = force_operand (dest_rtx, NULL_RTX); +rtx +expand_builtin_setjmp (buf_addr, target) + rtx buf_addr; + rtx target; +{ + rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx (); + enum machine_mode sa_mode = Pmode, value_mode; + rtx stack_save; + int old_inhibit_defer_pop = inhibit_defer_pop; + int return_pops + = RETURN_POPS_ARGS (get_identifier ("__dummy"), + build_function_type (void_type_node, NULL_TREE), + 0); + rtx next_arg_reg; + CUMULATIVE_ARGS args_so_far; + rtx op0; + int i; - return dest_addr; - } + value_mode = TYPE_MODE (integer_type_node); - case BUILT_IN_MEMSET: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; +#ifdef POINTERS_EXTEND_UNSIGNED + buf_addr = convert_memory_address (Pmode, buf_addr); +#endif - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) - != INTEGER_TYPE) - || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 - || (INTEGER_TYPE - != (TREE_CODE (TREE_TYPE - (TREE_VALUE - (TREE_CHAIN (TREE_CHAIN (arglist)))))))) - break; - else - { - tree dest = TREE_VALUE (arglist); - tree val = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - tree type; + buf_addr = force_reg (Pmode, buf_addr); - int dest_align - = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - rtx dest_rtx, dest_mem, dest_addr, len_rtx; + if (target == 0 || GET_CODE (target) != REG + || REGNO (target) < FIRST_PSEUDO_REGISTER) + target = gen_reg_rtx (value_mode); - /* If DEST is not a pointer type, don't do this - operation in-line. */ - if (dest_align == 0) - break; + emit_queue (); - /* If VAL is not 0, don't do this operation in-line. */ - if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx) - break; + /* We store the frame pointer and the address of lab1 in the buffer + and use the rest of it for the stack save area, which is + machine-dependent. */ + emit_move_insn (gen_rtx_MEM (Pmode, buf_addr), + virtual_stack_vars_rtx); + emit_move_insn + (validize_mem (gen_rtx_MEM (Pmode, + plus_constant (buf_addr, + GET_MODE_SIZE (Pmode)))), + gen_rtx_LABEL_REF (Pmode, lab1)); - /* If LEN does not expand to a constant, don't do this - operation in-line. */ - len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); - if (GET_CODE (len_rtx) != CONST_INT) - break; +#ifdef HAVE_save_stack_nonlocal + if (HAVE_save_stack_nonlocal) + sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0]; +#endif - dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM); - dest_mem = gen_rtx_MEM (BLKmode, - memory_address (BLKmode, dest_rtx)); - - /* Just check DST is writable and mark it as readable. */ - if (flag_check_memory_usage) - emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3, - dest_rtx, ptr_mode, - len_rtx, TYPE_MODE (sizetype), - GEN_INT (MEMORY_USE_WO), - TYPE_MODE (integer_type_node)); + stack_save = gen_rtx_MEM (sa_mode, + plus_constant (buf_addr, + 2 * GET_MODE_SIZE (Pmode))); + emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX); - /* There could be a void* cast on top of the object. */ - while (TREE_CODE (dest) == NOP_EXPR) - dest = TREE_OPERAND (dest, 0); - type = TREE_TYPE (TREE_TYPE (dest)); - MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type); +#ifdef HAVE_setjmp + if (HAVE_setjmp) + emit_insn (gen_setjmp ()); +#endif - dest_addr = clear_storage (dest_mem, len_rtx, dest_align); + /* Set TARGET to zero and branch around the other case. */ + emit_move_insn (target, const0_rtx); + emit_jump_insn (gen_jump (lab2)); + emit_barrier (); + emit_label (lab1); - if (dest_addr == 0) - dest_addr = force_operand (dest_rtx, NULL_RTX); + /* Note that setjmp clobbers FP when we get here, so we have to make + sure it's marked as used by this function. */ + emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - return dest_addr; - } + /* Mark the static chain as clobbered here so life information + doesn't get messed up for it. */ + emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx)); -/* These comparison functions need an instruction that returns an actual - index. An ordinary compare that just sets the condition codes - is not enough. */ -#ifdef HAVE_cmpstrsi - case BUILT_IN_STRCMP: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; + /* Now put in the code to restore the frame pointer, and argument + pointer, if needed. The code below is from expand_end_bindings + in stmt.c; see detailed documentation there. */ +#ifdef HAVE_nonlocal_goto + if (! HAVE_nonlocal_goto) +#endif + emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx); - /* If we need to check memory accesses, call the library function. */ - if (flag_check_memory_usage) - break; + current_function_has_nonlocal_label = 1; - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE) - break; - else if (!HAVE_cmpstrsi) - break; - { - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree offset; - tree len, len2; +#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + if (fixed_regs[ARG_POINTER_REGNUM]) + { +#ifdef ELIMINABLE_REGS + static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS; - len = c_strlen (arg1); - if (len) - len = size_binop (PLUS_EXPR, integer_one_node, len); - len2 = c_strlen (arg2); - if (len2) - len2 = size_binop (PLUS_EXPR, integer_one_node, len2); + for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++) + if (elim_regs[i].from == ARG_POINTER_REGNUM + && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM) + break; - /* If we don't have a constant length for the first, use the length - of the second, if we know it. We don't require a constant for - this case; some cost analysis could be done if both are available - but neither is constant. For now, assume they're equally cheap. + if (i == sizeof elim_regs / sizeof elim_regs [0]) +#endif + { + /* Now restore our arg pointer from the address at which it + was saved in our stack frame. + If there hasn't be space allocated for it yet, make + some now. */ + if (arg_pointer_save_area == 0) + arg_pointer_save_area + = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); + emit_move_insn (virtual_incoming_args_rtx, + copy_to_reg (arg_pointer_save_area)); + } + } +#endif - If both strings have constant lengths, use the smaller. This - could arise if optimization results in strcpy being called with - two fixed strings, or if the code was machine-generated. We should - add some code to the `memcmp' handler below to deal with such - situations, someday. */ - if (!len || TREE_CODE (len) != INTEGER_CST) - { - if (len2) - len = len2; - else if (len == 0) - break; - } - else if (len2 && TREE_CODE (len2) == INTEGER_CST) - { - if (tree_int_cst_lt (len2, len)) - len = len2; - } +#ifdef HAVE_nonlocal_goto_receiver + if (HAVE_nonlocal_goto_receiver) + emit_insn (gen_nonlocal_goto_receiver ()); +#endif + /* The static chain pointer contains the address of dummy function. + We need to call it here to handle some PIC cases of restoring a + global pointer. Then return 1. */ + op0 = copy_to_mode_reg (Pmode, static_chain_rtx); - chainon (arglist, build_tree_list (NULL_TREE, len)); - } + /* We can't actually call emit_library_call here, so do everything + it does, which isn't much for a libfunc with no args. */ + op0 = memory_address (FUNCTION_MODE, op0); - /* Drops in. */ - case BUILT_IN_MEMCMP: - /* If not optimizing, call the library function. */ - if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) - break; + INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, + gen_rtx_SYMBOL_REF (Pmode, "__dummy"), 1); + next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1); - /* If we need to check memory accesses, call the library function. */ - if (flag_check_memory_usage) - break; +#ifndef ACCUMULATE_OUTGOING_ARGS +#ifdef HAVE_call_pop + if (HAVE_call_pop) + emit_call_insn (gen_call_pop (gen_rtx_MEM (FUNCTION_MODE, op0), + const0_rtx, next_arg_reg, + GEN_INT (return_pops))); + else +#endif +#endif - if (arglist == 0 - /* Arg could be non-pointer if user redeclared this fcn wrong. */ - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE - || TREE_CHAIN (arglist) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE - || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE) - break; - else if (!HAVE_cmpstrsi) - break; - { - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); - rtx result; +#ifdef HAVE_call + if (HAVE_call) + emit_call_insn (gen_call (gen_rtx_MEM (FUNCTION_MODE, op0), + const0_rtx, next_arg_reg, const0_rtx)); + else +#endif + abort (); - int arg1_align - = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int arg2_align - = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - enum machine_mode insn_mode - = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0]; +#ifdef HAVE_builtin_setjmp_receiver + if (HAVE_builtin_setjmp_receiver) + emit_insn (gen_builtin_setjmp_receiver ()); +#endif - /* If we don't have POINTER_TYPE, call the function. */ - if (arg1_align == 0 || arg2_align == 0) - { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCMP) - TREE_CHAIN (TREE_CHAIN (arglist)) = 0; - break; - } + emit_move_insn (target, const1_rtx); + emit_label (lab2); + return target; +} - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && GET_CODE (result) == REG && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); + +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ - emit_insn (gen_cmpstrsi (result, - gen_rtx_MEM (BLKmode, - expand_expr (arg1, NULL_RTX, - ptr_mode, - EXPAND_NORMAL)), - gen_rtx_MEM (BLKmode, - expand_expr (arg2, NULL_RTX, - ptr_mode, - EXPAND_NORMAL)), - expand_expr (len, NULL_RTX, VOIDmode, 0), - GEN_INT (MIN (arg1_align, arg2_align)))); +#define CALLED_AS_BUILT_IN(NODE) \ + (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10)) - /* Return the value in the proper mode for this function. */ - mode = TYPE_MODE (TREE_TYPE (exp)); - if (GET_MODE (result) == mode) - return result; - else if (target != 0) - { - convert_move (target, result, 0); - return target; - } - else - return convert_to_mode (mode, result, 0); - } -#else - case BUILT_IN_STRCMP: - case BUILT_IN_MEMCMP: - break; -#endif +static rtx +expand_builtin (exp, target, subtarget, mode, ignore) + tree exp; + rtx target; + rtx subtarget; + enum machine_mode mode; + int ignore; +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree arglist = TREE_OPERAND (exp, 1); + rtx op0; + rtx lab1, insns; + enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp)); + optab builtin_optab; - case BUILT_IN_SETJMP: - if (arglist == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) - break; + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_FABS: + /* build_function_call changes these into ABS_EXPR. */ + abort (); - { - rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget, - VOIDmode, 0); - return expand_builtin_setjmp (buf_addr, target); - } + case BUILT_IN_SIN: + case BUILT_IN_COS: + /* Treat these like sqrt, but only if the user asks for them. */ + if (! flag_fast_math) + break; + case BUILT_IN_FSQRT: + /* If not optimizing, call the library function. */ + if (! optimize) + break; - /* __builtin_longjmp is passed a pointer to an array of five words - and a value, which is a dummy. It's similar to the C library longjmp - function but works with __builtin_setjmp above. */ - case BUILT_IN_LONGJMP: - if (arglist == 0 || TREE_CHAIN (arglist) == 0 - || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) + if (arglist == 0 + /* Arg could be wrong type if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE) break; - { - tree dummy_id = get_identifier ("__dummy"); - tree dummy_type = build_function_type (void_type_node, NULL_TREE); - tree dummy_decl = build_decl (FUNCTION_DECL, dummy_id, dummy_type); -#ifdef POINTERS_EXTEND_UNSIGNED - rtx buf_addr - = force_reg (Pmode, - convert_memory_address - (Pmode, - expand_expr (TREE_VALUE (arglist), - NULL_RTX, VOIDmode, 0))); -#else - rtx buf_addr - = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), - NULL_RTX, - VOIDmode, 0)); -#endif - rtx fp = gen_rtx_MEM (Pmode, buf_addr); - rtx lab = gen_rtx_MEM (Pmode, - plus_constant (buf_addr, - GET_MODE_SIZE (Pmode))); - enum machine_mode sa_mode -#ifdef HAVE_save_stack_nonlocal - = (HAVE_save_stack_nonlocal - ? insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0] - : Pmode); -#else - = Pmode; -#endif - rtx stack = gen_rtx_MEM (sa_mode, - plus_constant (buf_addr, - 2 * GET_MODE_SIZE (Pmode))); + /* Stabilize and compute the argument. */ + if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL + && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL) + { + exp = copy_node (exp); + arglist = copy_node (arglist); + TREE_OPERAND (exp, 1) = arglist; + TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist)); + } + op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); - DECL_EXTERNAL (dummy_decl) = 1; - TREE_PUBLIC (dummy_decl) = 1; - make_decl_rtl (dummy_decl, NULL_PTR, 1); + /* Make a suitable register to place result in. */ + target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); - /* Expand the second expression just for side-effects. */ - expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), - const0_rtx, VOIDmode, 0); + emit_queue (); + start_sequence (); - assemble_external (dummy_decl); + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_SIN: + builtin_optab = sin_optab; break; + case BUILT_IN_COS: + builtin_optab = cos_optab; break; + case BUILT_IN_FSQRT: + builtin_optab = sqrt_optab; break; + default: + abort (); + } - /* Pick up FP, label, and SP from the block and jump. This code is - from expand_goto in stmt.c; see there for detailed comments. */ -#if HAVE_nonlocal_goto - if (HAVE_nonlocal_goto) - emit_insn (gen_nonlocal_goto (fp, lab, stack, - XEXP (DECL_RTL (dummy_decl), 0))); - else -#endif + /* Compute into TARGET. + Set TARGET to wherever the result comes back. */ + target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), + builtin_optab, op0, target, 0); + + /* If we were unable to expand via the builtin, stop the + sequence (without outputting the insns) and break, causing + a call the the library function. */ + if (target == 0) { - lab = copy_to_reg (lab); - emit_move_insn (hard_frame_pointer_rtx, fp); - emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); + end_sequence (); + break; + } - /* Put in the static chain register the address of the dummy - function. */ - emit_move_insn (static_chain_rtx, XEXP (DECL_RTL (dummy_decl), 0)); - emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx)); - emit_indirect_jump (lab); - } + /* Check the results by default. But if flag_fast_math is turned on, + then assume sqrt will always be called with valid arguments. */ - return const0_rtx; - } + if (! flag_fast_math) + { + /* Don't define the builtin FP instructions + if your machine is not IEEE. */ + if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT) + abort (); - /* Various hooks for the DWARF 2 __throw routine. */ - case BUILT_IN_UNWIND_INIT: - expand_builtin_unwind_init (); - return const0_rtx; - case BUILT_IN_FP: - return frame_pointer_rtx; - case BUILT_IN_SP: - return stack_pointer_rtx; -#ifdef DWARF2_UNWIND_INFO - case BUILT_IN_DWARF_FP_REGNUM: - return expand_builtin_dwarf_fp_regnum (); - case BUILT_IN_DWARF_REG_SIZE: - return expand_builtin_dwarf_reg_size (TREE_VALUE (arglist), target); -#endif - case BUILT_IN_FROB_RETURN_ADDR: - return expand_builtin_frob_return_addr (TREE_VALUE (arglist)); - case BUILT_IN_EXTRACT_RETURN_ADDR: - return expand_builtin_extract_return_addr (TREE_VALUE (arglist)); - case BUILT_IN_SET_RETURN_ADDR_REG: - expand_builtin_set_return_addr_reg (TREE_VALUE (arglist)); - return const0_rtx; - case BUILT_IN_EH_STUB: - return expand_builtin_eh_stub (); - case BUILT_IN_SET_EH_REGS: - expand_builtin_set_eh_regs (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist))); - return const0_rtx; + lab1 = gen_label_rtx (); - default: /* just do library call, if unknown builtin */ - error ("built-in function `%s' not currently supported", - IDENTIFIER_POINTER (DECL_NAME (fndecl))); - } + /* Test the result; if it is NaN, set errno=EDOM because + the argument was not in the domain. */ + emit_cmp_insn (target, target, EQ, 0, GET_MODE (target), 0, 0); + emit_jump_insn (gen_beq (lab1)); + +#ifdef TARGET_EDOM + { +#ifdef GEN_ERRNO_RTX + rtx errno_rtx = GEN_ERRNO_RTX; +#else + rtx errno_rtx + = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno")); +#endif - /* The switch statement above can drop through to cause the function - to be called normally. */ + emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM)); + } +#else + /* We can't set errno=EDOM directly; let the library call do it. + Pop the arguments right away in case the call gets deleted. */ + NO_DEFER_POP; + expand_call (exp, target, 0); + OK_DEFER_POP; +#endif - return expand_call (exp, target, ignore); -} - -/* Built-in functions to perform an untyped call and return. */ + emit_label (lab1); + } -/* For each register that may be used for calling a function, this - gives a mode used to copy the register's value. VOIDmode indicates - the register is not used for calling a function. If the machine - has register windows, this gives only the outbound registers. - INCOMING_REGNO gives the corresponding inbound register. */ -static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER]; + /* Output the entire sequence. */ + insns = get_insns (); + end_sequence (); + emit_insns (insns); + + return target; -/* For each register that may be used for returning values, this gives - a mode used to copy the register's value. VOIDmode indicates the - register is not used for returning values. If the machine has - register windows, this gives only the outbound registers. - INCOMING_REGNO gives the corresponding inbound register. */ -static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER]; + case BUILT_IN_FMOD: + break; -/* For each register that may be used for calling a function, this - gives the offset of that register into the block returned by - __builtin_apply_args. 0 indicates that the register is not - used for calling a function. */ -static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER]; + /* __builtin_apply_args returns block of memory allocated on + the stack into which is stored the arg pointer, structure + value address, static chain, and all the registers that might + possibly be used in performing a function call. The code is + moved to the start of the function so the incoming values are + saved. */ + case BUILT_IN_APPLY_ARGS: + /* Don't do __builtin_apply_args more than once in a function. + Save the result of the first call and reuse it. */ + if (apply_args_value != 0) + return apply_args_value; + { + /* When this function is called, it means that registers must be + saved on entry to this function. So we migrate the + call to the first insn of this function. */ + rtx temp; + rtx seq; -/* Return the offset of register REGNO into the block returned by - __builtin_apply_args. This is not declared static, since it is - needed in objc-act.c. */ + start_sequence (); + temp = expand_builtin_apply_args (); + seq = get_insns (); + end_sequence (); -int -apply_args_register_offset (regno) - int regno; -{ - apply_args_size (); + apply_args_value = temp; - /* Arguments are always put in outgoing registers (in the argument - block) if such make sense. */ -#ifdef OUTGOING_REGNO - regno = OUTGOING_REGNO(regno); -#endif - return apply_args_reg_offset[regno]; -} + /* Put the sequence after the NOTE that starts the function. + If this is inside a SEQUENCE, make the outer-level insn + chain current, so the code is placed at the start of the + function. */ + push_topmost_sequence (); + emit_insns_before (seq, NEXT_INSN (get_insns ())); + pop_topmost_sequence (); + return temp; + } -/* Return the size required for the block returned by __builtin_apply_args, - and initialize apply_args_mode. */ + /* __builtin_apply (FUNCTION, ARGUMENTS, ARGSIZE) invokes + FUNCTION with a copy of the parameters described by + ARGUMENTS, and ARGSIZE. It returns a block of memory + allocated on the stack into which is stored all the registers + that might possibly be used for returning the result of a + function. ARGUMENTS is the value returned by + __builtin_apply_args. ARGSIZE is the number of bytes of + arguments that must be copied. ??? How should this value be + computed? We'll also need a safe worst case value for varargs + functions. */ + case BUILT_IN_APPLY: + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE + || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE) + return const0_rtx; + else + { + int i; + tree t; + rtx ops[3]; -static int -apply_args_size () -{ - static int size = -1; - int align, regno; - enum machine_mode mode; + for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++) + ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0); - /* The values computed by this function never change. */ - if (size < 0) - { - /* The first value is the incoming arg-pointer. */ - size = GET_MODE_SIZE (Pmode); + return expand_builtin_apply (ops[0], ops[1], ops[2]); + } - /* The second value is the structure value address unless this is - passed as an "invisible" first argument. */ - if (struct_value_rtx) - size += GET_MODE_SIZE (Pmode); + /* __builtin_return (RESULT) causes the function to return the + value described by RESULT. RESULT is address of the block of + memory returned by __builtin_apply. */ + case BUILT_IN_RETURN: + if (arglist + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE) + expand_builtin_return (expand_expr (TREE_VALUE (arglist), + NULL_RTX, VOIDmode, 0)); + return const0_rtx; - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (FUNCTION_ARG_REGNO_P (regno)) - { - /* Search for the proper mode for copying this register's - value. I'm not sure this is right, but it works so far. */ - enum machine_mode best_mode = VOIDmode; + case BUILT_IN_SAVEREGS: + /* Don't do __builtin_saveregs more than once in a function. + Save the result of the first call and reuse it. */ + if (saveregs_value != 0) + return saveregs_value; + { + /* When this function is called, it means that registers must be + saved on entry to this function. So we migrate the + call to the first insn of this function. */ + rtx temp; + rtx seq; - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_MODE_OK (regno, mode) - && HARD_REGNO_NREGS (regno, mode) == 1) - best_mode = mode; + /* Now really call the function. `expand_call' does not call + expand_builtin, so there is no danger of infinite recursion here. */ + start_sequence (); - if (best_mode == VOIDmode) - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); - mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_MODE_OK (regno, mode) - && (mov_optab->handlers[(int) mode].insn_code - != CODE_FOR_nothing)) - best_mode = mode; +#ifdef EXPAND_BUILTIN_SAVEREGS + /* Do whatever the machine needs done in this case. */ + temp = EXPAND_BUILTIN_SAVEREGS (arglist); +#else + /* The register where the function returns its value + is likely to have something else in it, such as an argument. + So preserve that register around the call. */ - mode = best_mode; - if (mode == VOIDmode) - abort (); + if (value_mode != VOIDmode) + { + rtx valreg = hard_libcall_value (value_mode); + rtx saved_valreg = gen_reg_rtx (value_mode); - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; - apply_args_reg_offset[regno] = size; - size += GET_MODE_SIZE (mode); - apply_args_mode[regno] = mode; + emit_move_insn (saved_valreg, valreg); + temp = expand_call (exp, target, ignore); + emit_move_insn (valreg, saved_valreg); } else - { - apply_args_mode[regno] = VOIDmode; - apply_args_reg_offset[regno] = 0; - } - } - return size; -} - -/* Return the size required for the block returned by __builtin_apply, - and initialize apply_result_mode. */ + /* Generate the call, putting the value in a pseudo. */ + temp = expand_call (exp, target, ignore); +#endif -static int -apply_result_size () -{ - static int size = -1; - int align, regno; - enum machine_mode mode; + seq = get_insns (); + end_sequence (); - /* The values computed by this function never change. */ - if (size < 0) - { - size = 0; + saveregs_value = temp; - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (FUNCTION_VALUE_REGNO_P (regno)) - { - /* Search for the proper mode for copying this register's - value. I'm not sure this is right, but it works so far. */ - enum machine_mode best_mode = VOIDmode; + /* Put the sequence after the NOTE that starts the function. + If this is inside a SEQUENCE, make the outer-level insn + chain current, so the code is placed at the start of the + function. */ + push_topmost_sequence (); + emit_insns_before (seq, NEXT_INSN (get_insns ())); + pop_topmost_sequence (); + return temp; + } - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - mode != TImode; - mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_MODE_OK (regno, mode)) - best_mode = mode; + /* __builtin_args_info (N) returns word N of the arg space info + for the current function. The number and meanings of words + is controlled by the definition of CUMULATIVE_ARGS. */ + case BUILT_IN_ARGS_INFO: + { + int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int); + int i; + int *word_ptr = (int *) ¤t_function_args_info; + tree type, elts, result; - if (best_mode == VOIDmode) - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); - mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) - if (HARD_REGNO_MODE_OK (regno, mode) - && (mov_optab->handlers[(int) mode].insn_code - != CODE_FOR_nothing)) - best_mode = mode; + if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0) + fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d", + __FILE__, __LINE__); - mode = best_mode; - if (mode == VOIDmode) - abort (); + if (arglist != 0) + { + tree arg = TREE_VALUE (arglist); + if (TREE_CODE (arg) != INTEGER_CST) + error ("argument of `__builtin_args_info' must be constant"); + else + { + int wordnum = TREE_INT_CST_LOW (arg); - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; - size += GET_MODE_SIZE (mode); - apply_result_mode[regno] = mode; + if (wordnum < 0 || wordnum >= nwords || TREE_INT_CST_HIGH (arg)) + error ("argument of `__builtin_args_info' out of range"); + else + return GEN_INT (word_ptr[wordnum]); + } } else - apply_result_mode[regno] = VOIDmode; + error ("missing argument in `__builtin_args_info'"); - /* Allow targets that use untyped_call and untyped_return to override - the size so that machine-specific information can be stored here. */ -#ifdef APPLY_RESULT_SIZE - size = APPLY_RESULT_SIZE; -#endif - } - return size; -} + return const0_rtx; -#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return) -/* Create a vector describing the result block RESULT. If SAVEP is true, - the result block is used to save the values; otherwise it is used to - restore the values. */ +#if 0 + for (i = 0; i < nwords; i++) + elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0)); -static rtx -result_vector (savep, result) - int savep; - rtx result; -{ - int regno, size, align, nelts; - enum machine_mode mode; - rtx reg, mem; - rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx)); - - size = nelts = 0; - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((mode = apply_result_mode[regno]) != VOIDmode) + type = build_array_type (integer_type_node, + build_index_type (build_int_2 (nwords, 0))); + result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts)); + TREE_CONSTANT (result) = 1; + TREE_STATIC (result) = 1; + result = build (INDIRECT_REF, build_pointer_type (type), result); + TREE_CONSTANT (result) = 1; + return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD); +#endif + } + + /* Return the address of the first anonymous stack arg. */ + case BUILT_IN_NEXT_ARG: { - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; - reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno)); - mem = change_address (result, mode, - plus_constant (XEXP (result, 0), size)); - savevec[nelts++] = (savep - ? gen_rtx_SET (VOIDmode, mem, reg) - : gen_rtx_SET (VOIDmode, reg, mem)); - size += GET_MODE_SIZE (mode); + tree fntype = TREE_TYPE (current_function_decl); + + if ((TYPE_ARG_TYPES (fntype) == 0 + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + == void_type_node)) + && ! current_function_varargs) + { + error ("`va_start' used in function with fixed args"); + return const0_rtx; + } + + if (arglist) + { + tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl)); + tree arg = TREE_VALUE (arglist); + + /* Strip off all nops for the sake of the comparison. This + is not quite the same as STRIP_NOPS. It does more. + We must also strip off INDIRECT_EXPR for C++ reference + parameters. */ + while (TREE_CODE (arg) == NOP_EXPR + || TREE_CODE (arg) == CONVERT_EXPR + || TREE_CODE (arg) == NON_LVALUE_EXPR + || TREE_CODE (arg) == INDIRECT_REF) + arg = TREE_OPERAND (arg, 0); + if (arg != last_parm) + warning ("second parameter of `va_start' not last named argument"); + } + else if (! current_function_varargs) + /* Evidently an out of date version of ; can't validate + va_start's second argument, but can still work as intended. */ + warning ("`__builtin_next_arg' called without an argument"); } - return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec)); -} -#endif /* HAVE_untyped_call or HAVE_untyped_return */ -/* Save the state required to perform an untyped call with the same - arguments as were passed to the current function. */ + return expand_binop (Pmode, add_optab, + current_function_internal_arg_pointer, + current_function_arg_offset_rtx, + NULL_RTX, 0, OPTAB_LIB_WIDEN); -static rtx -expand_builtin_apply_args () -{ - rtx registers; - int size, align, regno; - enum machine_mode mode; + case BUILT_IN_CLASSIFY_TYPE: + if (arglist != 0) + { + tree type = TREE_TYPE (TREE_VALUE (arglist)); + enum tree_code code = TREE_CODE (type); + if (code == VOID_TYPE) + return GEN_INT (void_type_class); + if (code == INTEGER_TYPE) + return GEN_INT (integer_type_class); + if (code == CHAR_TYPE) + return GEN_INT (char_type_class); + if (code == ENUMERAL_TYPE) + return GEN_INT (enumeral_type_class); + if (code == BOOLEAN_TYPE) + return GEN_INT (boolean_type_class); + if (code == POINTER_TYPE) + return GEN_INT (pointer_type_class); + if (code == REFERENCE_TYPE) + return GEN_INT (reference_type_class); + if (code == OFFSET_TYPE) + return GEN_INT (offset_type_class); + if (code == REAL_TYPE) + return GEN_INT (real_type_class); + if (code == COMPLEX_TYPE) + return GEN_INT (complex_type_class); + if (code == FUNCTION_TYPE) + return GEN_INT (function_type_class); + if (code == METHOD_TYPE) + return GEN_INT (method_type_class); + if (code == RECORD_TYPE) + return GEN_INT (record_type_class); + if (code == UNION_TYPE || code == QUAL_UNION_TYPE) + return GEN_INT (union_type_class); + if (code == ARRAY_TYPE) + { + if (TYPE_STRING_FLAG (type)) + return GEN_INT (string_type_class); + else + return GEN_INT (array_type_class); + } + if (code == SET_TYPE) + return GEN_INT (set_type_class); + if (code == FILE_TYPE) + return GEN_INT (file_type_class); + if (code == LANG_TYPE) + return GEN_INT (lang_type_class); + } + return GEN_INT (no_type_class); - /* Create a block where the arg-pointer, structure value address, - and argument registers can be saved. */ - registers = assign_stack_local (BLKmode, apply_args_size (), -1); + case BUILT_IN_CONSTANT_P: + if (arglist == 0) + return const0_rtx; + else + { + tree arg = TREE_VALUE (arglist); - /* Walk past the arg-pointer and structure value address. */ - size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) - size += GET_MODE_SIZE (Pmode); + STRIP_NOPS (arg); + return (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c' + || (TREE_CODE (arg) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST) + ? const1_rtx : const0_rtx); + } - /* Save each register used in calling a function to the block. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((mode = apply_args_mode[regno]) != VOIDmode) - { - rtx tem; + case BUILT_IN_FRAME_ADDRESS: + /* The argument must be a nonnegative integer constant. + It counts the number of frames to scan up the stack. + The value is the address of that frame. */ + case BUILT_IN_RETURN_ADDRESS: + /* The argument must be a nonnegative integer constant. + It counts the number of frames to scan up the stack. + The value is the return address saved in that frame. */ + if (arglist == 0) + /* Warning about missing arg was already issued. */ + return const0_rtx; + else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST + || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0) + { + if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) + error ("invalid arg to `__builtin_frame_address'"); + else + error ("invalid arg to `__builtin_return_address'"); + return const0_rtx; + } + else + { + rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), + TREE_INT_CST_LOW (TREE_VALUE (arglist)), + hard_frame_pointer_rtx); - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; + /* Some ports cannot access arbitrary stack frames. */ + if (tem == NULL) + { + if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) + warning ("unsupported arg to `__builtin_frame_address'"); + else + warning ("unsupported arg to `__builtin_return_address'"); + return const0_rtx; + } - tem = gen_rtx_REG (mode, INCOMING_REGNO (regno)); + /* For __builtin_frame_address, return what we've got. */ + if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) + return tem; -#ifdef STACK_REGS - /* For reg-stack.c's stack register household. - Compare with a similar piece of code in function.c. */ + if (GET_CODE (tem) != REG) + tem = copy_to_reg (tem); + return tem; + } - emit_insn (gen_rtx_USE (mode, tem)); -#endif + /* Returns the address of the area where the structure is returned. + 0 otherwise. */ + case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: + if (arglist != 0 + || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))) + || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM) + return const0_rtx; + else + return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); - emit_move_insn (change_address (registers, mode, - plus_constant (XEXP (registers, 0), - size)), - tem); - size += GET_MODE_SIZE (mode); - } + case BUILT_IN_ALLOCA: + if (arglist == 0 + /* Arg could be non-integer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) + break; - /* Save the arg pointer to the block. */ - emit_move_insn (change_address (registers, Pmode, XEXP (registers, 0)), - copy_to_reg (virtual_incoming_args_rtx)); - size = GET_MODE_SIZE (Pmode); + /* Compute the argument. */ + op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); - /* Save the structure value address unless this is passed as an - "invisible" first argument. */ - if (struct_value_incoming_rtx) - { - emit_move_insn (change_address (registers, Pmode, - plus_constant (XEXP (registers, 0), - size)), - copy_to_reg (struct_value_incoming_rtx)); - size += GET_MODE_SIZE (Pmode); - } + /* Allocate the desired space. */ + return allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT); - /* Return the address of the block. */ - return copy_addr_to_reg (XEXP (registers, 0)); -} + case BUILT_IN_FFS: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; -/* Perform an untyped call and save the state required to perform an - untyped return of whatever value was returned by the given function. */ + if (arglist == 0 + /* Arg could be non-integer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) + break; -static rtx -expand_builtin_apply (function, arguments, argsize) - rtx function, arguments, argsize; -{ - int size, align, regno; - enum machine_mode mode; - rtx incoming_args, result, reg, dest, call_insn; - rtx old_stack_level = 0; - rtx call_fusage = 0; + /* Compute the argument. */ + op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); + /* Compute ffs, into TARGET if possible. + Set TARGET to wherever the result comes back. */ + target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), + ffs_optab, op0, target, 1); + if (target == 0) + abort (); + return target; - /* Create a block where the return registers can be saved. */ - result = assign_stack_local (BLKmode, apply_result_size (), -1); + case BUILT_IN_STRLEN: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; - /* ??? The argsize value should be adjusted here. */ + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) + break; + else + { + tree src = TREE_VALUE (arglist); + tree len = c_strlen (src); - /* Fetch the arg pointer from the ARGUMENTS block. */ - incoming_args = gen_reg_rtx (Pmode); - emit_move_insn (incoming_args, - gen_rtx_MEM (Pmode, arguments)); -#ifndef STACK_GROWS_DOWNWARD - incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize, - incoming_args, 0, OPTAB_LIB_WIDEN); -#endif + int align + = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - /* Perform postincrements before actually calling the function. */ - emit_queue (); + rtx result, src_rtx, char_rtx; + enum machine_mode insn_mode = value_mode, char_mode; + enum insn_code icode; - /* Push a new argument block and copy the arguments. */ - do_pending_stack_adjust (); + /* If the length is known, just return it. */ + if (len != 0) + return expand_expr (len, target, mode, EXPAND_MEMORY_USE_BAD); - /* Save the stack with nonlocal if available */ -#ifdef HAVE_save_stack_nonlocal - if (HAVE_save_stack_nonlocal) - emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX); - else -#endif - emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + /* If SRC is not a pointer type, don't do this operation inline. */ + if (align == 0) + break; - /* Push a block of memory onto the stack to store the memory arguments. - Save the address in a register, and copy the memory arguments. ??? I - haven't figured out how the calling convention macros effect this, - but it's likely that the source and/or destination addresses in - the block copy will need updating in machine specific ways. */ - dest = allocate_dynamic_stack_space (argsize, 0, 0); - emit_block_move (gen_rtx_MEM (BLKmode, dest), - gen_rtx_MEM (BLKmode, incoming_args), - argsize, - PARM_BOUNDARY / BITS_PER_UNIT); + /* Call a function if we can't compute strlen in the right mode. */ - /* Refer to the argument block. */ - apply_args_size (); - arguments = gen_rtx_MEM (BLKmode, arguments); + while (insn_mode != VOIDmode) + { + icode = strlen_optab->handlers[(int) insn_mode].insn_code; + if (icode != CODE_FOR_nothing) + break; - /* Walk past the arg-pointer and structure value address. */ - size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) - size += GET_MODE_SIZE (Pmode); + insn_mode = GET_MODE_WIDER_MODE (insn_mode); + } + if (insn_mode == VOIDmode) + break; - /* Restore each of the registers previously saved. Make USE insns - for each of these registers for use in making the call. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((mode = apply_args_mode[regno]) != VOIDmode) - { - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; - reg = gen_rtx_REG (mode, regno); - emit_move_insn (reg, - change_address (arguments, mode, - plus_constant (XEXP (arguments, 0), - size))); + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && GET_CODE (result) == REG + && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); - use_reg (&call_fusage, reg); - size += GET_MODE_SIZE (mode); - } + /* Make sure the operands are acceptable to the predicates. */ - /* Restore the structure value address unless this is passed as an - "invisible" first argument. */ - size = GET_MODE_SIZE (Pmode); - if (struct_value_rtx) - { - rtx value = gen_reg_rtx (Pmode); - emit_move_insn (value, - change_address (arguments, Pmode, - plus_constant (XEXP (arguments, 0), - size))); - emit_move_insn (struct_value_rtx, value); - if (GET_CODE (struct_value_rtx) == REG) - use_reg (&call_fusage, struct_value_rtx); - size += GET_MODE_SIZE (Pmode); - } + if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode)) + result = gen_reg_rtx (insn_mode); + src_rtx = memory_address (BLKmode, + expand_expr (src, NULL_RTX, ptr_mode, + EXPAND_NORMAL)); - /* All arguments and registers used for the call are set up by now! */ - function = prepare_call_address (function, NULL_TREE, &call_fusage, 0); + if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode)) + src_rtx = copy_to_mode_reg (Pmode, src_rtx); - /* Ensure address is valid. SYMBOL_REF is already valid, so no need, - and we don't want to load it into a register as an optimization, - because prepare_call_address already did it if it should be done. */ - if (GET_CODE (function) != SYMBOL_REF) - function = memory_address (FUNCTION_MODE, function); + /* Check the string is readable and has an end. */ + if (flag_check_memory_usage) + emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2, + src_rtx, ptr_mode, + GEN_INT (MEMORY_USE_RO), + TYPE_MODE (integer_type_node)); - /* Generate the actual call instruction and save the return value. */ -#ifdef HAVE_untyped_call - if (HAVE_untyped_call) - emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function), - result, result_vector (1, result))); - else -#endif -#ifdef HAVE_call_value - if (HAVE_call_value) - { - rtx valreg = 0; + char_rtx = const0_rtx; + char_mode = insn_operand_mode[(int)icode][2]; + if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode)) + char_rtx = copy_to_mode_reg (char_mode, char_rtx); - /* Locate the unique return register. It is not possible to - express a call that sets more than one return register using - call_value; use untyped_call for that. In fact, untyped_call - only needs to save the return registers in the given block. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((mode = apply_result_mode[regno]) != VOIDmode) - { - if (valreg) - abort (); /* HAVE_untyped_call required. */ - valreg = gen_rtx_REG (mode, regno); - } + emit_insn (GEN_FCN (icode) (result, + gen_rtx_MEM (BLKmode, src_rtx), + char_rtx, GEN_INT (align))); - emit_call_insn (gen_call_value (valreg, - gen_rtx_MEM (FUNCTION_MODE, function), - const0_rtx, NULL_RTX, const0_rtx)); + /* Return the value in the proper mode for this function. */ + if (GET_MODE (result) == value_mode) + return result; + else if (target != 0) + { + convert_move (target, result, 0); + return target; + } + else + return convert_to_mode (value_mode, result, 0); + } - emit_move_insn (change_address (result, GET_MODE (valreg), - XEXP (result, 0)), - valreg); - } - else -#endif - abort (); + case BUILT_IN_STRCPY: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; - /* Find the CALL insn we just emitted. */ - for (call_insn = get_last_insn (); - call_insn && GET_CODE (call_insn) != CALL_INSN; - call_insn = PREV_INSN (call_insn)) - ; + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE) + break; + else + { + tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); - if (! call_insn) - abort (); + if (len == 0) + break; - /* Put the register usage information on the CALL. If there is already - some usage information, put ours at the end. */ - if (CALL_INSN_FUNCTION_USAGE (call_insn)) - { - rtx link; + len = size_binop (PLUS_EXPR, len, integer_one_node); - for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0; - link = XEXP (link, 1)) - ; + chainon (arglist, build_tree_list (NULL_TREE, len)); + } - XEXP (link, 1) = call_fusage; - } - else - CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage; + /* Drops in. */ + case BUILT_IN_MEMCPY: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; - /* Restore the stack. */ -#ifdef HAVE_save_stack_nonlocal - if (HAVE_save_stack_nonlocal) - emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX); - else -#endif - emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) + != POINTER_TYPE) + || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 + || (TREE_CODE (TREE_TYPE (TREE_VALUE + (TREE_CHAIN (TREE_CHAIN (arglist))))) + != INTEGER_TYPE)) + break; + else + { + tree dest = TREE_VALUE (arglist); + tree src = TREE_VALUE (TREE_CHAIN (arglist)); + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + tree type; - /* Return the address of the result block. */ - return copy_addr_to_reg (XEXP (result, 0)); -} + int src_align + = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int dest_align + = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + rtx dest_rtx, dest_mem, src_mem, src_rtx, dest_addr, len_rtx; -/* Perform an untyped return. */ + /* If either SRC or DEST is not a pointer type, don't do + this operation in-line. */ + if (src_align == 0 || dest_align == 0) + { + if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCPY) + TREE_CHAIN (TREE_CHAIN (arglist)) = 0; + break; + } -static void -expand_builtin_return (result) - rtx result; -{ - int size, align, regno; - enum machine_mode mode; - rtx reg; - rtx call_fusage = 0; + dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM); + dest_mem = gen_rtx_MEM (BLKmode, + memory_address (BLKmode, dest_rtx)); + /* There could be a void* cast on top of the object. */ + while (TREE_CODE (dest) == NOP_EXPR) + dest = TREE_OPERAND (dest, 0); + type = TREE_TYPE (TREE_TYPE (dest)); + MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type); + src_rtx = expand_expr (src, NULL_RTX, ptr_mode, EXPAND_SUM); + src_mem = gen_rtx_MEM (BLKmode, + memory_address (BLKmode, src_rtx)); + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); - apply_result_size (); - result = gen_rtx_MEM (BLKmode, result); + /* Just copy the rights of SRC to the rights of DEST. */ + if (flag_check_memory_usage) + emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3, + dest_rtx, ptr_mode, + src_rtx, ptr_mode, + len_rtx, TYPE_MODE (sizetype)); -#ifdef HAVE_untyped_return - if (HAVE_untyped_return) - { - emit_jump_insn (gen_untyped_return (result, result_vector (0, result))); - emit_barrier (); - return; - } -#endif + /* There could be a void* cast on top of the object. */ + while (TREE_CODE (src) == NOP_EXPR) + src = TREE_OPERAND (src, 0); + type = TREE_TYPE (TREE_TYPE (src)); + MEM_IN_STRUCT_P (src_mem) = AGGREGATE_TYPE_P (type); - /* Restore the return value and note that each value is used. */ - size = 0; - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((mode = apply_result_mode[regno]) != VOIDmode) - { - align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; - if (size % align != 0) - size = CEIL (size, align) * align; - reg = gen_rtx_REG (mode, INCOMING_REGNO (regno)); - emit_move_insn (reg, - change_address (result, mode, - plus_constant (XEXP (result, 0), - size))); + /* Copy word part most expediently. */ + dest_addr + = emit_block_move (dest_mem, src_mem, len_rtx, + MIN (src_align, dest_align)); - push_to_sequence (call_fusage); - emit_insn (gen_rtx_USE (VOIDmode, reg)); - call_fusage = get_insns (); - end_sequence (); - size += GET_MODE_SIZE (mode); - } + if (dest_addr == 0) + dest_addr = force_operand (dest_rtx, NULL_RTX); - /* Put the USE insns before the return. */ - emit_insns (call_fusage); + return dest_addr; + } - /* Return whatever values was restored by jumping directly to the end - of the function. */ - expand_null_return (); -} - -/* Expand code for a post- or pre- increment or decrement - and return the RTX for the result. - POST is 1 for postinc/decrements and 0 for preinc/decrements. */ + case BUILT_IN_MEMSET: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; -static rtx -expand_increment (exp, post, ignore) - register tree exp; - int post, ignore; -{ - register rtx op0, op1; - register rtx temp, value; - register tree incremented = TREE_OPERAND (exp, 0); - optab this_optab = add_optab; - int icode; - enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); - int op0_is_copy = 0; - int single_insn = 0; - /* 1 means we can't store into OP0 directly, - because it is a subreg narrower than a word, - and we don't dare clobber the rest of the word. */ - int bad_subreg = 0; + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) + != INTEGER_TYPE) + || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 + || (INTEGER_TYPE + != (TREE_CODE (TREE_TYPE + (TREE_VALUE + (TREE_CHAIN (TREE_CHAIN (arglist)))))))) + break; + else + { + tree dest = TREE_VALUE (arglist); + tree val = TREE_VALUE (TREE_CHAIN (arglist)); + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + tree type; - if (output_bytecode) - { - bc_expand_expr (exp); - return NULL_RTX; - } + int dest_align + = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + rtx dest_rtx, dest_mem, dest_addr, len_rtx; - /* Stabilize any component ref that might need to be - evaluated more than once below. */ - if (!post - || TREE_CODE (incremented) == BIT_FIELD_REF - || (TREE_CODE (incremented) == COMPONENT_REF - && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF - || DECL_BIT_FIELD (TREE_OPERAND (incremented, 1))))) - incremented = stabilize_reference (incremented); - /* Nested *INCREMENT_EXPRs can happen in C++. We must force innermost - ones into save exprs so that they don't accidentally get evaluated - more than once by the code below. */ - if (TREE_CODE (incremented) == PREINCREMENT_EXPR - || TREE_CODE (incremented) == PREDECREMENT_EXPR) - incremented = save_expr (incremented); + /* If DEST is not a pointer type, don't do this + operation in-line. */ + if (dest_align == 0) + break; - /* Compute the operands as RTX. - Note whether OP0 is the actual lvalue or a copy of it: - I believe it is a copy iff it is a register or subreg - and insns were generated in computing it. */ + /* If VAL is not 0, don't do this operation in-line. */ + if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx) + break; - temp = get_last_insn (); - op0 = expand_expr (incremented, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_RW); + /* If LEN does not expand to a constant, don't do this + operation in-line. */ + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + if (GET_CODE (len_rtx) != CONST_INT) + break; - /* If OP0 is a SUBREG made for a promoted variable, we cannot increment - in place but instead must do sign- or zero-extension during assignment, - so we copy it into a new register and let the code below use it as - a copy. + dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM); + dest_mem = gen_rtx_MEM (BLKmode, + memory_address (BLKmode, dest_rtx)); + + /* Just check DST is writable and mark it as readable. */ + if (flag_check_memory_usage) + emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3, + dest_rtx, ptr_mode, + len_rtx, TYPE_MODE (sizetype), + GEN_INT (MEMORY_USE_WO), + TYPE_MODE (integer_type_node)); - Note that we can safely modify this SUBREG since it is know not to be - shared (it was made by the expand_expr call above). */ + /* There could be a void* cast on top of the object. */ + while (TREE_CODE (dest) == NOP_EXPR) + dest = TREE_OPERAND (dest, 0); + type = TREE_TYPE (TREE_TYPE (dest)); + MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type); - if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0)) - { - if (post) - SUBREG_REG (op0) = copy_to_reg (SUBREG_REG (op0)); - else - bad_subreg = 1; - } - else if (GET_CODE (op0) == SUBREG - && GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD) - { - /* We cannot increment this SUBREG in place. If we are - post-incrementing, get a copy of the old value. Otherwise, - just mark that we cannot increment in place. */ - if (post) - op0 = copy_to_reg (op0); - else - bad_subreg = 1; - } + dest_addr = clear_storage (dest_mem, len_rtx, dest_align); - op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) - && temp != get_last_insn ()); - op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, - EXPAND_MEMORY_USE_BAD); + if (dest_addr == 0) + dest_addr = force_operand (dest_rtx, NULL_RTX); - /* Decide whether incrementing or decrementing. */ - if (TREE_CODE (exp) == POSTDECREMENT_EXPR - || TREE_CODE (exp) == PREDECREMENT_EXPR) - this_optab = sub_optab; + return dest_addr; + } - /* Convert decrement by a constant into a negative increment. */ - if (this_optab == sub_optab - && GET_CODE (op1) == CONST_INT) - { - op1 = GEN_INT (- INTVAL (op1)); - this_optab = add_optab; - } +/* These comparison functions need an instruction that returns an actual + index. An ordinary compare that just sets the condition codes + is not enough. */ +#ifdef HAVE_cmpstrsi + case BUILT_IN_STRCMP: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; - /* For a preincrement, see if we can do this with a single instruction. */ - if (!post) - { - icode = (int) this_optab->handlers[(int) mode].insn_code; - if (icode != (int) CODE_FOR_nothing - /* Make sure that OP0 is valid for operands 0 and 1 - of the insn we want to queue. */ - && (*insn_operand_predicate[icode][0]) (op0, mode) - && (*insn_operand_predicate[icode][1]) (op0, mode) - && (*insn_operand_predicate[icode][2]) (op1, mode)) - single_insn = 1; - } + /* If we need to check memory accesses, call the library function. */ + if (flag_check_memory_usage) + break; - /* If OP0 is not the actual lvalue, but rather a copy in a register, - then we cannot just increment OP0. We must therefore contrive to - increment the original value. Then, for postincrement, we can return - OP0 since it is a copy of the old value. For preincrement, expand here - unless we can do it with a single insn. + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE) + break; + else if (!HAVE_cmpstrsi) + break; + { + tree arg1 = TREE_VALUE (arglist); + tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree offset; + tree len, len2; - Likewise if storing directly into OP0 would clobber high bits - we need to preserve (bad_subreg). */ - if (op0_is_copy || (!post && !single_insn) || bad_subreg) - { - /* This is the easiest way to increment the value wherever it is. - Problems with multiple evaluation of INCREMENTED are prevented - because either (1) it is a component_ref or preincrement, - in which case it was stabilized above, or (2) it is an array_ref - with constant index in an array in a register, which is - safe to reevaluate. */ - tree newexp = build (((TREE_CODE (exp) == POSTDECREMENT_EXPR - || TREE_CODE (exp) == PREDECREMENT_EXPR) - ? MINUS_EXPR : PLUS_EXPR), - TREE_TYPE (exp), - incremented, - TREE_OPERAND (exp, 1)); + len = c_strlen (arg1); + if (len) + len = size_binop (PLUS_EXPR, integer_one_node, len); + len2 = c_strlen (arg2); + if (len2) + len2 = size_binop (PLUS_EXPR, integer_one_node, len2); - while (TREE_CODE (incremented) == NOP_EXPR - || TREE_CODE (incremented) == CONVERT_EXPR) - { - newexp = convert (TREE_TYPE (incremented), newexp); - incremented = TREE_OPERAND (incremented, 0); - } + /* If we don't have a constant length for the first, use the length + of the second, if we know it. We don't require a constant for + this case; some cost analysis could be done if both are available + but neither is constant. For now, assume they're equally cheap. - temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0); - return post ? op0 : temp; - } + If both strings have constant lengths, use the smaller. This + could arise if optimization results in strcpy being called with + two fixed strings, or if the code was machine-generated. We should + add some code to the `memcmp' handler below to deal with such + situations, someday. */ + if (!len || TREE_CODE (len) != INTEGER_CST) + { + if (len2) + len = len2; + else if (len == 0) + break; + } + else if (len2 && TREE_CODE (len2) == INTEGER_CST) + { + if (tree_int_cst_lt (len2, len)) + len = len2; + } - if (post) - { - /* We have a true reference to the value in OP0. - If there is an insn to add or subtract in this mode, queue it. - Queueing the increment insn avoids the register shuffling - that often results if we must increment now and first save - the old value for subsequent use. */ + chainon (arglist, build_tree_list (NULL_TREE, len)); + } -#if 0 /* Turned off to avoid making extra insn for indexed memref. */ - op0 = stabilize (op0); -#endif + /* Drops in. */ + case BUILT_IN_MEMCMP: + /* If not optimizing, call the library function. */ + if (!optimize && ! CALLED_AS_BUILT_IN (fndecl)) + break; - icode = (int) this_optab->handlers[(int) mode].insn_code; - if (icode != (int) CODE_FOR_nothing - /* Make sure that OP0 is valid for operands 0 and 1 - of the insn we want to queue. */ - && (*insn_operand_predicate[icode][0]) (op0, mode) - && (*insn_operand_predicate[icode][1]) (op0, mode)) - { - if (! (*insn_operand_predicate[icode][2]) (op1, mode)) - op1 = force_reg (mode, op1); + /* If we need to check memory accesses, call the library function. */ + if (flag_check_memory_usage) + break; - return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1)); - } - if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM) - { - rtx addr = (general_operand (XEXP (op0, 0), mode) - ? force_reg (Pmode, XEXP (op0, 0)) - : copy_to_reg (XEXP (op0, 0))); - rtx temp, result; + if (arglist == 0 + /* Arg could be non-pointer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE + || TREE_CHAIN (TREE_CHAIN (arglist)) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE) + break; + else if (!HAVE_cmpstrsi) + break; + { + tree arg1 = TREE_VALUE (arglist); + tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + rtx result; - op0 = change_address (op0, VOIDmode, addr); - temp = force_reg (GET_MODE (op0), op0); - if (! (*insn_operand_predicate[icode][2]) (op1, mode)) - op1 = force_reg (mode, op1); + int arg1_align + = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int arg2_align + = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + enum machine_mode insn_mode + = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0]; - /* The increment queue is LIFO, thus we have to `queue' - the instructions in reverse order. */ - enqueue_insn (op0, gen_move_insn (op0, temp)); - result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1)); - return result; - } - } + /* If we don't have POINTER_TYPE, call the function. */ + if (arg1_align == 0 || arg2_align == 0) + { + if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCMP) + TREE_CHAIN (TREE_CHAIN (arglist)) = 0; + break; + } - /* Preincrement, or we can't increment with one simple insn. */ - if (post) - /* Save a copy of the value before inc or dec, to return it later. */ - temp = value = copy_to_reg (op0); - else - /* Arrange to return the incremented value. */ - /* Copy the rtx because expand_binop will protect from the queue, - and the results of that would be invalid for us to return - if our caller does emit_queue before using our result. */ - temp = copy_rtx (value = op0); + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); - /* Increment however we can. */ - op1 = expand_binop (mode, this_optab, value, op1, - flag_check_memory_usage ? NULL_RTX : op0, - TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); - /* Make sure the value is stored into OP0. */ - if (op1 != op0) - emit_move_insn (op0, op1); + emit_insn (gen_cmpstrsi (result, + gen_rtx_MEM (BLKmode, + expand_expr (arg1, NULL_RTX, + ptr_mode, + EXPAND_NORMAL)), + gen_rtx_MEM (BLKmode, + expand_expr (arg2, NULL_RTX, + ptr_mode, + EXPAND_NORMAL)), + expand_expr (len, NULL_RTX, VOIDmode, 0), + GEN_INT (MIN (arg1_align, arg2_align)))); - return temp; -} - -/* Expand all function calls contained within EXP, innermost ones first. - But don't look within expressions that have sequence points. - For each CALL_EXPR, record the rtx for its value - in the CALL_EXPR_RTL field. */ + /* Return the value in the proper mode for this function. */ + mode = TYPE_MODE (TREE_TYPE (exp)); + if (GET_MODE (result) == mode) + return result; + else if (target != 0) + { + convert_move (target, result, 0); + return target; + } + else + return convert_to_mode (mode, result, 0); + } +#else + case BUILT_IN_STRCMP: + case BUILT_IN_MEMCMP: + break; +#endif -static void -preexpand_calls (exp) - tree exp; -{ - register int nops, i; - int type = TREE_CODE_CLASS (TREE_CODE (exp)); + case BUILT_IN_SETJMP: + if (arglist == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) + break; - if (! do_preexpand_calls) - return; + { + rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget, + VOIDmode, 0); + return expand_builtin_setjmp (buf_addr, target); + } - /* Only expressions and references can contain calls. */ + /* __builtin_longjmp is passed a pointer to an array of five words + and a value, which is a dummy. It's similar to the C library longjmp + function but works with __builtin_setjmp above. */ + case BUILT_IN_LONGJMP: + if (arglist == 0 || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) + break; - if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r') - return; + { + tree dummy_id = get_identifier ("__dummy"); + tree dummy_type = build_function_type (void_type_node, NULL_TREE); + tree dummy_decl = build_decl (FUNCTION_DECL, dummy_id, dummy_type); +#ifdef POINTERS_EXTEND_UNSIGNED + rtx buf_addr + = force_reg (Pmode, + convert_memory_address + (Pmode, + expand_expr (TREE_VALUE (arglist), + NULL_RTX, VOIDmode, 0))); +#else + rtx buf_addr + = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), + NULL_RTX, + VOIDmode, 0)); +#endif + rtx fp = gen_rtx_MEM (Pmode, buf_addr); + rtx lab = gen_rtx_MEM (Pmode, + plus_constant (buf_addr, + GET_MODE_SIZE (Pmode))); + enum machine_mode sa_mode +#ifdef HAVE_save_stack_nonlocal + = (HAVE_save_stack_nonlocal + ? insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0] + : Pmode); +#else + = Pmode; +#endif + rtx stack = gen_rtx_MEM (sa_mode, + plus_constant (buf_addr, + 2 * GET_MODE_SIZE (Pmode))); - switch (TREE_CODE (exp)) - { - case CALL_EXPR: - /* Do nothing if already expanded. */ - if (CALL_EXPR_RTL (exp) != 0 - /* Do nothing if the call returns a variable-sized object. */ - || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST - /* Do nothing to built-in functions. */ - || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR - && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) - == FUNCTION_DECL) - && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))) - return; + DECL_EXTERNAL (dummy_decl) = 1; + TREE_PUBLIC (dummy_decl) = 1; + make_decl_rtl (dummy_decl, NULL_PTR, 1); - CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0); - return; + /* Expand the second expression just for side-effects. */ + expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), + const0_rtx, VOIDmode, 0); - case COMPOUND_EXPR: - case COND_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - /* If we find one of these, then we can be sure - the adjust will be done for it (since it makes jumps). - Do it now, so that if this is inside an argument - of a function, we don't get the stack adjustment - after some other args have already been pushed. */ - do_pending_stack_adjust (); - return; + assemble_external (dummy_decl); - case BLOCK: - case RTL_EXPR: - case WITH_CLEANUP_EXPR: - case CLEANUP_POINT_EXPR: - case TRY_CATCH_EXPR: - return; + /* Pick up FP, label, and SP from the block and jump. This code is + from expand_goto in stmt.c; see there for detailed comments. */ +#if HAVE_nonlocal_goto + if (HAVE_nonlocal_goto) + emit_insn (gen_nonlocal_goto (fp, lab, stack, + XEXP (DECL_RTL (dummy_decl), 0))); + else +#endif + { + lab = copy_to_reg (lab); + emit_move_insn (hard_frame_pointer_rtx, fp); + emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); - case SAVE_EXPR: - if (SAVE_EXPR_RTL (exp) != 0) - return; - - default: - break; - } + /* Put in the static chain register the address of the dummy + function. */ + emit_move_insn (static_chain_rtx, XEXP (DECL_RTL (dummy_decl), 0)); + emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); + emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); + emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx)); + emit_indirect_jump (lab); + } - nops = tree_code_length[(int) TREE_CODE (exp)]; - for (i = 0; i < nops; i++) - if (TREE_OPERAND (exp, i) != 0) - { - type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i))); - if (type == 'e' || type == '<' || type == '1' || type == '2' - || type == 'r') - preexpand_calls (TREE_OPERAND (exp, i)); + return const0_rtx; } -} - -/* At the start of a function, record that we have no previously-pushed - arguments waiting to be popped. */ - -void -init_pending_stack_adjust () -{ - pending_stack_adjust = 0; -} - -/* When exiting from function, if safe, clear out any pending stack adjust - so the adjustment won't get done. */ -void -clear_pending_stack_adjust () -{ -#ifdef EXIT_IGNORE_STACK - if (optimize > 0 - && ! flag_omit_frame_pointer && EXIT_IGNORE_STACK - && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline) - && ! flag_inline_functions) - pending_stack_adjust = 0; + /* Various hooks for the DWARF 2 __throw routine. */ + case BUILT_IN_UNWIND_INIT: + expand_builtin_unwind_init (); + return const0_rtx; + case BUILT_IN_FP: + return frame_pointer_rtx; + case BUILT_IN_SP: + return stack_pointer_rtx; +#ifdef DWARF2_UNWIND_INFO + case BUILT_IN_DWARF_FP_REGNUM: + return expand_builtin_dwarf_fp_regnum (); + case BUILT_IN_DWARF_REG_SIZE: + return expand_builtin_dwarf_reg_size (TREE_VALUE (arglist), target); #endif -} - -/* Pop any previously-pushed arguments that have not been popped yet. */ + case BUILT_IN_FROB_RETURN_ADDR: + return expand_builtin_frob_return_addr (TREE_VALUE (arglist)); + case BUILT_IN_EXTRACT_RETURN_ADDR: + return expand_builtin_extract_return_addr (TREE_VALUE (arglist)); + case BUILT_IN_SET_RETURN_ADDR_REG: + expand_builtin_set_return_addr_reg (TREE_VALUE (arglist)); + return const0_rtx; + case BUILT_IN_EH_STUB: + return expand_builtin_eh_stub (); + case BUILT_IN_SET_EH_REGS: + expand_builtin_set_eh_regs (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist))); + return const0_rtx; -void -do_pending_stack_adjust () -{ - if (inhibit_defer_pop == 0) - { - if (pending_stack_adjust != 0) - adjust_stack (GEN_INT (pending_stack_adjust)); - pending_stack_adjust = 0; + default: /* just do library call, if unknown builtin */ + error ("built-in function `%s' not currently supported", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); } -} - -/* Expand conditional expressions. */ -/* Generate code to evaluate EXP and jump to LABEL if the value is zero. - LABEL is an rtx of code CODE_LABEL, in this function and all the - functions here. */ + /* The switch statement above can drop through to cause the function + to be called normally. */ -void -jumpifnot (exp, label) - tree exp; - rtx label; -{ - do_jump (exp, label, NULL_RTX); + return expand_call (exp, target, ignore); } + +/* Built-in functions to perform an untyped call and return. */ -/* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */ +/* For each register that may be used for calling a function, this + gives a mode used to copy the register's value. VOIDmode indicates + the register is not used for calling a function. If the machine + has register windows, this gives only the outbound registers. + INCOMING_REGNO gives the corresponding inbound register. */ +static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER]; -void -jumpif (exp, label) - tree exp; - rtx label; -{ - do_jump (exp, NULL_RTX, label); -} +/* For each register that may be used for returning values, this gives + a mode used to copy the register's value. VOIDmode indicates the + register is not used for returning values. If the machine has + register windows, this gives only the outbound registers. + INCOMING_REGNO gives the corresponding inbound register. */ +static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER]; -/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if - the result is zero, or IF_TRUE_LABEL if the result is one. - Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero, - meaning fall through in that case. +/* For each register that may be used for calling a function, this + gives the offset of that register into the block returned by + __builtin_apply_args. 0 indicates that the register is not + used for calling a function. */ +static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER]; + +/* Return the offset of register REGNO into the block returned by + __builtin_apply_args. This is not declared static, since it is + needed in objc-act.c. */ - do_jump always does any pending stack adjust except when it does not - actually perform a jump. An example where there is no jump - is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null. +int +apply_args_register_offset (regno) + int regno; +{ + apply_args_size (); - This function is responsible for optimizing cases such as - &&, || and comparison operators in EXP. */ + /* Arguments are always put in outgoing registers (in the argument + block) if such make sense. */ +#ifdef OUTGOING_REGNO + regno = OUTGOING_REGNO(regno); +#endif + return apply_args_reg_offset[regno]; +} -void -do_jump (exp, if_false_label, if_true_label) - tree exp; - rtx if_false_label, if_true_label; +/* Return the size required for the block returned by __builtin_apply_args, + and initialize apply_args_mode. */ + +static int +apply_args_size () { - register enum tree_code code = TREE_CODE (exp); - /* Some cases need to create a label to jump to - in order to properly fall through. - These cases set DROP_THROUGH_LABEL nonzero. */ - rtx drop_through_label = 0; - rtx temp; - rtx comparison = 0; - int i; - tree type; + static int size = -1; + int align, regno; enum machine_mode mode; - emit_queue (); - - switch (code) + /* The values computed by this function never change. */ + if (size < 0) { - case ERROR_MARK: - break; + /* The first value is the incoming arg-pointer. */ + size = GET_MODE_SIZE (Pmode); - case INTEGER_CST: - temp = integer_zerop (exp) ? if_false_label : if_true_label; - if (temp) - emit_jump (temp); - break; + /* The second value is the structure value address unless this is + passed as an "invisible" first argument. */ + if (struct_value_rtx) + size += GET_MODE_SIZE (Pmode); -#if 0 - /* This is not true with #pragma weak */ - case ADDR_EXPR: - /* The address of something can never be zero. */ - if (if_true_label) - emit_jump (if_true_label); - break; -#endif + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (FUNCTION_ARG_REGNO_P (regno)) + { + /* Search for the proper mode for copying this register's + value. I'm not sure this is right, but it works so far. */ + enum machine_mode best_mode = VOIDmode; - case NOP_EXPR: - if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF - || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF - || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF) - goto normal; - case CONVERT_EXPR: - /* If we are narrowing the operand, we have to do the compare in the - narrower mode. */ - if ((TYPE_PRECISION (TREE_TYPE (exp)) - < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))) - goto normal; - case NON_LVALUE_EXPR: - case REFERENCE_EXPR: - case ABS_EXPR: - case NEGATE_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - /* These cannot change zero->non-zero or vice versa. */ - do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); - break; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && HARD_REGNO_NREGS (regno, mode) == 1) + best_mode = mode; -#if 0 - /* This is never less insns than evaluating the PLUS_EXPR followed by - a test and can be longer if the test is eliminated. */ - case PLUS_EXPR: - /* Reduce to minus. */ - exp = build (MINUS_EXPR, TREE_TYPE (exp), - TREE_OPERAND (exp, 0), - fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)), - TREE_OPERAND (exp, 1)))); - /* Process as MINUS. */ -#endif + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && (mov_optab->handlers[(int) mode].insn_code + != CODE_FOR_nothing)) + best_mode = mode; - case MINUS_EXPR: - /* Non-zero iff operands of minus differ. */ - comparison = compare (build (NE_EXPR, TREE_TYPE (exp), - TREE_OPERAND (exp, 0), - TREE_OPERAND (exp, 1)), - NE, NE); - break; + mode = best_mode; + if (mode == VOIDmode) + abort (); - case BIT_AND_EXPR: - /* If we are AND'ing with a small constant, do this comparison in the - smallest type that fits. If the machine doesn't have comparisons - that small, it will be converted back to the wider comparison. - This helps if we are testing the sign bit of a narrower object. - combine can't do this for us because it can't know whether a - ZERO_EXTRACT or a compare in a smaller mode exists, but we do. */ + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; + apply_args_reg_offset[regno] = size; + size += GET_MODE_SIZE (mode); + apply_args_mode[regno] = mode; + } + else + { + apply_args_mode[regno] = VOIDmode; + apply_args_reg_offset[regno] = 0; + } + } + return size; +} - if (! SLOW_BYTE_ACCESS - && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT - && (i = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0 - && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode - && (type = type_for_mode (mode, 1)) != 0 - && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) - && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code - != CODE_FOR_nothing)) - { - do_jump (convert (type, exp), if_false_label, if_true_label); - break; - } - goto normal; +/* Return the size required for the block returned by __builtin_apply, + and initialize apply_result_mode. */ - case TRUTH_NOT_EXPR: - do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); - break; +static int +apply_result_size () +{ + static int size = -1; + int align, regno; + enum machine_mode mode; - case TRUTH_ANDIF_EXPR: - if (if_false_label == 0) - if_false_label = drop_through_label = gen_label_rtx (); - do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX); - start_cleanup_deferral (); - do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); - end_cleanup_deferral (); - break; + /* The values computed by this function never change. */ + if (size < 0) + { + size = 0; - case TRUTH_ORIF_EXPR: - if (if_true_label == 0) - if_true_label = drop_through_label = gen_label_rtx (); - do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label); - start_cleanup_deferral (); - do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); - end_cleanup_deferral (); - break; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (FUNCTION_VALUE_REGNO_P (regno)) + { + /* Search for the proper mode for copying this register's + value. I'm not sure this is right, but it works so far. */ + enum machine_mode best_mode = VOIDmode; - case COMPOUND_EXPR: - push_temp_slots (); - expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); - preserve_temp_slots (NULL_RTX); - free_temp_slots (); - pop_temp_slots (); - emit_queue (); - do_pending_stack_adjust (); - do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); - break; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != TImode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode)) + best_mode = mode; - case COMPONENT_REF: - case BIT_FIELD_REF: - case ARRAY_REF: - { - int bitsize, bitpos, unsignedp; - enum machine_mode mode; - tree type; - tree offset; - int volatilep = 0; - int alignment; + if (best_mode == VOIDmode) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_MODE_OK (regno, mode) + && (mov_optab->handlers[(int) mode].insn_code + != CODE_FOR_nothing)) + best_mode = mode; - /* Get description of this reference. We don't actually care - about the underlying object here. */ - get_inner_reference (exp, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, - &alignment); + mode = best_mode; + if (mode == VOIDmode) + abort (); + + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; + size += GET_MODE_SIZE (mode); + apply_result_mode[regno] = mode; + } + else + apply_result_mode[regno] = VOIDmode; + + /* Allow targets that use untyped_call and untyped_return to override + the size so that machine-specific information can be stored here. */ +#ifdef APPLY_RESULT_SIZE + size = APPLY_RESULT_SIZE; +#endif + } + return size; +} - type = type_for_size (bitsize, unsignedp); - if (! SLOW_BYTE_ACCESS - && type != 0 && bitsize >= 0 - && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) - && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code - != CODE_FOR_nothing)) - { - do_jump (convert (type, exp), if_false_label, if_true_label); - break; - } - goto normal; +#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return) +/* Create a vector describing the result block RESULT. If SAVEP is true, + the result block is used to save the values; otherwise it is used to + restore the values. */ + +static rtx +result_vector (savep, result) + int savep; + rtx result; +{ + int regno, size, align, nelts; + enum machine_mode mode; + rtx reg, mem; + rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx)); + + size = nelts = 0; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((mode = apply_result_mode[regno]) != VOIDmode) + { + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; + reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno)); + mem = change_address (result, mode, + plus_constant (XEXP (result, 0), size)); + savevec[nelts++] = (savep + ? gen_rtx_SET (VOIDmode, mem, reg) + : gen_rtx_SET (VOIDmode, reg, mem)); + size += GET_MODE_SIZE (mode); } + return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec)); +} +#endif /* HAVE_untyped_call or HAVE_untyped_return */ - case COND_EXPR: - /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases. */ - if (integer_onep (TREE_OPERAND (exp, 1)) - && integer_zerop (TREE_OPERAND (exp, 2))) - do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); +/* Save the state required to perform an untyped call with the same + arguments as were passed to the current function. */ - else if (integer_zerop (TREE_OPERAND (exp, 1)) - && integer_onep (TREE_OPERAND (exp, 2))) - do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); +static rtx +expand_builtin_apply_args () +{ + rtx registers; + int size, align, regno; + enum machine_mode mode; - else - { - register rtx label1 = gen_label_rtx (); - drop_through_label = gen_label_rtx (); + /* Create a block where the arg-pointer, structure value address, + and argument registers can be saved. */ + registers = assign_stack_local (BLKmode, apply_args_size (), -1); - do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX); + /* Walk past the arg-pointer and structure value address. */ + size = GET_MODE_SIZE (Pmode); + if (struct_value_rtx) + size += GET_MODE_SIZE (Pmode); - start_cleanup_deferral (); - /* Now the THEN-expression. */ - do_jump (TREE_OPERAND (exp, 1), - if_false_label ? if_false_label : drop_through_label, - if_true_label ? if_true_label : drop_through_label); - /* In case the do_jump just above never jumps. */ - do_pending_stack_adjust (); - emit_label (label1); + /* Save each register used in calling a function to the block. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((mode = apply_args_mode[regno]) != VOIDmode) + { + rtx tem; - /* Now the ELSE-expression. */ - do_jump (TREE_OPERAND (exp, 2), - if_false_label ? if_false_label : drop_through_label, - if_true_label ? if_true_label : drop_through_label); - end_cleanup_deferral (); - } - break; + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; - case EQ_EXPR: - { - tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); + tem = gen_rtx_REG (mode, INCOMING_REGNO (regno)); - if (integer_zerop (TREE_OPERAND (exp, 1))) - do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); - else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT - || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT) - do_jump - (fold - (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp), - fold (build (EQ_EXPR, TREE_TYPE (exp), - fold (build1 (REALPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 0))), - fold (build1 (REALPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 1))))), - fold (build (EQ_EXPR, TREE_TYPE (exp), - fold (build1 (IMAGPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 0))), - fold (build1 (IMAGPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 1))))))), - if_false_label, if_true_label); - else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT - && !can_compare_p (TYPE_MODE (inner_type))) - do_jump_by_parts_equality (exp, if_false_label, if_true_label); - else - comparison = compare (exp, EQ, EQ); - break; - } +#ifdef STACK_REGS + /* For reg-stack.c's stack register household. + Compare with a similar piece of code in function.c. */ - case NE_EXPR: - { - tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); + emit_insn (gen_rtx_USE (mode, tem)); +#endif - if (integer_zerop (TREE_OPERAND (exp, 1))) - do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); - else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT - || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT) - do_jump - (fold - (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), - fold (build (NE_EXPR, TREE_TYPE (exp), - fold (build1 (REALPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 0))), - fold (build1 (REALPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 1))))), - fold (build (NE_EXPR, TREE_TYPE (exp), - fold (build1 (IMAGPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 0))), - fold (build1 (IMAGPART_EXPR, - TREE_TYPE (inner_type), - TREE_OPERAND (exp, 1))))))), - if_false_label, if_true_label); - else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT - && !can_compare_p (TYPE_MODE (inner_type))) - do_jump_by_parts_equality (exp, if_true_label, if_false_label); - else - comparison = compare (exp, NE, NE); - break; + emit_move_insn (change_address (registers, mode, + plus_constant (XEXP (registers, 0), + size)), + tem); + size += GET_MODE_SIZE (mode); } - case LT_EXPR: - if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == MODE_INT) - && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) - do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label); - else - comparison = compare (exp, LT, LTU); - break; + /* Save the arg pointer to the block. */ + emit_move_insn (change_address (registers, Pmode, XEXP (registers, 0)), + copy_to_reg (virtual_incoming_args_rtx)); + size = GET_MODE_SIZE (Pmode); - case LE_EXPR: - if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == MODE_INT) - && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) - do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label); - else - comparison = compare (exp, LE, LEU); - break; + /* Save the structure value address unless this is passed as an + "invisible" first argument. */ + if (struct_value_incoming_rtx) + { + emit_move_insn (change_address (registers, Pmode, + plus_constant (XEXP (registers, 0), + size)), + copy_to_reg (struct_value_incoming_rtx)); + size += GET_MODE_SIZE (Pmode); + } - case GT_EXPR: - if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == MODE_INT) - && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) - do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label); - else - comparison = compare (exp, GT, GTU); - break; + /* Return the address of the block. */ + return copy_addr_to_reg (XEXP (registers, 0)); +} - case GE_EXPR: - if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == MODE_INT) - && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) - do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label); - else - comparison = compare (exp, GE, GEU); - break; +/* Perform an untyped call and save the state required to perform an + untyped return of whatever value was returned by the given function. */ - default: - normal: - temp = expand_expr (exp, NULL_RTX, VOIDmode, 0); -#if 0 - /* This is not needed any more and causes poor code since it causes - comparisons and tests from non-SI objects to have different code - sequences. */ - /* Copy to register to avoid generating bad insns by cse - from (set (mem ...) (arithop)) (set (cc0) (mem ...)). */ - if (!cse_not_expected && GET_CODE (temp) == MEM) - temp = copy_to_reg (temp); -#endif - do_pending_stack_adjust (); - if (GET_CODE (temp) == CONST_INT) - comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx); - else if (GET_CODE (temp) == LABEL_REF) - comparison = const_true_rtx; - else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT - && !can_compare_p (GET_MODE (temp))) - /* Note swapping the labels gives us not-equal. */ - do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label); - else if (GET_MODE (temp) != VOIDmode) - comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)), - NE, TREE_UNSIGNED (TREE_TYPE (exp)), - GET_MODE (temp), NULL_RTX, 0); - else - abort (); - } +static rtx +expand_builtin_apply (function, arguments, argsize) + rtx function, arguments, argsize; +{ + int size, align, regno; + enum machine_mode mode; + rtx incoming_args, result, reg, dest, call_insn; + rtx old_stack_level = 0; + rtx call_fusage = 0; - /* Do any postincrements in the expression that was tested. */ + /* Create a block where the return registers can be saved. */ + result = assign_stack_local (BLKmode, apply_result_size (), -1); + + /* ??? The argsize value should be adjusted here. */ + + /* Fetch the arg pointer from the ARGUMENTS block. */ + incoming_args = gen_reg_rtx (Pmode); + emit_move_insn (incoming_args, + gen_rtx_MEM (Pmode, arguments)); +#ifndef STACK_GROWS_DOWNWARD + incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize, + incoming_args, 0, OPTAB_LIB_WIDEN); +#endif + + /* Perform postincrements before actually calling the function. */ emit_queue (); - /* If COMPARISON is nonzero here, it is an rtx that can be substituted - straight into a conditional jump instruction as the jump condition. - Otherwise, all the work has been done already. */ + /* Push a new argument block and copy the arguments. */ + do_pending_stack_adjust (); - if (comparison == const_true_rtx) - { - if (if_true_label) - emit_jump (if_true_label); - } - else if (comparison == const0_rtx) - { - if (if_false_label) - emit_jump (if_false_label); - } - else if (comparison) - do_jump_for_compare (comparison, if_false_label, if_true_label); + /* Save the stack with nonlocal if available */ +#ifdef HAVE_save_stack_nonlocal + if (HAVE_save_stack_nonlocal) + emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX); + else +#endif + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); - if (drop_through_label) + /* Push a block of memory onto the stack to store the memory arguments. + Save the address in a register, and copy the memory arguments. ??? I + haven't figured out how the calling convention macros effect this, + but it's likely that the source and/or destination addresses in + the block copy will need updating in machine specific ways. */ + dest = allocate_dynamic_stack_space (argsize, 0, 0); + emit_block_move (gen_rtx_MEM (BLKmode, dest), + gen_rtx_MEM (BLKmode, incoming_args), + argsize, + PARM_BOUNDARY / BITS_PER_UNIT); + + /* Refer to the argument block. */ + apply_args_size (); + arguments = gen_rtx_MEM (BLKmode, arguments); + + /* Walk past the arg-pointer and structure value address. */ + size = GET_MODE_SIZE (Pmode); + if (struct_value_rtx) + size += GET_MODE_SIZE (Pmode); + + /* Restore each of the registers previously saved. Make USE insns + for each of these registers for use in making the call. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((mode = apply_args_mode[regno]) != VOIDmode) + { + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; + reg = gen_rtx_REG (mode, regno); + emit_move_insn (reg, + change_address (arguments, mode, + plus_constant (XEXP (arguments, 0), + size))); + + use_reg (&call_fusage, reg); + size += GET_MODE_SIZE (mode); + } + + /* Restore the structure value address unless this is passed as an + "invisible" first argument. */ + size = GET_MODE_SIZE (Pmode); + if (struct_value_rtx) { - /* If do_jump produces code that might be jumped around, - do any stack adjusts from that code, before the place - where control merges in. */ - do_pending_stack_adjust (); - emit_label (drop_through_label); + rtx value = gen_reg_rtx (Pmode); + emit_move_insn (value, + change_address (arguments, Pmode, + plus_constant (XEXP (arguments, 0), + size))); + emit_move_insn (struct_value_rtx, value); + if (GET_CODE (struct_value_rtx) == REG) + use_reg (&call_fusage, struct_value_rtx); + size += GET_MODE_SIZE (Pmode); } -} - -/* Given a comparison expression EXP for values too wide to be compared - with one insn, test the comparison and jump to the appropriate label. - The code of EXP is ignored; we always test GT if SWAP is 0, - and LT if SWAP is 1. */ -static void -do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label) - tree exp; - int swap; - rtx if_false_label, if_true_label; -{ - rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0); - enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); - int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); - rtx drop_through_label = 0; - int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))); - int i; + /* All arguments and registers used for the call are set up by now! */ + function = prepare_call_address (function, NULL_TREE, &call_fusage, 0); - if (! if_true_label || ! if_false_label) - drop_through_label = gen_label_rtx (); - if (! if_true_label) - if_true_label = drop_through_label; - if (! if_false_label) - if_false_label = drop_through_label; + /* Ensure address is valid. SYMBOL_REF is already valid, so no need, + and we don't want to load it into a register as an optimization, + because prepare_call_address already did it if it should be done. */ + if (GET_CODE (function) != SYMBOL_REF) + function = memory_address (FUNCTION_MODE, function); - /* Compare a word at a time, high order first. */ - for (i = 0; i < nwords; i++) + /* Generate the actual call instruction and save the return value. */ +#ifdef HAVE_untyped_call + if (HAVE_untyped_call) + emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function), + result, result_vector (1, result))); + else +#endif +#ifdef HAVE_call_value + if (HAVE_call_value) { - rtx comp; - rtx op0_word, op1_word; + rtx valreg = 0; - if (WORDS_BIG_ENDIAN) - { - op0_word = operand_subword_force (op0, i, mode); - op1_word = operand_subword_force (op1, i, mode); - } - else - { - op0_word = operand_subword_force (op0, nwords - 1 - i, mode); - op1_word = operand_subword_force (op1, nwords - 1 - i, mode); - } + /* Locate the unique return register. It is not possible to + express a call that sets more than one return register using + call_value; use untyped_call for that. In fact, untyped_call + only needs to save the return registers in the given block. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((mode = apply_result_mode[regno]) != VOIDmode) + { + if (valreg) + abort (); /* HAVE_untyped_call required. */ + valreg = gen_rtx_REG (mode, regno); + } - /* All but high-order word must be compared as unsigned. */ - comp = compare_from_rtx (op0_word, op1_word, - (unsignedp || i > 0) ? GTU : GT, - unsignedp, word_mode, NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_true_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, NULL_RTX, if_true_label); + emit_call_insn (gen_call_value (valreg, + gen_rtx_MEM (FUNCTION_MODE, function), + const0_rtx, NULL_RTX, const0_rtx)); - /* Consider lower words only if these are equal. */ - comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode, - NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_false_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, NULL_RTX, if_false_label); + emit_move_insn (change_address (result, GET_MODE (valreg), + XEXP (result, 0)), + valreg); } + else +#endif + abort (); - if (if_false_label) - emit_jump (if_false_label); - if (drop_through_label) - emit_label (drop_through_label); -} - -/* Compare OP0 with OP1, word at a time, in mode MODE. - UNSIGNEDP says to do unsigned comparison. - Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise. */ - -void -do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label) - enum machine_mode mode; - int unsignedp; - rtx op0, op1; - rtx if_false_label, if_true_label; -{ - int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); - rtx drop_through_label = 0; - int i; + /* Find the CALL insn we just emitted. */ + for (call_insn = get_last_insn (); + call_insn && GET_CODE (call_insn) != CALL_INSN; + call_insn = PREV_INSN (call_insn)) + ; - if (! if_true_label || ! if_false_label) - drop_through_label = gen_label_rtx (); - if (! if_true_label) - if_true_label = drop_through_label; - if (! if_false_label) - if_false_label = drop_through_label; + if (! call_insn) + abort (); - /* Compare a word at a time, high order first. */ - for (i = 0; i < nwords; i++) + /* Put the register usage information on the CALL. If there is already + some usage information, put ours at the end. */ + if (CALL_INSN_FUNCTION_USAGE (call_insn)) { - rtx comp; - rtx op0_word, op1_word; - - if (WORDS_BIG_ENDIAN) - { - op0_word = operand_subword_force (op0, i, mode); - op1_word = operand_subword_force (op1, i, mode); - } - else - { - op0_word = operand_subword_force (op0, nwords - 1 - i, mode); - op1_word = operand_subword_force (op1, nwords - 1 - i, mode); - } - - /* All but high-order word must be compared as unsigned. */ - comp = compare_from_rtx (op0_word, op1_word, - (unsignedp || i > 0) ? GTU : GT, - unsignedp, word_mode, NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_true_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, NULL_RTX, if_true_label); + rtx link; - /* Consider lower words only if these are equal. */ - comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode, - NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_false_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, NULL_RTX, if_false_label); + for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0; + link = XEXP (link, 1)) + ; + + XEXP (link, 1) = call_fusage; } + else + CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage; - if (if_false_label) - emit_jump (if_false_label); - if (drop_through_label) - emit_label (drop_through_label); + /* Restore the stack. */ +#ifdef HAVE_save_stack_nonlocal + if (HAVE_save_stack_nonlocal) + emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX); + else +#endif + emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + + /* Return the address of the result block. */ + return copy_addr_to_reg (XEXP (result, 0)); } -/* Given an EQ_EXPR expression EXP for values too wide to be compared - with one insn, test the comparison and jump to the appropriate label. */ +/* Perform an untyped return. */ static void -do_jump_by_parts_equality (exp, if_false_label, if_true_label) - tree exp; - rtx if_false_label, if_true_label; +expand_builtin_return (result) + rtx result; { - rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); - rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); - enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); - int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); - int i; - rtx drop_through_label = 0; + int size, align, regno; + enum machine_mode mode; + rtx reg; + rtx call_fusage = 0; - if (! if_false_label) - drop_through_label = if_false_label = gen_label_rtx (); + apply_result_size (); + result = gen_rtx_MEM (BLKmode, result); - for (i = 0; i < nwords; i++) +#ifdef HAVE_untyped_return + if (HAVE_untyped_return) { - rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode), - operand_subword_force (op1, i, mode), - EQ, TREE_UNSIGNED (TREE_TYPE (exp)), - word_mode, NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_false_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, if_false_label, NULL_RTX); + emit_jump_insn (gen_untyped_return (result, result_vector (0, result))); + emit_barrier (); + return; } +#endif - if (if_true_label) - emit_jump (if_true_label); - if (drop_through_label) - emit_label (drop_through_label); + /* Restore the return value and note that each value is used. */ + size = 0; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((mode = apply_result_mode[regno]) != VOIDmode) + { + align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; + if (size % align != 0) + size = CEIL (size, align) * align; + reg = gen_rtx_REG (mode, INCOMING_REGNO (regno)); + emit_move_insn (reg, + change_address (result, mode, + plus_constant (XEXP (result, 0), + size))); + + push_to_sequence (call_fusage); + emit_insn (gen_rtx_USE (VOIDmode, reg)); + call_fusage = get_insns (); + end_sequence (); + size += GET_MODE_SIZE (mode); + } + + /* Put the USE insns before the return. */ + emit_insns (call_fusage); + + /* Return whatever values was restored by jumping directly to the end + of the function. */ + expand_null_return (); } -/* Jump according to whether OP0 is 0. - We assume that OP0 has an integer mode that is too wide - for the available compare insns. */ +/* Expand code for a post- or pre- increment or decrement + and return the RTX for the result. + POST is 1 for postinc/decrements and 0 for preinc/decrements. */ -static void -do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) - rtx op0; - rtx if_false_label, if_true_label; +static rtx +expand_increment (exp, post, ignore) + register tree exp; + int post, ignore; { - int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD; - rtx part; - int i; - rtx drop_through_label = 0; + register rtx op0, op1; + register rtx temp, value; + register tree incremented = TREE_OPERAND (exp, 0); + optab this_optab = add_optab; + int icode; + enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); + int op0_is_copy = 0; + int single_insn = 0; + /* 1 means we can't store into OP0 directly, + because it is a subreg narrower than a word, + and we don't dare clobber the rest of the word. */ + int bad_subreg = 0; - /* The fastest way of doing this comparison on almost any machine is to - "or" all the words and compare the result. If all have to be loaded - from memory and this is a very wide item, it's possible this may - be slower, but that's highly unlikely. */ + /* Stabilize any component ref that might need to be + evaluated more than once below. */ + if (!post + || TREE_CODE (incremented) == BIT_FIELD_REF + || (TREE_CODE (incremented) == COMPONENT_REF + && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF + || DECL_BIT_FIELD (TREE_OPERAND (incremented, 1))))) + incremented = stabilize_reference (incremented); + /* Nested *INCREMENT_EXPRs can happen in C++. We must force innermost + ones into save exprs so that they don't accidentally get evaluated + more than once by the code below. */ + if (TREE_CODE (incremented) == PREINCREMENT_EXPR + || TREE_CODE (incremented) == PREDECREMENT_EXPR) + incremented = save_expr (incremented); - part = gen_reg_rtx (word_mode); - emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0))); - for (i = 1; i < nwords && part != 0; i++) - part = expand_binop (word_mode, ior_optab, part, - operand_subword_force (op0, i, GET_MODE (op0)), - part, 1, OPTAB_WIDEN); + /* Compute the operands as RTX. + Note whether OP0 is the actual lvalue or a copy of it: + I believe it is a copy iff it is a register or subreg + and insns were generated in computing it. */ - if (part != 0) - { - rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode, - NULL_RTX, 0); + temp = get_last_insn (); + op0 = expand_expr (incremented, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_RW); - if (comp == const_true_rtx) - emit_jump (if_false_label); - else if (comp == const0_rtx) - emit_jump (if_true_label); - else - do_jump_for_compare (comp, if_false_label, if_true_label); + /* If OP0 is a SUBREG made for a promoted variable, we cannot increment + in place but instead must do sign- or zero-extension during assignment, + so we copy it into a new register and let the code below use it as + a copy. - return; + Note that we can safely modify this SUBREG since it is know not to be + shared (it was made by the expand_expr call above). */ + + if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0)) + { + if (post) + SUBREG_REG (op0) = copy_to_reg (SUBREG_REG (op0)); + else + bad_subreg = 1; + } + else if (GET_CODE (op0) == SUBREG + && GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD) + { + /* We cannot increment this SUBREG in place. If we are + post-incrementing, get a copy of the old value. Otherwise, + just mark that we cannot increment in place. */ + if (post) + op0 = copy_to_reg (op0); + else + bad_subreg = 1; } - /* If we couldn't do the "or" simply, do this with a series of compares. */ - if (! if_false_label) - drop_through_label = if_false_label = gen_label_rtx (); + op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) + && temp != get_last_insn ()); + op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, + EXPAND_MEMORY_USE_BAD); - for (i = 0; i < nwords; i++) + /* Decide whether incrementing or decrementing. */ + if (TREE_CODE (exp) == POSTDECREMENT_EXPR + || TREE_CODE (exp) == PREDECREMENT_EXPR) + this_optab = sub_optab; + + /* Convert decrement by a constant into a negative increment. */ + if (this_optab == sub_optab + && GET_CODE (op1) == CONST_INT) { - rtx comp = compare_from_rtx (operand_subword_force (op0, i, - GET_MODE (op0)), - const0_rtx, EQ, 1, word_mode, NULL_RTX, 0); - if (comp == const_true_rtx) - emit_jump (if_false_label); - else if (comp != const0_rtx) - do_jump_for_compare (comp, if_false_label, NULL_RTX); + op1 = GEN_INT (- INTVAL (op1)); + this_optab = add_optab; } - if (if_true_label) - emit_jump (if_true_label); - - if (drop_through_label) - emit_label (drop_through_label); -} + /* For a preincrement, see if we can do this with a single instruction. */ + if (!post) + { + icode = (int) this_optab->handlers[(int) mode].insn_code; + if (icode != (int) CODE_FOR_nothing + /* Make sure that OP0 is valid for operands 0 and 1 + of the insn we want to queue. */ + && (*insn_operand_predicate[icode][0]) (op0, mode) + && (*insn_operand_predicate[icode][1]) (op0, mode) + && (*insn_operand_predicate[icode][2]) (op1, mode)) + single_insn = 1; + } -/* Given a comparison expression in rtl form, output conditional branches to - IF_TRUE_LABEL, IF_FALSE_LABEL, or both. */ + /* If OP0 is not the actual lvalue, but rather a copy in a register, + then we cannot just increment OP0. We must therefore contrive to + increment the original value. Then, for postincrement, we can return + OP0 since it is a copy of the old value. For preincrement, expand here + unless we can do it with a single insn. -static void -do_jump_for_compare (comparison, if_false_label, if_true_label) - rtx comparison, if_false_label, if_true_label; -{ - if (if_true_label) + Likewise if storing directly into OP0 would clobber high bits + we need to preserve (bad_subreg). */ + if (op0_is_copy || (!post && !single_insn) || bad_subreg) { - if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0) - emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label)); - else - abort (); + /* This is the easiest way to increment the value wherever it is. + Problems with multiple evaluation of INCREMENTED are prevented + because either (1) it is a component_ref or preincrement, + in which case it was stabilized above, or (2) it is an array_ref + with constant index in an array in a register, which is + safe to reevaluate. */ + tree newexp = build (((TREE_CODE (exp) == POSTDECREMENT_EXPR + || TREE_CODE (exp) == PREDECREMENT_EXPR) + ? MINUS_EXPR : PLUS_EXPR), + TREE_TYPE (exp), + incremented, + TREE_OPERAND (exp, 1)); - if (if_false_label) - emit_jump (if_false_label); - } - else if (if_false_label) - { - rtx insn; - rtx prev = get_last_insn (); - rtx branch = 0; + while (TREE_CODE (incremented) == NOP_EXPR + || TREE_CODE (incremented) == CONVERT_EXPR) + { + newexp = convert (TREE_TYPE (incremented), newexp); + incremented = TREE_OPERAND (incremented, 0); + } - /* Output the branch with the opposite condition. Then try to invert - what is generated. If more than one insn is a branch, or if the - branch is not the last insn written, abort. If we can't invert - the branch, emit make a true label, redirect this jump to that, - emit a jump to the false label and define the true label. */ + temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0); + return post ? op0 : temp; + } - if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0) - emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])(if_false_label)); - else - abort (); + if (post) + { + /* We have a true reference to the value in OP0. + If there is an insn to add or subtract in this mode, queue it. + Queueing the increment insn avoids the register shuffling + that often results if we must increment now and first save + the old value for subsequent use. */ - /* Here we get the first insn that was just emitted. It used to be the - case that, on some machines, emitting the branch would discard - the previous compare insn and emit a replacement. This isn't - done anymore, but abort if we see that PREV is deleted. */ +#if 0 /* Turned off to avoid making extra insn for indexed memref. */ + op0 = stabilize (op0); +#endif - if (prev == 0) - insn = get_insns (); - else if (INSN_DELETED_P (prev)) - abort (); - else - insn = NEXT_INSN (prev); + icode = (int) this_optab->handlers[(int) mode].insn_code; + if (icode != (int) CODE_FOR_nothing + /* Make sure that OP0 is valid for operands 0 and 1 + of the insn we want to queue. */ + && (*insn_operand_predicate[icode][0]) (op0, mode) + && (*insn_operand_predicate[icode][1]) (op0, mode)) + { + if (! (*insn_operand_predicate[icode][2]) (op1, mode)) + op1 = force_reg (mode, op1); - for (; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == JUMP_INSN) - { - if (branch) - abort (); - branch = insn; - } + return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1)); + } + if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM) + { + rtx addr = (general_operand (XEXP (op0, 0), mode) + ? force_reg (Pmode, XEXP (op0, 0)) + : copy_to_reg (XEXP (op0, 0))); + rtx temp, result; - if (branch != get_last_insn ()) - abort (); + op0 = change_address (op0, VOIDmode, addr); + temp = force_reg (GET_MODE (op0), op0); + if (! (*insn_operand_predicate[icode][2]) (op1, mode)) + op1 = force_reg (mode, op1); - JUMP_LABEL (branch) = if_false_label; - if (! invert_jump (branch, if_false_label)) - { - if_true_label = gen_label_rtx (); - redirect_jump (branch, if_true_label); - emit_jump (if_false_label); - emit_label (if_true_label); + /* The increment queue is LIFO, thus we have to `queue' + the instructions in reverse order. */ + enqueue_insn (op0, gen_move_insn (op0, temp)); + result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1)); + return result; } } -} - -/* Generate code for a comparison expression EXP - (including code to compute the values to be compared) - and set (CC0) according to the result. - SIGNED_CODE should be the rtx operation for this comparison for - signed data; UNSIGNED_CODE, likewise for use if data is unsigned. - - We force a stack adjustment unless there are currently - things pushed on the stack that aren't yet used. */ -static rtx -compare (exp, signed_code, unsigned_code) - register tree exp; - enum rtx_code signed_code, unsigned_code; -{ - register rtx op0 - = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); - register rtx op1 - = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); - register tree type = TREE_TYPE (TREE_OPERAND (exp, 0)); - register enum machine_mode mode = TYPE_MODE (type); - int unsignedp = TREE_UNSIGNED (type); - enum rtx_code code = unsignedp ? unsigned_code : signed_code; + /* Preincrement, or we can't increment with one simple insn. */ + if (post) + /* Save a copy of the value before inc or dec, to return it later. */ + temp = value = copy_to_reg (op0); + else + /* Arrange to return the incremented value. */ + /* Copy the rtx because expand_binop will protect from the queue, + and the results of that would be invalid for us to return + if our caller does emit_queue before using our result. */ + temp = copy_rtx (value = op0); -#ifdef HAVE_canonicalize_funcptr_for_compare - /* If function pointers need to be "canonicalized" before they can - be reliably compared, then canonicalize them. */ - if (HAVE_canonicalize_funcptr_for_compare - && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == FUNCTION_TYPE)) - { - rtx new_op0 = gen_reg_rtx (mode); + /* Increment however we can. */ + op1 = expand_binop (mode, this_optab, value, op1, + flag_check_memory_usage ? NULL_RTX : op0, + TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); + /* Make sure the value is stored into OP0. */ + if (op1 != op0) + emit_move_insn (op0, op1); - emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0)); - op0 = new_op0; - } + return temp; +} + +/* Expand all function calls contained within EXP, innermost ones first. + But don't look within expressions that have sequence points. + For each CALL_EXPR, record the rtx for its value + in the CALL_EXPR_RTL field. */ - if (HAVE_canonicalize_funcptr_for_compare - && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))) - == FUNCTION_TYPE)) - { - rtx new_op1 = gen_reg_rtx (mode); +static void +preexpand_calls (exp) + tree exp; +{ + register int nops, i; + int type = TREE_CODE_CLASS (TREE_CODE (exp)); - emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1)); - op1 = new_op1; - } -#endif + if (! do_preexpand_calls) + return; - return compare_from_rtx (op0, op1, code, unsignedp, mode, - ((mode == BLKmode) - ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX), - TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); -} + /* Only expressions and references can contain calls. */ -/* Like compare but expects the values to compare as two rtx's. - The decision as to signed or unsigned comparison must be made by the caller. + if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r') + return; - If MODE is BLKmode, SIZE is an RTX giving the size of the objects being - compared. + switch (TREE_CODE (exp)) + { + case CALL_EXPR: + /* Do nothing if already expanded. */ + if (CALL_EXPR_RTL (exp) != 0 + /* Do nothing if the call returns a variable-sized object. */ + || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST + /* Do nothing to built-in functions. */ + || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + == FUNCTION_DECL) + && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))) + return; - If ALIGN is non-zero, it is the alignment of this type; if zero, the - size of MODE should be used. */ + CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0); + return; -rtx -compare_from_rtx (op0, op1, code, unsignedp, mode, size, align) - register rtx op0, op1; - enum rtx_code code; - int unsignedp; - enum machine_mode mode; - rtx size; - int align; -{ - rtx tem; + case COMPOUND_EXPR: + case COND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + /* If we find one of these, then we can be sure + the adjust will be done for it (since it makes jumps). + Do it now, so that if this is inside an argument + of a function, we don't get the stack adjustment + after some other args have already been pushed. */ + do_pending_stack_adjust (); + return; - /* If one operand is constant, make it the second one. Only do this - if the other operand is not constant as well. */ + case BLOCK: + case RTL_EXPR: + case WITH_CLEANUP_EXPR: + case CLEANUP_POINT_EXPR: + case TRY_CATCH_EXPR: + return; - if ((CONSTANT_P (op0) && ! CONSTANT_P (op1)) - || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT)) - { - tem = op0; - op0 = op1; - op1 = tem; - code = swap_condition (code); + case SAVE_EXPR: + if (SAVE_EXPR_RTL (exp) != 0) + return; + + default: + break; } - if (flag_force_mem) - { - op0 = force_not_mem (op0); - op1 = force_not_mem (op1); - } + nops = tree_code_length[(int) TREE_CODE (exp)]; + for (i = 0; i < nops; i++) + if (TREE_OPERAND (exp, i) != 0) + { + type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i))); + if (type == 'e' || type == '<' || type == '1' || type == '2' + || type == 'r') + preexpand_calls (TREE_OPERAND (exp, i)); + } +} + +/* At the start of a function, record that we have no previously-pushed + arguments waiting to be popped. */ - do_pending_stack_adjust (); +void +init_pending_stack_adjust () +{ + pending_stack_adjust = 0; +} - if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT - && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0) - return tem; +/* When exiting from function, if safe, clear out any pending stack adjust + so the adjustment won't get done. */ -#if 0 - /* There's no need to do this now that combine.c can eliminate lots of - sign extensions. This can be less efficient in certain cases on other - machines. */ +void +clear_pending_stack_adjust () +{ +#ifdef EXIT_IGNORE_STACK + if (optimize > 0 + && ! flag_omit_frame_pointer && EXIT_IGNORE_STACK + && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline) + && ! flag_inline_functions) + pending_stack_adjust = 0; +#endif +} - /* If this is a signed equality comparison, we can do it as an - unsigned comparison since zero-extension is cheaper than sign - extension and comparisons with zero are done as unsigned. This is - the case even on machines that can do fast sign extension, since - zero-extension is easier to combine with other operations than - sign-extension is. If we are comparing against a constant, we must - convert it to what it would look like unsigned. */ - if ((code == EQ || code == NE) && ! unsignedp - && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT) +/* Pop any previously-pushed arguments that have not been popped yet. */ + +void +do_pending_stack_adjust () +{ + if (inhibit_defer_pop == 0) { - if (GET_CODE (op1) == CONST_INT - && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1)) - op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))); - unsignedp = 1; + if (pending_stack_adjust != 0) + adjust_stack (GEN_INT (pending_stack_adjust)); + pending_stack_adjust = 0; } -#endif - - emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align); - - return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); } -/* Generate code to calculate EXP using a store-flag instruction - and return an rtx for the result. EXP is either a comparison - or a TRUTH_NOT_EXPR whose operand is a comparison. - - If TARGET is nonzero, store the result there if convenient. - - If ONLY_CHEAP is non-zero, only do this if it is likely to be very - cheap. - - Return zero if there is no suitable set-flag instruction - available on this machine. +/* Expand conditional expressions. */ - Once expand_expr has been called on the arguments of the comparison, - we are committed to doing the store flag, since it is not safe to - re-evaluate the expression. We emit the store-flag insn by calling - emit_store_flag, but only expand the arguments if we have a reason - to believe that emit_store_flag will be successful. If we think that - it will, but it isn't, we have to simulate the store-flag with a - set/jump/set sequence. */ +/* Generate code to evaluate EXP and jump to LABEL if the value is zero. + LABEL is an rtx of code CODE_LABEL, in this function and all the + functions here. */ -static rtx -do_store_flag (exp, target, mode, only_cheap) +void +jumpifnot (exp, label) tree exp; - rtx target; - enum machine_mode mode; - int only_cheap; + rtx label; { - enum rtx_code code; - tree arg0, arg1, type; - tree tem; - enum machine_mode operand_mode; - int invert = 0; - int unsignedp; - rtx op0, op1; - enum insn_code icode; - rtx subtarget = target; - rtx result, label, pattern, jump_pat; + do_jump (exp, label, NULL_RTX); +} - /* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the - result at the end. We can't simply invert the test since it would - have already been inverted if it were valid. This case occurs for - some floating-point comparisons. */ +/* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */ - if (TREE_CODE (exp) == TRUTH_NOT_EXPR) - invert = 1, exp = TREE_OPERAND (exp, 0); +void +jumpif (exp, label) + tree exp; + rtx label; +{ + do_jump (exp, NULL_RTX, label); +} - arg0 = TREE_OPERAND (exp, 0); - arg1 = TREE_OPERAND (exp, 1); - type = TREE_TYPE (arg0); - operand_mode = TYPE_MODE (type); - unsignedp = TREE_UNSIGNED (type); +/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if + the result is zero, or IF_TRUE_LABEL if the result is one. + Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero, + meaning fall through in that case. - /* We won't bother with BLKmode store-flag operations because it would mean - passing a lot of information to emit_store_flag. */ - if (operand_mode == BLKmode) - return 0; + do_jump always does any pending stack adjust except when it does not + actually perform a jump. An example where there is no jump + is when EXP is `(foo (), 0)' and IF_FALSE_LABEL is null. - /* We won't bother with store-flag operations involving function pointers - when function pointers must be canonicalized before comparisons. */ -#ifdef HAVE_canonicalize_funcptr_for_compare - if (HAVE_canonicalize_funcptr_for_compare - && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))) - == FUNCTION_TYPE)) - || (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE - && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))) - == FUNCTION_TYPE)))) - return 0; -#endif + This function is responsible for optimizing cases such as + &&, || and comparison operators in EXP. */ - STRIP_NOPS (arg0); - STRIP_NOPS (arg1); +void +do_jump (exp, if_false_label, if_true_label) + tree exp; + rtx if_false_label, if_true_label; +{ + register enum tree_code code = TREE_CODE (exp); + /* Some cases need to create a label to jump to + in order to properly fall through. + These cases set DROP_THROUGH_LABEL nonzero. */ + rtx drop_through_label = 0; + rtx temp; + rtx comparison = 0; + int i; + tree type; + enum machine_mode mode; - /* Get the rtx comparison code to use. We know that EXP is a comparison - operation of some type. Some comparisons against 1 and -1 can be - converted to comparisons with zero. Do so here so that the tests - below will be aware that we have a comparison with zero. These - tests will not catch constants in the first operand, but constants - are rarely passed as the first operand. */ + emit_queue (); - switch (TREE_CODE (exp)) + switch (code) { - case EQ_EXPR: - code = EQ; - break; - case NE_EXPR: - code = NE; - break; - case LT_EXPR: - if (integer_onep (arg1)) - arg1 = integer_zero_node, code = unsignedp ? LEU : LE; - else - code = unsignedp ? LTU : LT; - break; - case LE_EXPR: - if (! unsignedp && integer_all_onesp (arg1)) - arg1 = integer_zero_node, code = LT; - else - code = unsignedp ? LEU : LE; - break; - case GT_EXPR: - if (! unsignedp && integer_all_onesp (arg1)) - arg1 = integer_zero_node, code = GE; - else - code = unsignedp ? GTU : GT; - break; - case GE_EXPR: - if (integer_onep (arg1)) - arg1 = integer_zero_node, code = unsignedp ? GTU : GT; - else - code = unsignedp ? GEU : GE; + case ERROR_MARK: break; - default: - abort (); - } - - /* Put a constant second. */ - if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST) - { - tem = arg0; arg0 = arg1; arg1 = tem; - code = swap_condition (code); - } - - /* If this is an equality or inequality test of a single bit, we can - do this by shifting the bit being tested to the low-order bit and - masking the result with the constant 1. If the condition was EQ, - we xor it with 1. This does not require an scc insn and is faster - than an scc insn even if we have it. */ - if ((code == NE || code == EQ) - && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) - && integer_pow2p (TREE_OPERAND (arg0, 1))) - { - tree inner = TREE_OPERAND (arg0, 0); - int bitnum = tree_log2 (TREE_OPERAND (arg0, 1)); - int ops_unsignedp; + case INTEGER_CST: + temp = integer_zerop (exp) ? if_false_label : if_true_label; + if (temp) + emit_jump (temp); + break; - /* If INNER is a right shift of a constant and it plus BITNUM does - not overflow, adjust BITNUM and INNER. */ +#if 0 + /* This is not true with #pragma weak */ + case ADDR_EXPR: + /* The address of something can never be zero. */ + if (if_true_label) + emit_jump (if_true_label); + break; +#endif - if (TREE_CODE (inner) == RSHIFT_EXPR - && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST - && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0 - && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)) - < TYPE_PRECISION (type))) - { - bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)); - inner = TREE_OPERAND (inner, 0); - } + case NOP_EXPR: + if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF + || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF + || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF) + goto normal; + case CONVERT_EXPR: + /* If we are narrowing the operand, we have to do the compare in the + narrower mode. */ + if ((TYPE_PRECISION (TREE_TYPE (exp)) + < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))) + goto normal; + case NON_LVALUE_EXPR: + case REFERENCE_EXPR: + case ABS_EXPR: + case NEGATE_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + /* These cannot change zero->non-zero or vice versa. */ + do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); + break; - /* If we are going to be able to omit the AND below, we must do our - operations as unsigned. If we must use the AND, we have a choice. - Normally unsigned is faster, but for some machines signed is. */ - ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1 -#ifdef LOAD_EXTEND_OP - : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1) -#else - : 1 +#if 0 + /* This is never less insns than evaluating the PLUS_EXPR followed by + a test and can be longer if the test is eliminated. */ + case PLUS_EXPR: + /* Reduce to minus. */ + exp = build (MINUS_EXPR, TREE_TYPE (exp), + TREE_OPERAND (exp, 0), + fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)), + TREE_OPERAND (exp, 1)))); + /* Process as MINUS. */ #endif - ); - - if (subtarget == 0 || GET_CODE (subtarget) != REG - || GET_MODE (subtarget) != operand_mode - || ! safe_from_p (subtarget, inner)) - subtarget = 0; - - op0 = expand_expr (inner, subtarget, VOIDmode, 0); - if (bitnum != 0) - op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0, - size_int (bitnum), subtarget, ops_unsignedp); + case MINUS_EXPR: + /* Non-zero iff operands of minus differ. */ + comparison = compare (build (NE_EXPR, TREE_TYPE (exp), + TREE_OPERAND (exp, 0), + TREE_OPERAND (exp, 1)), + NE, NE); + break; - if (GET_MODE (op0) != mode) - op0 = convert_to_mode (mode, op0, ops_unsignedp); + case BIT_AND_EXPR: + /* If we are AND'ing with a small constant, do this comparison in the + smallest type that fits. If the machine doesn't have comparisons + that small, it will be converted back to the wider comparison. + This helps if we are testing the sign bit of a narrower object. + combine can't do this for us because it can't know whether a + ZERO_EXTRACT or a compare in a smaller mode exists, but we do. */ - if ((code == EQ && ! invert) || (code == NE && invert)) - op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget, - ops_unsignedp, OPTAB_LIB_WIDEN); + if (! SLOW_BYTE_ACCESS + && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT + && (i = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0 + && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode + && (type = type_for_mode (mode, 1)) != 0 + && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) + && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code + != CODE_FOR_nothing)) + { + do_jump (convert (type, exp), if_false_label, if_true_label); + break; + } + goto normal; - /* Put the AND last so it can combine with more things. */ - if (bitnum != TYPE_PRECISION (type) - 1) - op0 = expand_and (op0, const1_rtx, subtarget); + case TRUTH_NOT_EXPR: + do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); + break; - return op0; - } + case TRUTH_ANDIF_EXPR: + if (if_false_label == 0) + if_false_label = drop_through_label = gen_label_rtx (); + do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX); + start_cleanup_deferral (); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + end_cleanup_deferral (); + break; - /* Now see if we are likely to be able to do this. Return if not. */ - if (! can_compare_p (operand_mode)) - return 0; - icode = setcc_gen_code[(int) code]; - if (icode == CODE_FOR_nothing - || (only_cheap && insn_operand_mode[(int) icode][0] != mode)) - { - /* We can only do this if it is one of the special cases that - can be handled without an scc insn. */ - if ((code == LT && integer_zerop (arg1)) - || (! only_cheap && code == GE && integer_zerop (arg1))) - ; - else if (BRANCH_COST >= 0 - && ! only_cheap && (code == NE || code == EQ) - && TREE_CODE (type) != REAL_TYPE - && ((abs_optab->handlers[(int) operand_mode].insn_code - != CODE_FOR_nothing) - || (ffs_optab->handlers[(int) operand_mode].insn_code - != CODE_FOR_nothing))) - ; - else - return 0; - } - - preexpand_calls (exp); - if (subtarget == 0 || GET_CODE (subtarget) != REG - || GET_MODE (subtarget) != operand_mode - || ! safe_from_p (subtarget, arg1)) - subtarget = 0; + case TRUTH_ORIF_EXPR: + if (if_true_label == 0) + if_true_label = drop_through_label = gen_label_rtx (); + do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label); + start_cleanup_deferral (); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + end_cleanup_deferral (); + break; - op0 = expand_expr (arg0, subtarget, VOIDmode, 0); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + case COMPOUND_EXPR: + push_temp_slots (); + expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); + preserve_temp_slots (NULL_RTX); + free_temp_slots (); + pop_temp_slots (); + emit_queue (); + do_pending_stack_adjust (); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + break; - if (target == 0) - target = gen_reg_rtx (mode); + case COMPONENT_REF: + case BIT_FIELD_REF: + case ARRAY_REF: + { + int bitsize, bitpos, unsignedp; + enum machine_mode mode; + tree type; + tree offset; + int volatilep = 0; + int alignment; - /* Pass copies of OP0 and OP1 in case they contain a QUEUED. This is safe - because, if the emit_store_flag does anything it will succeed and - OP0 and OP1 will not be used subsequently. */ + /* Get description of this reference. We don't actually care + about the underlying object here. */ + get_inner_reference (exp, &bitsize, &bitpos, &offset, + &mode, &unsignedp, &volatilep, + &alignment); - result = emit_store_flag (target, code, - queued_subexp_p (op0) ? copy_rtx (op0) : op0, - queued_subexp_p (op1) ? copy_rtx (op1) : op1, - operand_mode, unsignedp, 1); + type = type_for_size (bitsize, unsignedp); + if (! SLOW_BYTE_ACCESS + && type != 0 && bitsize >= 0 + && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) + && (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code + != CODE_FOR_nothing)) + { + do_jump (convert (type, exp), if_false_label, if_true_label); + break; + } + goto normal; + } - if (result) - { - if (invert) - result = expand_binop (mode, xor_optab, result, const1_rtx, - result, 0, OPTAB_LIB_WIDEN); - return result; - } + case COND_EXPR: + /* Do (a ? 1 : 0) and (a ? 0 : 1) as special cases. */ + if (integer_onep (TREE_OPERAND (exp, 1)) + && integer_zerop (TREE_OPERAND (exp, 2))) + do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); - /* If this failed, we have to do this with set/compare/jump/set code. */ - if (GET_CODE (target) != REG - || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1)) - target = gen_reg_rtx (GET_MODE (target)); + else if (integer_zerop (TREE_OPERAND (exp, 1)) + && integer_onep (TREE_OPERAND (exp, 2))) + do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); - emit_move_insn (target, invert ? const0_rtx : const1_rtx); - result = compare_from_rtx (op0, op1, code, unsignedp, - operand_mode, NULL_RTX, 0); - if (GET_CODE (result) == CONST_INT) - return (((result == const0_rtx && ! invert) - || (result != const0_rtx && invert)) - ? const0_rtx : const1_rtx); + else + { + register rtx label1 = gen_label_rtx (); + drop_through_label = gen_label_rtx (); - label = gen_label_rtx (); - if (bcc_gen_fctn[(int) code] == 0) - abort (); + do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX); - emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label)); - emit_move_insn (target, invert ? const1_rtx : const0_rtx); - emit_label (label); + start_cleanup_deferral (); + /* Now the THEN-expression. */ + do_jump (TREE_OPERAND (exp, 1), + if_false_label ? if_false_label : drop_through_label, + if_true_label ? if_true_label : drop_through_label); + /* In case the do_jump just above never jumps. */ + do_pending_stack_adjust (); + emit_label (label1); - return target; -} - -/* Generate a tablejump instruction (used for switch statements). */ + /* Now the ELSE-expression. */ + do_jump (TREE_OPERAND (exp, 2), + if_false_label ? if_false_label : drop_through_label, + if_true_label ? if_true_label : drop_through_label); + end_cleanup_deferral (); + } + break; -#ifdef HAVE_tablejump + case EQ_EXPR: + { + tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); -/* INDEX is the value being switched on, with the lowest value - in the table already subtracted. - MODE is its expected mode (needed if INDEX is constant). - RANGE is the length of the jump table. - TABLE_LABEL is a CODE_LABEL rtx for the table itself. + if (integer_zerop (TREE_OPERAND (exp, 1))) + do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); + else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT + || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT) + do_jump + (fold + (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp), + fold (build (EQ_EXPR, TREE_TYPE (exp), + fold (build1 (REALPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 0))), + fold (build1 (REALPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 1))))), + fold (build (EQ_EXPR, TREE_TYPE (exp), + fold (build1 (IMAGPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 0))), + fold (build1 (IMAGPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 1))))))), + if_false_label, if_true_label); + else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT + && !can_compare_p (TYPE_MODE (inner_type))) + do_jump_by_parts_equality (exp, if_false_label, if_true_label); + else + comparison = compare (exp, EQ, EQ); + break; + } - DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the - index value is out of range. */ + case NE_EXPR: + { + tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); -void -do_tablejump (index, mode, range, table_label, default_label) - rtx index, range, table_label, default_label; - enum machine_mode mode; -{ - register rtx temp, vector; + if (integer_zerop (TREE_OPERAND (exp, 1))) + do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); + else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT + || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT) + do_jump + (fold + (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), + fold (build (NE_EXPR, TREE_TYPE (exp), + fold (build1 (REALPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 0))), + fold (build1 (REALPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 1))))), + fold (build (NE_EXPR, TREE_TYPE (exp), + fold (build1 (IMAGPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 0))), + fold (build1 (IMAGPART_EXPR, + TREE_TYPE (inner_type), + TREE_OPERAND (exp, 1))))))), + if_false_label, if_true_label); + else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT + && !can_compare_p (TYPE_MODE (inner_type))) + do_jump_by_parts_equality (exp, if_true_label, if_false_label); + else + comparison = compare (exp, NE, NE); + break; + } - /* Do an unsigned comparison (in the proper mode) between the index - expression and the value which represents the length of the range. - Since we just finished subtracting the lower bound of the range - from the index expression, this comparison allows us to simultaneously - check that the original index expression value is both greater than - or equal to the minimum value of the range and less than or equal to - the maximum value of the range. */ + case LT_EXPR: + if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == MODE_INT) + && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) + do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label); + else + comparison = compare (exp, LT, LTU); + break; - emit_cmp_insn (index, range, GTU, NULL_RTX, mode, 1, 0); - emit_jump_insn (gen_bgtu (default_label)); + case LE_EXPR: + if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == MODE_INT) + && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) + do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label); + else + comparison = compare (exp, LE, LEU); + break; - /* If index is in range, it must fit in Pmode. - Convert to Pmode so we can index with it. */ - if (mode != Pmode) - index = convert_to_mode (Pmode, index, 1); + case GT_EXPR: + if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == MODE_INT) + && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) + do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label); + else + comparison = compare (exp, GT, GTU); + break; - /* Don't let a MEM slip thru, because then INDEX that comes - out of PIC_CASE_VECTOR_ADDRESS won't be a valid address, - and break_out_memory_refs will go to work on it and mess it up. */ -#ifdef PIC_CASE_VECTOR_ADDRESS - if (flag_pic && GET_CODE (index) != REG) - index = copy_to_mode_reg (Pmode, index); -#endif + case GE_EXPR: + if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == MODE_INT) + && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) + do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label); + else + comparison = compare (exp, GE, GEU); + break; - /* If flag_force_addr were to affect this address - it could interfere with the tricky assumptions made - about addresses that contain label-refs, - which may be valid only very near the tablejump itself. */ - /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the - GET_MODE_SIZE, because this indicates how large insns are. The other - uses should all be Pmode, because they are addresses. This code - could fail if addresses and insns are not the same size. */ - index = gen_rtx_PLUS (Pmode, - gen_rtx_MULT (Pmode, index, - GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))), - gen_rtx_LABEL_REF (Pmode, table_label)); -#ifdef PIC_CASE_VECTOR_ADDRESS - if (flag_pic) - index = PIC_CASE_VECTOR_ADDRESS (index); - else + default: + normal: + temp = expand_expr (exp, NULL_RTX, VOIDmode, 0); +#if 0 + /* This is not needed any more and causes poor code since it causes + comparisons and tests from non-SI objects to have different code + sequences. */ + /* Copy to register to avoid generating bad insns by cse + from (set (mem ...) (arithop)) (set (cc0) (mem ...)). */ + if (!cse_not_expected && GET_CODE (temp) == MEM) + temp = copy_to_reg (temp); #endif - index = memory_address_noforce (CASE_VECTOR_MODE, index); - temp = gen_reg_rtx (CASE_VECTOR_MODE); - vector = gen_rtx_MEM (CASE_VECTOR_MODE, index); - RTX_UNCHANGING_P (vector) = 1; - convert_move (temp, vector, 0); - - emit_jump_insn (gen_tablejump (temp, table_label)); - - /* If we are generating PIC code or if the table is PC-relative, the - table and JUMP_INSN must be adjacent, so don't output a BARRIER. */ - if (! CASE_VECTOR_PC_RELATIVE && ! flag_pic) - emit_barrier (); -} - -#endif /* HAVE_tablejump */ + do_pending_stack_adjust (); + if (GET_CODE (temp) == CONST_INT) + comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx); + else if (GET_CODE (temp) == LABEL_REF) + comparison = const_true_rtx; + else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT + && !can_compare_p (GET_MODE (temp))) + /* Note swapping the labels gives us not-equal. */ + do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label); + else if (GET_MODE (temp) != VOIDmode) + comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)), + NE, TREE_UNSIGNED (TREE_TYPE (exp)), + GET_MODE (temp), NULL_RTX, 0); + else + abort (); + } + /* Do any postincrements in the expression that was tested. */ + emit_queue (); -/* Emit a suitable bytecode to load a value from memory, assuming a pointer - to that value is on the top of the stack. The resulting type is TYPE, and - the source declaration is DECL. */ + /* If COMPARISON is nonzero here, it is an rtx that can be substituted + straight into a conditional jump instruction as the jump condition. + Otherwise, all the work has been done already. */ -void -bc_load_memory (type, decl) - tree type, decl; -{ - enum bytecode_opcode opcode; - - - /* Bit fields are special. We only know about signed and - unsigned ints, and enums. The latter are treated as - signed integers. */ - - if (DECL_BIT_FIELD (decl)) - if (TREE_CODE (type) == ENUMERAL_TYPE - || TREE_CODE (type) == INTEGER_TYPE) - opcode = TREE_UNSIGNED (type) ? zxloadBI : sxloadBI; - else - abort (); - else - /* See corresponding comment in bc_store_memory. */ - if (TYPE_MODE (type) == BLKmode - || TYPE_MODE (type) == VOIDmode) - return; - else - opcode = mode_to_load_map [(int) TYPE_MODE (type)]; + if (comparison == const_true_rtx) + { + if (if_true_label) + emit_jump (if_true_label); + } + else if (comparison == const0_rtx) + { + if (if_false_label) + emit_jump (if_false_label); + } + else if (comparison) + do_jump_for_compare (comparison, if_false_label, if_true_label); - if (opcode == neverneverland) - abort (); - - bc_emit_bytecode (opcode); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif + if (drop_through_label) + { + /* If do_jump produces code that might be jumped around, + do any stack adjusts from that code, before the place + where control merges in. */ + do_pending_stack_adjust (); + emit_label (drop_through_label); + } } + +/* Given a comparison expression EXP for values too wide to be compared + with one insn, test the comparison and jump to the appropriate label. + The code of EXP is ignored; we always test GT if SWAP is 0, + and LT if SWAP is 1. */ +static void +do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label) + tree exp; + int swap; + rtx if_false_label, if_true_label; +{ + rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0); + enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); + int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); + rtx drop_through_label = 0; + int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))); + int i; -/* Store the contents of the second stack slot to the address in the - top stack slot. DECL is the declaration of the destination and is used - to determine whether we're dealing with a bitfield. */ + if (! if_true_label || ! if_false_label) + drop_through_label = gen_label_rtx (); + if (! if_true_label) + if_true_label = drop_through_label; + if (! if_false_label) + if_false_label = drop_through_label; -void -bc_store_memory (type, decl) - tree type, decl; -{ - enum bytecode_opcode opcode; - - - if (DECL_BIT_FIELD (decl)) + /* Compare a word at a time, high order first. */ + for (i = 0; i < nwords; i++) { - if (TREE_CODE (type) == ENUMERAL_TYPE - || TREE_CODE (type) == INTEGER_TYPE) - opcode = sstoreBI; + rtx comp; + rtx op0_word, op1_word; + + if (WORDS_BIG_ENDIAN) + { + op0_word = operand_subword_force (op0, i, mode); + op1_word = operand_subword_force (op1, i, mode); + } else - abort (); + { + op0_word = operand_subword_force (op0, nwords - 1 - i, mode); + op1_word = operand_subword_force (op1, nwords - 1 - i, mode); + } + + /* All but high-order word must be compared as unsigned. */ + comp = compare_from_rtx (op0_word, op1_word, + (unsignedp || i > 0) ? GTU : GT, + unsignedp, word_mode, NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_true_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, NULL_RTX, if_true_label); + + /* Consider lower words only if these are equal. */ + comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode, + NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_false_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, NULL_RTX, if_false_label); } - else - if (TYPE_MODE (type) == BLKmode) - { - /* Copy structure. This expands to a block copy instruction, storeBLK. - In addition to the arguments expected by the other store instructions, - it also expects a type size (SImode) on top of the stack, which is the - structure size in size units (usually bytes). The two first arguments - are already on the stack; so we just put the size on level 1. For some - other languages, the size may be variable, this is why we don't encode - it as a storeBLK literal, but rather treat it as a full-fledged expression. */ - - bc_expand_expr (TYPE_SIZE (type)); - opcode = storeBLK; - } - else - opcode = mode_to_store_map [(int) TYPE_MODE (type)]; - - if (opcode == neverneverland) - abort (); - bc_emit_bytecode (opcode); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif + if (if_false_label) + emit_jump (if_false_label); + if (drop_through_label) + emit_label (drop_through_label); } +/* Compare OP0 with OP1, word at a time, in mode MODE. + UNSIGNEDP says to do unsigned comparison. + Jump to IF_TRUE_LABEL if OP0 is greater, IF_FALSE_LABEL otherwise. */ -/* Allocate local stack space sufficient to hold a value of the given - SIZE at alignment boundary ALIGNMENT bits. ALIGNMENT must be an - integral power of 2. A special case is locals of type VOID, which - have size 0 and alignment 1 - any "voidish" SIZE or ALIGNMENT is - remapped into the corresponding attribute of SI. */ - -rtx -bc_allocate_local (size, alignment) - int size, alignment; +void +do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label) + enum machine_mode mode; + int unsignedp; + rtx op0, op1; + rtx if_false_label, if_true_label; { - rtx retval; - int byte_alignment; + int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); + rtx drop_through_label = 0; + int i; - if (size < 0) - abort (); + if (! if_true_label || ! if_false_label) + drop_through_label = gen_label_rtx (); + if (! if_true_label) + if_true_label = drop_through_label; + if (! if_false_label) + if_false_label = drop_through_label; - /* Normalize size and alignment */ - if (!size) - size = UNITS_PER_WORD; + /* Compare a word at a time, high order first. */ + for (i = 0; i < nwords; i++) + { + rtx comp; + rtx op0_word, op1_word; - if (alignment < BITS_PER_UNIT) - byte_alignment = 1 << (INT_ALIGN - 1); - else - /* Align */ - byte_alignment = alignment / BITS_PER_UNIT; + if (WORDS_BIG_ENDIAN) + { + op0_word = operand_subword_force (op0, i, mode); + op1_word = operand_subword_force (op1, i, mode); + } + else + { + op0_word = operand_subword_force (op0, nwords - 1 - i, mode); + op1_word = operand_subword_force (op1, nwords - 1 - i, mode); + } - if (local_vars_size & (byte_alignment - 1)) - local_vars_size += byte_alignment - (local_vars_size & (byte_alignment - 1)); + /* All but high-order word must be compared as unsigned. */ + comp = compare_from_rtx (op0_word, op1_word, + (unsignedp || i > 0) ? GTU : GT, + unsignedp, word_mode, NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_true_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, NULL_RTX, if_true_label); - retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0); - local_vars_size += size; + /* Consider lower words only if these are equal. */ + comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode, + NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_false_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, NULL_RTX, if_false_label); + } - return retval; + if (if_false_label) + emit_jump (if_false_label); + if (drop_through_label) + emit_label (drop_through_label); } +/* Given an EQ_EXPR expression EXP for values too wide to be compared + with one insn, test the comparison and jump to the appropriate label. */ -/* Allocate variable-sized local array. Variable-sized arrays are - actually pointers to the address in memory where they are stored. */ - -rtx -bc_allocate_variable_array (size) - tree size; +static void +do_jump_by_parts_equality (exp, if_false_label, if_true_label) + tree exp; + rtx if_false_label, if_true_label; { - rtx retval; - const int ptralign = (1 << (PTR_ALIGN - 1)); + rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); + enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); + int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD); + int i; + rtx drop_through_label = 0; - /* Align pointer */ - if (local_vars_size & ptralign) - local_vars_size += ptralign - (local_vars_size & ptralign); + if (! if_false_label) + drop_through_label = if_false_label = gen_label_rtx (); - /* Note down local space needed: pointer to block; also return - dummy rtx */ + for (i = 0; i < nwords; i++) + { + rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode), + operand_subword_force (op1, i, mode), + EQ, TREE_UNSIGNED (TREE_TYPE (exp)), + word_mode, NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_false_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, if_false_label, NULL_RTX); + } - retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0); - local_vars_size += POINTER_SIZE / BITS_PER_UNIT; - return retval; + if (if_true_label) + emit_jump (if_true_label); + if (drop_through_label) + emit_label (drop_through_label); } + +/* Jump according to whether OP0 is 0. + We assume that OP0 has an integer mode that is too wide + for the available compare insns. */ - -/* Push the machine address for the given external variable offset. */ - -void -bc_load_externaddr (externaddr) - rtx externaddr; +static void +do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) + rtx op0; + rtx if_false_label, if_true_label; { - bc_emit_bytecode (constP); - bc_emit_code_labelref (BYTECODE_LABEL (externaddr), - BYTECODE_BC_LABEL (externaddr)->offset); + int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD; + rtx part; + int i; + rtx drop_through_label = 0; -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif -} + /* The fastest way of doing this comparison on almost any machine is to + "or" all the words and compare the result. If all have to be loaded + from memory and this is a very wide item, it's possible this may + be slower, but that's highly unlikely. */ + part = gen_reg_rtx (word_mode); + emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0))); + for (i = 1; i < nwords && part != 0; i++) + part = expand_binop (word_mode, ior_optab, part, + operand_subword_force (op0, i, GET_MODE (op0)), + part, 1, OPTAB_WIDEN); -/* Like above, but expects an IDENTIFIER. */ + if (part != 0) + { + rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode, + NULL_RTX, 0); -void -bc_load_externaddr_id (id, offset) - tree id; - int offset; -{ - if (!IDENTIFIER_POINTER (id)) - abort (); + if (comp == const_true_rtx) + emit_jump (if_false_label); + else if (comp == const0_rtx) + emit_jump (if_true_label); + else + do_jump_for_compare (comp, if_false_label, if_true_label); - bc_emit_bytecode (constP); - bc_emit_code_labelref (xstrdup (IDENTIFIER_POINTER (id)), offset); + return; + } -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif -} + /* If we couldn't do the "or" simply, do this with a series of compares. */ + if (! if_false_label) + drop_through_label = if_false_label = gen_label_rtx (); + for (i = 0; i < nwords; i++) + { + rtx comp = compare_from_rtx (operand_subword_force (op0, i, + GET_MODE (op0)), + const0_rtx, EQ, 1, word_mode, NULL_RTX, 0); + if (comp == const_true_rtx) + emit_jump (if_false_label); + else if (comp != const0_rtx) + do_jump_for_compare (comp, if_false_label, NULL_RTX); + } -/* Push the machine address for the given local variable offset. */ + if (if_true_label) + emit_jump (if_true_label); -void -bc_load_localaddr (localaddr) - rtx localaddr; -{ - bc_emit_instruction (localP, (HOST_WIDE_INT) BYTECODE_BC_LABEL (localaddr)->offset); + if (drop_through_label) + emit_label (drop_through_label); } +/* Given a comparison expression in rtl form, output conditional branches to + IF_TRUE_LABEL, IF_FALSE_LABEL, or both. */ -/* Push the machine address for the given parameter offset. - NOTE: offset is in bits. */ - -void -bc_load_parmaddr (parmaddr) - rtx parmaddr; +static void +do_jump_for_compare (comparison, if_false_label, if_true_label) + rtx comparison, if_false_label, if_true_label; { - bc_emit_instruction (argP, ((HOST_WIDE_INT) BYTECODE_BC_LABEL (parmaddr)->offset - / BITS_PER_UNIT)); -} - + if (if_true_label) + { + if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0) + emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label)); + else + abort (); -/* Convert a[i] into *(a + i). */ + if (if_false_label) + emit_jump (if_false_label); + } + else if (if_false_label) + { + rtx insn; + rtx prev = get_last_insn (); + rtx branch = 0; -tree -bc_canonicalize_array_ref (exp) - tree exp; -{ - tree type = TREE_TYPE (exp); - tree array_adr = build1 (ADDR_EXPR, TYPE_POINTER_TO (type), - TREE_OPERAND (exp, 0)); - tree index = TREE_OPERAND (exp, 1); - - - /* Convert the integer argument to a type the same size as a pointer - so the multiply won't overflow spuriously. */ - - if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE) - index = convert (type_for_size (POINTER_SIZE, 0), index); - - /* The array address isn't volatile even if the array is. - (Of course this isn't terribly relevant since the bytecode - translator treats nearly everything as volatile anyway.) */ - TREE_THIS_VOLATILE (array_adr) = 0; - - return build1 (INDIRECT_REF, type, - fold (build (PLUS_EXPR, - TYPE_POINTER_TO (type), - array_adr, - fold (build (MULT_EXPR, - TYPE_POINTER_TO (type), - index, - size_in_bytes (type)))))); -} + /* Output the branch with the opposite condition. Then try to invert + what is generated. If more than one insn is a branch, or if the + branch is not the last insn written, abort. If we can't invert + the branch, emit make a true label, redirect this jump to that, + emit a jump to the false label and define the true label. */ + if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0) + emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])(if_false_label)); + else + abort (); -/* Load the address of the component referenced by the given - COMPONENT_REF expression. + /* Here we get the first insn that was just emitted. It used to be the + case that, on some machines, emitting the branch would discard + the previous compare insn and emit a replacement. This isn't + done anymore, but abort if we see that PREV is deleted. */ - Returns innermost lvalue. */ + if (prev == 0) + insn = get_insns (); + else if (INSN_DELETED_P (prev)) + abort (); + else + insn = NEXT_INSN (prev); -tree -bc_expand_component_address (exp) - tree exp; -{ - tree tem, chain; - enum machine_mode mode; - int bitpos = 0; - HOST_WIDE_INT SIval; + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == JUMP_INSN) + { + if (branch) + abort (); + branch = insn; + } + if (branch != get_last_insn ()) + abort (); - tem = TREE_OPERAND (exp, 1); - mode = DECL_MODE (tem); + JUMP_LABEL (branch) = if_false_label; + if (! invert_jump (branch, if_false_label)) + { + if_true_label = gen_label_rtx (); + redirect_jump (branch, if_true_label); + emit_jump (if_false_label); + emit_label (if_true_label); + } + } +} + +/* Generate code for a comparison expression EXP + (including code to compute the values to be compared) + and set (CC0) according to the result. + SIGNED_CODE should be the rtx operation for this comparison for + signed data; UNSIGNED_CODE, likewise for use if data is unsigned. + We force a stack adjustment unless there are currently + things pushed on the stack that aren't yet used. */ - /* Compute cumulative bit offset for nested component refs - and array refs, and find the ultimate containing object. */ +static rtx +compare (exp, signed_code, unsigned_code) + register tree exp; + enum rtx_code signed_code, unsigned_code; +{ + register rtx op0 + = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + register rtx op1 + = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); + register tree type = TREE_TYPE (TREE_OPERAND (exp, 0)); + register enum machine_mode mode = TYPE_MODE (type); + int unsignedp = TREE_UNSIGNED (type); + enum rtx_code code = unsignedp ? unsigned_code : signed_code; - for (tem = exp;; tem = TREE_OPERAND (tem, 0)) +#ifdef HAVE_canonicalize_funcptr_for_compare + /* If function pointers need to be "canonicalized" before they can + be reliably compared, then canonicalize them. */ + if (HAVE_canonicalize_funcptr_for_compare + && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == FUNCTION_TYPE)) { - if (TREE_CODE (tem) == COMPONENT_REF) - bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (tem, 1))); - else - if (TREE_CODE (tem) == ARRAY_REF - && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST - && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST) + rtx new_op0 = gen_reg_rtx (mode); - bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)) - * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem))) - /* * TYPE_SIZE_UNIT (TREE_TYPE (tem)) */); - else - break; + emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0)); + op0 = new_op0; } - bc_expand_expr (tem); - - - /* For bitfields also push their offset and size */ - if (DECL_BIT_FIELD (TREE_OPERAND (exp, 1))) - bc_push_offset_and_size (bitpos, /* DECL_SIZE_UNIT */ (TREE_OPERAND (exp, 1))); - else - if (SIval = bitpos / BITS_PER_UNIT) - bc_emit_instruction (addconstPSI, SIval); - - return (TREE_OPERAND (exp, 1)); -} - + if (HAVE_canonicalize_funcptr_for_compare + && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))) + == FUNCTION_TYPE)) + { + rtx new_op1 = gen_reg_rtx (mode); -/* Emit code to push two SI constants */ + emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1)); + op1 = new_op1; + } +#endif -void -bc_push_offset_and_size (offset, size) - HOST_WIDE_INT offset, size; -{ - bc_emit_instruction (constSI, offset); - bc_emit_instruction (constSI, size); + return compare_from_rtx (op0, op1, code, unsignedp, mode, + ((mode == BLKmode) + ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX), + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); } +/* Like compare but expects the values to compare as two rtx's. + The decision as to signed or unsigned comparison must be made by the caller. -/* Emit byte code to push the address of the given lvalue expression to - the stack. If it's a bit field, we also push offset and size info. + If MODE is BLKmode, SIZE is an RTX giving the size of the objects being + compared. - Returns innermost component, which allows us to determine not only - its type, but also whether it's a bitfield. */ + If ALIGN is non-zero, it is the alignment of this type; if zero, the + size of MODE should be used. */ -tree -bc_expand_address (exp) - tree exp; +rtx +compare_from_rtx (op0, op1, code, unsignedp, mode, size, align) + register rtx op0, op1; + enum rtx_code code; + int unsignedp; + enum machine_mode mode; + rtx size; + int align; { - /* Safeguard */ - if (!exp || TREE_CODE (exp) == ERROR_MARK) - return (exp); + rtx tem; + /* If one operand is constant, make it the second one. Only do this + if the other operand is not constant as well. */ - switch (TREE_CODE (exp)) + if ((CONSTANT_P (op0) && ! CONSTANT_P (op1)) + || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT)) { - case ARRAY_REF: - - return (bc_expand_address (bc_canonicalize_array_ref (exp))); - - case COMPONENT_REF: - - return (bc_expand_component_address (exp)); + tem = op0; + op0 = op1; + op1 = tem; + code = swap_condition (code); + } - case INDIRECT_REF: + if (flag_force_mem) + { + op0 = force_not_mem (op0); + op1 = force_not_mem (op1); + } - bc_expand_expr (TREE_OPERAND (exp, 0)); + do_pending_stack_adjust (); - /* For variable-sized types: retrieve pointer. Sometimes the - TYPE_SIZE tree is NULL. Is this a bug or a feature? Let's - also make sure we have an operand, just in case... */ + if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT + && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0) + return tem; - if (TREE_OPERAND (exp, 0) - && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0))) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))) != INTEGER_CST) - bc_emit_instruction (loadP); +#if 0 + /* There's no need to do this now that combine.c can eliminate lots of + sign extensions. This can be less efficient in certain cases on other + machines. */ - /* If packed, also return offset and size */ - if (DECL_BIT_FIELD (TREE_OPERAND (exp, 0))) + /* If this is a signed equality comparison, we can do it as an + unsigned comparison since zero-extension is cheaper than sign + extension and comparisons with zero are done as unsigned. This is + the case even on machines that can do fast sign extension, since + zero-extension is easier to combine with other operations than + sign-extension is. If we are comparing against a constant, we must + convert it to what it would look like unsigned. */ + if ((code == EQ || code == NE) && ! unsignedp + && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT) + { + if (GET_CODE (op1) == CONST_INT + && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1)) + op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))); + unsignedp = 1; + } +#endif - bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (exp, 0))), - TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (exp, 0)))); - - return (TREE_OPERAND (exp, 0)); + emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align); - case FUNCTION_DECL: + return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); +} + +/* Generate code to calculate EXP using a store-flag instruction + and return an rtx for the result. EXP is either a comparison + or a TRUTH_NOT_EXPR whose operand is a comparison. - bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), - BYTECODE_BC_LABEL (DECL_RTL (exp))->offset); - break; + If TARGET is nonzero, store the result there if convenient. - case PARM_DECL: + If ONLY_CHEAP is non-zero, only do this if it is likely to be very + cheap. - bc_load_parmaddr (DECL_RTL (exp)); + Return zero if there is no suitable set-flag instruction + available on this machine. - /* For variable-sized types: retrieve pointer */ - if (TYPE_SIZE (TREE_TYPE (exp)) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST) - bc_emit_instruction (loadP); + Once expand_expr has been called on the arguments of the comparison, + we are committed to doing the store flag, since it is not safe to + re-evaluate the expression. We emit the store-flag insn by calling + emit_store_flag, but only expand the arguments if we have a reason + to believe that emit_store_flag will be successful. If we think that + it will, but it isn't, we have to simulate the store-flag with a + set/jump/set sequence. */ - /* If packed, also return offset and size */ - if (DECL_BIT_FIELD (exp)) - bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)), - TREE_INT_CST_LOW (DECL_SIZE (exp))); +static rtx +do_store_flag (exp, target, mode, only_cheap) + tree exp; + rtx target; + enum machine_mode mode; + int only_cheap; +{ + enum rtx_code code; + tree arg0, arg1, type; + tree tem; + enum machine_mode operand_mode; + int invert = 0; + int unsignedp; + rtx op0, op1; + enum insn_code icode; + rtx subtarget = target; + rtx result, label, pattern, jump_pat; - break; + /* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the + result at the end. We can't simply invert the test since it would + have already been inverted if it were valid. This case occurs for + some floating-point comparisons. */ - case RESULT_DECL: + if (TREE_CODE (exp) == TRUTH_NOT_EXPR) + invert = 1, exp = TREE_OPERAND (exp, 0); - bc_emit_instruction (returnP); - break; + arg0 = TREE_OPERAND (exp, 0); + arg1 = TREE_OPERAND (exp, 1); + type = TREE_TYPE (arg0); + operand_mode = TYPE_MODE (type); + unsignedp = TREE_UNSIGNED (type); - case VAR_DECL: + /* We won't bother with BLKmode store-flag operations because it would mean + passing a lot of information to emit_store_flag. */ + if (operand_mode == BLKmode) + return 0; -#if 0 - if (BYTECODE_LABEL (DECL_RTL (exp))) - bc_load_externaddr (DECL_RTL (exp)); + /* We won't bother with store-flag operations involving function pointers + when function pointers must be canonicalized before comparisons. */ +#ifdef HAVE_canonicalize_funcptr_for_compare + if (HAVE_canonicalize_funcptr_for_compare + && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + == FUNCTION_TYPE)) + || (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))) + == FUNCTION_TYPE)))) + return 0; #endif - if (DECL_EXTERNAL (exp)) - bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp), - (BYTECODE_BC_LABEL (DECL_RTL (exp)))->offset); - else - bc_load_localaddr (DECL_RTL (exp)); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); - /* For variable-sized types: retrieve pointer */ - if (TYPE_SIZE (TREE_TYPE (exp)) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST) - bc_emit_instruction (loadP); + /* Get the rtx comparison code to use. We know that EXP is a comparison + operation of some type. Some comparisons against 1 and -1 can be + converted to comparisons with zero. Do so here so that the tests + below will be aware that we have a comparison with zero. These + tests will not catch constants in the first operand, but constants + are rarely passed as the first operand. */ - /* If packed, also return offset and size */ - if (DECL_BIT_FIELD (exp)) - bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)), - TREE_INT_CST_LOW (DECL_SIZE (exp))); - + switch (TREE_CODE (exp)) + { + case EQ_EXPR: + code = EQ; break; - - case STRING_CST: - { - rtx r; - - bc_emit_bytecode (constP); - r = output_constant_def (exp); - bc_emit_code_labelref (BYTECODE_LABEL (r), BYTECODE_BC_LABEL (r)->offset); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - } + case NE_EXPR: + code = NE; break; - - default: - - abort(); + case LT_EXPR: + if (integer_onep (arg1)) + arg1 = integer_zero_node, code = unsignedp ? LEU : LE; + else + code = unsignedp ? LTU : LT; break; - } - - /* Most lvalues don't have components. */ - return (exp); -} - - -/* Emit a type code to be used by the runtime support in handling - parameter passing. The type code consists of the machine mode - plus the minimal alignment shifted left 8 bits. */ - -tree -bc_runtime_type_code (type) - tree type; -{ - int val; - - switch (TREE_CODE (type)) - { - case VOID_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case COMPLEX_TYPE: - case ENUMERAL_TYPE: - case POINTER_TYPE: - case RECORD_TYPE: - - val = (int) TYPE_MODE (type) | TYPE_ALIGN (type) << 8; + case LE_EXPR: + if (! unsignedp && integer_all_onesp (arg1)) + arg1 = integer_zero_node, code = LT; + else + code = unsignedp ? LEU : LE; break; - - case ERROR_MARK: - - val = 0; + case GT_EXPR: + if (! unsignedp && integer_all_onesp (arg1)) + arg1 = integer_zero_node, code = GE; + else + code = unsignedp ? GTU : GT; + break; + case GE_EXPR: + if (integer_onep (arg1)) + arg1 = integer_zero_node, code = unsignedp ? GTU : GT; + else + code = unsignedp ? GEU : GE; break; - default: - - abort (); - } - return build_int_2 (val, 0); -} - - -/* Generate constructor label */ - -char * -bc_gen_constr_label () -{ - static int label_counter; - static char label[20]; - - sprintf (label, "*LR%d", label_counter++); - - return (obstack_copy0 (&permanent_obstack, label, strlen (label))); -} - - -/* Evaluate constructor CONSTR and return pointer to it on level one. We - expand the constructor data as static data, and push a pointer to it. - The pointer is put in the pointer table and is retrieved by a constP - bytecode instruction. We then loop and store each constructor member in - the corresponding component. Finally, we return the original pointer on - the stack. */ - -void -bc_expand_constructor (constr) - tree constr; -{ - char *l; - HOST_WIDE_INT ptroffs; - rtx constr_rtx; - - - /* Literal constructors are handled as constants, whereas - non-literals are evaluated and stored element by element - into the data segment. */ - - /* Allocate space in proper segment and push pointer to space on stack. - */ - - l = bc_gen_constr_label (); - - if (TREE_CONSTANT (constr)) - { - text_section (); - - bc_emit_const_labeldef (l); - bc_output_constructor (constr, int_size_in_bytes (TREE_TYPE (constr))); + abort (); } - else - { - data_section (); - bc_emit_data_labeldef (l); - bc_output_data_constructor (constr); + /* Put a constant second. */ + if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST) + { + tem = arg0; arg0 = arg1; arg1 = tem; + code = swap_condition (code); } - - /* Add reference to pointer table and recall pointer to stack; - this code is common for both types of constructors: literals - and non-literals. */ - - ptroffs = bc_define_pointer (l); - bc_emit_instruction (constP, ptroffs); + /* If this is an equality or inequality test of a single bit, we can + do this by shifting the bit being tested to the low-order bit and + masking the result with the constant 1. If the condition was EQ, + we xor it with 1. This does not require an scc insn and is faster + than an scc insn even if we have it. */ - /* This is all that has to be done if it's a literal. */ - if (TREE_CONSTANT (constr)) - return; + if ((code == NE || code == EQ) + && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1) + && integer_pow2p (TREE_OPERAND (arg0, 1))) + { + tree inner = TREE_OPERAND (arg0, 0); + int bitnum = tree_log2 (TREE_OPERAND (arg0, 1)); + int ops_unsignedp; + /* If INNER is a right shift of a constant and it plus BITNUM does + not overflow, adjust BITNUM and INNER. */ - /* At this point, we have the pointer to the structure on top of the stack. - Generate sequences of store_memory calls for the constructor. */ - - /* constructor type is structure */ - if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE) - { - register tree elt; - - /* If the constructor has fewer fields than the structure, - clear the whole structure first. */ - - if (list_length (CONSTRUCTOR_ELTS (constr)) - != list_length (TYPE_FIELDS (TREE_TYPE (constr)))) + if (TREE_CODE (inner) == RSHIFT_EXPR + && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST + && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0 + && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)) + < TYPE_PRECISION (type))) { - bc_emit_instruction (duplicate); - bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr))); - bc_emit_instruction (clearBLK); + bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1)); + inner = TREE_OPERAND (inner, 0); } - - /* Store each element of the constructor into the corresponding - field of TARGET. */ - - for (elt = CONSTRUCTOR_ELTS (constr); elt; elt = TREE_CHAIN (elt)) - { - register tree field = TREE_PURPOSE (elt); - register enum machine_mode mode; - int bitsize; - int bitpos; - int unsignedp; - - bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) /* * DECL_SIZE_UNIT (field) */; - mode = DECL_MODE (field); - unsignedp = TREE_UNSIGNED (field); - bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)); - - bc_store_field (elt, bitsize, bitpos, mode, TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)), - /* The alignment of TARGET is - at least what its type requires. */ - VOIDmode, 0, - TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT, - int_size_in_bytes (TREE_TYPE (constr))); - } - } - else - - /* Constructor type is array */ - if (TREE_CODE (TREE_TYPE (constr)) == ARRAY_TYPE) - { - register tree elt; - register int i; - tree domain = TYPE_DOMAIN (TREE_TYPE (constr)); - int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain)); - int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain)); - tree elttype = TREE_TYPE (TREE_TYPE (constr)); - - /* If the constructor has fewer fields than the structure, - clear the whole structure first. */ - - if (list_length (CONSTRUCTOR_ELTS (constr)) < maxelt - minelt + 1) - { - bc_emit_instruction (duplicate); - bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr))); - bc_emit_instruction (clearBLK); - } - - - /* Store each element of the constructor into the corresponding - element of TARGET, determined by counting the elements. */ - - for (elt = CONSTRUCTOR_ELTS (constr), i = 0; - elt; - elt = TREE_CHAIN (elt), i++) - { - register enum machine_mode mode; - int bitsize; - int bitpos; - int unsignedp; - - mode = TYPE_MODE (elttype); - bitsize = GET_MODE_BITSIZE (mode); - unsignedp = TREE_UNSIGNED (elttype); - - bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)) - /* * TYPE_SIZE_UNIT (elttype) */ ); - - bc_store_field (elt, bitsize, bitpos, mode, - TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)), - /* The alignment of TARGET is - at least what its type requires. */ - VOIDmode, 0, - TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT, - int_size_in_bytes (TREE_TYPE (constr))); - } - - } -} + /* If we are going to be able to omit the AND below, we must do our + operations as unsigned. If we must use the AND, we have a choice. + Normally unsigned is faster, but for some machines signed is. */ + ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1 +#ifdef LOAD_EXTEND_OP + : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1) +#else + : 1 +#endif + ); + if (subtarget == 0 || GET_CODE (subtarget) != REG + || GET_MODE (subtarget) != operand_mode + || ! safe_from_p (subtarget, inner)) + subtarget = 0; -/* Store the value of EXP (an expression tree) into member FIELD of - structure at address on stack, which has type TYPE, mode MODE and - occupies BITSIZE bits, starting BITPOS bits from the beginning of the - structure. + op0 = expand_expr (inner, subtarget, VOIDmode, 0); - ALIGN is the alignment that TARGET is known to have, measured in bytes. - TOTAL_SIZE is its size in bytes, or -1 if variable. */ + if (bitnum != 0) + op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0, + size_int (bitnum), subtarget, ops_unsignedp); -void -bc_store_field (field, bitsize, bitpos, mode, exp, type, - value_mode, unsignedp, align, total_size) - int bitsize, bitpos; - enum machine_mode mode; - tree field, exp, type; - enum machine_mode value_mode; - int unsignedp; - int align; - int total_size; -{ + if (GET_MODE (op0) != mode) + op0 = convert_to_mode (mode, op0, ops_unsignedp); - /* Expand expression and copy pointer */ - bc_expand_expr (exp); - bc_emit_instruction (over); + if ((code == EQ && ! invert) || (code == NE && invert)) + op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget, + ops_unsignedp, OPTAB_LIB_WIDEN); + /* Put the AND last so it can combine with more things. */ + if (bitnum != TYPE_PRECISION (type) - 1) + op0 = expand_and (op0, const1_rtx, subtarget); - /* If the component is a bit field, we cannot use addressing to access - it. Use bit-field techniques to store in it. */ + return op0; + } - if (DECL_BIT_FIELD (field)) + /* Now see if we are likely to be able to do this. Return if not. */ + if (! can_compare_p (operand_mode)) + return 0; + icode = setcc_gen_code[(int) code]; + if (icode == CODE_FOR_nothing + || (only_cheap && insn_operand_mode[(int) icode][0] != mode)) { - bc_store_bit_field (bitpos, bitsize, unsignedp); - return; + /* We can only do this if it is one of the special cases that + can be handled without an scc insn. */ + if ((code == LT && integer_zerop (arg1)) + || (! only_cheap && code == GE && integer_zerop (arg1))) + ; + else if (BRANCH_COST >= 0 + && ! only_cheap && (code == NE || code == EQ) + && TREE_CODE (type) != REAL_TYPE + && ((abs_optab->handlers[(int) operand_mode].insn_code + != CODE_FOR_nothing) + || (ffs_optab->handlers[(int) operand_mode].insn_code + != CODE_FOR_nothing))) + ; + else + return 0; } - else - /* Not bit field */ - { - HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT; + + preexpand_calls (exp); + if (subtarget == 0 || GET_CODE (subtarget) != REG + || GET_MODE (subtarget) != operand_mode + || ! safe_from_p (subtarget, arg1)) + subtarget = 0; + + op0 = expand_expr (arg0, subtarget, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + + if (target == 0) + target = gen_reg_rtx (mode); + + /* Pass copies of OP0 and OP1 in case they contain a QUEUED. This is safe + because, if the emit_store_flag does anything it will succeed and + OP0 and OP1 will not be used subsequently. */ - /* Advance pointer to the desired member */ - if (offset) - bc_emit_instruction (addconstPSI, offset); + result = emit_store_flag (target, code, + queued_subexp_p (op0) ? copy_rtx (op0) : op0, + queued_subexp_p (op1) ? copy_rtx (op1) : op1, + operand_mode, unsignedp, 1); - /* Store */ - bc_store_memory (type, field); + if (result) + { + if (invert) + result = expand_binop (mode, xor_optab, result, const1_rtx, + result, 0, OPTAB_LIB_WIDEN); + return result; } -} + /* If this failed, we have to do this with set/compare/jump/set code. */ + if (GET_CODE (target) != REG + || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1)) + target = gen_reg_rtx (GET_MODE (target)); + + emit_move_insn (target, invert ? const0_rtx : const1_rtx); + result = compare_from_rtx (op0, op1, code, unsignedp, + operand_mode, NULL_RTX, 0); + if (GET_CODE (result) == CONST_INT) + return (((result == const0_rtx && ! invert) + || (result != const0_rtx && invert)) + ? const0_rtx : const1_rtx); -/* Store SI/SU in bitfield */ + label = gen_label_rtx (); + if (bcc_gen_fctn[(int) code] == 0) + abort (); -void -bc_store_bit_field (offset, size, unsignedp) - int offset, size, unsignedp; -{ - /* Push bitfield offset and size */ - bc_push_offset_and_size (offset, size); + emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label)); + emit_move_insn (target, invert ? const1_rtx : const0_rtx); + emit_label (label); - /* Store */ - bc_emit_instruction (sstoreBI); + return target; } + +/* Generate a tablejump instruction (used for switch statements). */ + +#ifdef HAVE_tablejump +/* INDEX is the value being switched on, with the lowest value + in the table already subtracted. + MODE is its expected mode (needed if INDEX is constant). + RANGE is the length of the jump table. + TABLE_LABEL is a CODE_LABEL rtx for the table itself. -/* Load SI/SU from bitfield */ + DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the + index value is out of range. */ void -bc_load_bit_field (offset, size, unsignedp) - int offset, size, unsignedp; +do_tablejump (index, mode, range, table_label, default_label) + rtx index, range, table_label, default_label; + enum machine_mode mode; { - /* Push bitfield offset and size */ - bc_push_offset_and_size (offset, size); + register rtx temp, vector; - /* Load: sign-extend if signed, else zero-extend */ - bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI); -} + /* Do an unsigned comparison (in the proper mode) between the index + expression and the value which represents the length of the range. + Since we just finished subtracting the lower bound of the range + from the index expression, this comparison allows us to simultaneously + check that the original index expression value is both greater than + or equal to the minimum value of the range and less than or equal to + the maximum value of the range. */ + emit_cmp_insn (index, range, GTU, NULL_RTX, mode, 1, 0); + emit_jump_insn (gen_bgtu (default_label)); -/* Adjust interpreter stack by NLEVELS. Positive means drop NLEVELS - (adjust stack pointer upwards), negative means add that number of - levels (adjust the stack pointer downwards). Only positive values - normally make sense. */ + /* If index is in range, it must fit in Pmode. + Convert to Pmode so we can index with it. */ + if (mode != Pmode) + index = convert_to_mode (Pmode, index, 1); -void -bc_adjust_stack (nlevels) - int nlevels; -{ - switch (nlevels) - { - case 0: - break; - - case 2: - bc_emit_instruction (drop); - - case 1: - bc_emit_instruction (drop); - break; - - default: - - bc_emit_instruction (adjstackSI, (HOST_WIDE_INT) nlevels); - stack_depth -= nlevels; - } + /* Don't let a MEM slip thru, because then INDEX that comes + out of PIC_CASE_VECTOR_ADDRESS won't be a valid address, + and break_out_memory_refs will go to work on it and mess it up. */ +#ifdef PIC_CASE_VECTOR_ADDRESS + if (flag_pic && GET_CODE (index) != REG) + index = copy_to_mode_reg (Pmode, index); +#endif -#if defined (VALIDATE_STACK_FOR_BC) - VALIDATE_STACK_FOR_BC (); + /* If flag_force_addr were to affect this address + it could interfere with the tricky assumptions made + about addresses that contain label-refs, + which may be valid only very near the tablejump itself. */ + /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the + GET_MODE_SIZE, because this indicates how large insns are. The other + uses should all be Pmode, because they are addresses. This code + could fail if addresses and insns are not the same size. */ + index = gen_rtx_PLUS (Pmode, + gen_rtx_MULT (Pmode, index, + GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))), + gen_rtx_LABEL_REF (Pmode, table_label)); +#ifdef PIC_CASE_VECTOR_ADDRESS + if (flag_pic) + index = PIC_CASE_VECTOR_ADDRESS (index); + else #endif + index = memory_address_noforce (CASE_VECTOR_MODE, index); + temp = gen_reg_rtx (CASE_VECTOR_MODE); + vector = gen_rtx_MEM (CASE_VECTOR_MODE, index); + RTX_UNCHANGING_P (vector) = 1; + convert_move (temp, vector, 0); + + emit_jump_insn (gen_tablejump (temp, table_label)); + + /* If we are generating PIC code or if the table is PC-relative, the + table and JUMP_INSN must be adjacent, so don't output a BARRIER. */ + if (! CASE_VECTOR_PC_RELATIVE && ! flag_pic) + emit_barrier (); } + +#endif /* HAVE_tablejump */ diff --git a/gcc/expr.h b/gcc/expr.h index 62909c3c946..e818d5ab398 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -936,19 +936,7 @@ extern rtx (*lang_expand_expr) PROTO ((union tree_node *, rtx, enum machine_mode, enum expand_modifier modifier)); -#ifdef TREE_CODE -/* Build bytecode call descriptor for function SUBR. */ -extern rtx bc_build_calldesc PROTO((tree)); - -/* Emit a type code to be used by the runtime support in handling - parameter passing. The type code consists of the machine mode - plus the minimal alignment shifted left 8 bits. */ -extern tree bc_runtime_type_code PROTO((tree)); -#endif - extern void init_all_optabs PROTO ((void)); extern void init_mov_optab PROTO ((void)); -extern void bc_adjust_stack PROTO ((int)); -extern void bc_load_localaddr PROTO ((rtx)); extern void do_jump_by_parts_greater_rtx PROTO ((enum machine_mode, int, rtx, rtx, rtx, rtx)); diff --git a/gcc/function.c b/gcc/function.c index e77e0ba44e1..8a4d7d116bf 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -55,8 +55,6 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "basic-block.h" #include "obstack.h" -#include "bytecode.h" -#include "bc-emit.h" #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY @@ -388,19 +386,12 @@ static tree this_function_decl; /* Callinfo pointer for the current function. */ static rtx this_function_callinfo; -/* The label in the bytecode file of this function's actual bytecode. - Not an rtx. */ -static char *this_function_bytecode; - /* The call description vector for the current function. */ static rtx this_function_calldesc; /* Size of the local variables allocated for the current function. */ int local_vars_size; -/* Current depth of the bytecode evaluation stack. */ -int stack_depth; - /* Maximum depth of the evaluation stack in this function. */ int max_stack_depth; @@ -1312,9 +1303,6 @@ put_var_into_stack (decl) tree context; int can_use_addressof; - if (output_bytecode) - return; - context = decl_function_context (decl); /* Get the current rtl used for this object and it's original mode. */ @@ -5153,50 +5141,6 @@ all_blocks (block, vector) return n_blocks; } -/* Build bytecode call descriptor for function SUBR. */ - -rtx -bc_build_calldesc (subr) - tree subr; -{ - tree calldesc = 0, arg; - int nargs = 0; - - /* Build the argument description vector in reverse order. */ - DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr)); - nargs = 0; - - for (arg = DECL_ARGUMENTS (subr); arg; arg = TREE_CHAIN (arg)) - { - ++nargs; - - calldesc = tree_cons ((tree) 0, size_in_bytes (TREE_TYPE (arg)), calldesc); - calldesc = tree_cons ((tree) 0, bc_runtime_type_code (TREE_TYPE (arg)), calldesc); - } - - DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr)); - - /* Prepend the function's return type. */ - calldesc = tree_cons ((tree) 0, - size_in_bytes (TREE_TYPE (TREE_TYPE (subr))), - calldesc); - - calldesc = tree_cons ((tree) 0, - bc_runtime_type_code (TREE_TYPE (TREE_TYPE (subr))), - calldesc); - - /* Prepend the arg count. */ - calldesc = tree_cons ((tree) 0, build_int_2 (nargs, 0), calldesc); - - /* Output the call description vector and get its address. */ - calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc); - TREE_TYPE (calldesc) = build_array_type (integer_type_node, - build_index_type (build_int_2 (nargs * 2, 0))); - - return output_constant_def (calldesc); -} - - /* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node) and initialize static variables for generating RTL for the statements of the function. */ @@ -5207,17 +5151,6 @@ init_function_start (subr, filename, line) char *filename; int line; { - if (output_bytecode) - { - this_function_decl = subr; - this_function_calldesc = bc_build_calldesc (subr); - local_vars_size = 0; - stack_depth = 0; - max_stack_depth = 0; - stmt_expr_depth = 0; - return; - } - init_stmt_for_function (); cse_not_expected = ! optimize; @@ -5371,99 +5304,14 @@ mark_varargs () void expand_main_function () { - if (!output_bytecode) - { - /* The zero below avoids a possible parse error */ - 0; #if !defined (HAS_INIT_SECTION) - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0, - VOIDmode, 0); + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0, + VOIDmode, 0); #endif /* not HAS_INIT_SECTION */ - } } extern struct obstack permanent_obstack; -/* Expand start of bytecode function. See comment at - expand_function_start below for details. */ - -void -bc_expand_function_start (subr, parms_have_cleanups) - tree subr; - int parms_have_cleanups; -{ - char label[20], *name; - static int nlab; - tree thisarg; - int argsz; - - if (TREE_PUBLIC (subr)) - bc_globalize_label (IDENTIFIER_POINTER (DECL_NAME (subr))); - -#ifdef DEBUG_PRINT_CODE - fprintf (stderr, "\n\n", IDENTIFIER_POINTER (DECL_NAME (subr))); -#endif - - for (argsz = 0, thisarg = DECL_ARGUMENTS (subr); thisarg; thisarg = TREE_CHAIN (thisarg)) - { - if (DECL_RTL (thisarg)) - abort (); /* Should be NULL here I think. */ - else if (TREE_CONSTANT (DECL_SIZE (thisarg))) - { - DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0); - argsz += TREE_INT_CST_LOW (DECL_SIZE (thisarg)); - } - else - { - /* Variable-sized objects are pointers to their storage. */ - DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0); - argsz += POINTER_SIZE; - } - } - - bc_begin_function (xstrdup (IDENTIFIER_POINTER (DECL_NAME (subr)))); - - ASM_GENERATE_INTERNAL_LABEL (label, "LX", nlab); - - ++nlab; - name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); - this_function_callinfo = bc_gen_rtx (name, 0, (struct bc_label *) 0); - this_function_bytecode - = bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo)); -} - - -/* Expand end of bytecode function. See details the comment of - expand_function_end(), below. */ - -void -bc_expand_function_end () -{ - char *ptrconsts; - - expand_null_return (); - - /* Emit any fixup code. This must be done before the call to - to BC_END_FUNCTION (), since that will cause the bytecode - segment to be finished off and closed. */ - - expand_fixups (NULL_RTX); - - ptrconsts = bc_end_function (); - - bc_align_const (2 /* INT_ALIGN */); - - /* If this changes also make sure to change bc-interp.h! */ - - bc_emit_const_labeldef (BYTECODE_LABEL (this_function_callinfo)); - bc_emit_const ((char *) &max_stack_depth, sizeof max_stack_depth); - bc_emit_const ((char *) &local_vars_size, sizeof local_vars_size); - bc_emit_const_labelref (this_function_bytecode, 0); - bc_emit_const_labelref (ptrconsts, 0); - bc_emit_const_labelref (BYTECODE_LABEL (this_function_calldesc), 0); -} - - /* Start the RTL for a new function, and set variables used for emitting RTL. SUBR is the FUNCTION_DECL node. @@ -5479,12 +5327,6 @@ expand_function_start (subr, parms_have_cleanups) tree tem; rtx last_ptr; - if (output_bytecode) - { - bc_expand_function_start (subr, parms_have_cleanups); - return; - } - /* Make sure volatile mem refs aren't considered valid operands of arithmetic insns. */ init_recog_no_volatile (); @@ -5719,12 +5561,6 @@ expand_function_end (filename, line, end_bindings) static rtx initial_trampoline; #endif - if (output_bytecode) - { - bc_expand_function_end (); - return; - } - #ifdef NON_SAVING_SETJMP /* Don't put any variables in registers if we call setjmp on a machine that fails to restore the registers. */ diff --git a/gcc/integrate.c b/gcc/integrate.c index 256a665f07b..28731c0060d 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -35,7 +35,6 @@ Boston, MA 02111-1307, USA. */ #include "real.h" #include "except.h" #include "function.h" -#include "bytecode.h" #include "obstack.h" #define obstack_chunk_alloc xmalloc @@ -3273,12 +3272,6 @@ output_inline_function (fndecl) rtx head; rtx last; - if (output_bytecode) - { - warning ("`inline' ignored for bytecode output"); - return; - } - /* Things we allocate from here on are part of this function, not permanent. */ temporary_allocation (); diff --git a/gcc/output.h b/gcc/output.h index a7c9b1e7876..de06f45b956 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -56,20 +56,20 @@ extern void shorten_branches PROTO((rtx)); for the new function. The label for the function and associated assembler pseudo-ops have already been output in `assemble_start_function'. */ -extern void final_start_function STDIO_PROTO((rtx, FILE *, int)); +extern void final_start_function PROTO((rtx, FILE *, int)); /* Output assembler code for the end of a function. For clarity, args are same as those of `final_start_function' even though not all of them are needed. */ -extern void final_end_function STDIO_PROTO((rtx, FILE *, int)); +extern void final_end_function PROTO((rtx, FILE *, int)); /* Output assembler code for some insns: all or part of a function. */ -extern void final STDIO_PROTO((rtx, FILE *, int, int)); +extern void final PROTO((rtx, FILE *, int, int)); /* The final scan for one insn, INSN. Args are same as in `final', except that INSN is the insn being scanned. Value returned is the next insn to be scanned. */ -extern rtx final_scan_insn STDIO_PROTO((rtx, FILE *, int, int, int)); +extern rtx final_scan_insn PROTO((rtx, FILE *, int, int, int)); /* Replace a SUBREG with a REG or a MEM, based on the thing it is a subreg of. */ @@ -93,12 +93,11 @@ extern void output_address PROTO((rtx)); /* Print an integer constant expression in assembler syntax. Addition and subtraction are the only arithmetic that may appear in these expressions. */ -extern void output_addr_const STDIO_PROTO((FILE *, rtx)); +extern void output_addr_const PROTO((FILE *, rtx)); /* Output a string of assembler code, substituting numbers, strings and fixed syntactic prefixes. */ -extern void asm_fprintf STDIO_PROTO(PVPROTO((FILE *file, - char *p, ...))); +extern void asm_fprintf PROTO(PVPROTO((FILE *file, char *p, ...))); /* Split up a CONST_DOUBLE or integer constant rtx into two rtx's for single words. */ @@ -119,8 +118,8 @@ extern void leaf_renumber_regs_insn PROTO((rtx)); extern void allocate_for_life_analysis PROTO((void)); extern int regno_uninitialized PROTO((int)); extern int regno_clobbered_at_setjmp PROTO((int)); -extern void dump_flow_info STDIO_PROTO((FILE *)); -extern void flow_analysis STDIO_PROTO((rtx, int, FILE *)); +extern void dump_flow_info PROTO((FILE *)); +extern void flow_analysis PROTO((rtx, int, FILE *)); #endif /* Functions in varasm.c. */ @@ -229,12 +228,6 @@ extern void assemble_string PROTO((char *, int)); initial value (that will be done by the caller). */ extern void assemble_variable PROTO((tree, int, int, int)); -/* Output text storage for constructor CONSTR. */ -extern void bc_output_constructor PROTO((tree, int)); - -/* Create storage for constructor CONSTR. */ -extern void bc_output_data_constructor PROTO((tree)); - /* 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. */ @@ -257,7 +250,7 @@ extern void assemble_label PROTO((char *)); Otherwise NAME is transformed in an implementation-defined way (usually by the addition of an underscore). Many macros in the tm file are defined to call this function. */ -extern void assemble_name STDIO_PROTO((FILE *, char *)); +extern void assemble_name PROTO((FILE *, char *)); #ifdef RTX_CODE /* Assemble the integer constant X into an object of SIZE bytes. diff --git a/gcc/regclass.c b/gcc/regclass.c index b2d2c03add6..969d89e7d19 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -34,7 +34,6 @@ Boston, MA 02111-1307, USA. */ #include "recog.h" #include "reload.h" #include "real.h" -#include "bytecode.h" #ifndef REGISTER_MOVE_COST #define REGISTER_MOVE_COST(x, y) 2 @@ -424,8 +423,7 @@ init_regs () { /* This finishes what was started by init_reg_sets, but couldn't be done until after register usage was specified. */ - if (!output_bytecode) - init_reg_sets_1 (); + init_reg_sets_1 (); init_reg_modes (); } @@ -483,13 +481,6 @@ fix_register (name, fixed, call_used) { int i; - if (output_bytecode) - { - warning ("request to mark `%s' as %s ignored by bytecode compiler", - name, call_used ? "call-used" : "fixed"); - return; - } - /* Decode the name and update the primary form of the register info. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index 834ce8cdfb2..0f9d272d89c 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -439,17 +439,6 @@ extern char *note_insn_name[]; of LABEL_REFs that point at it, so unused labels can be deleted. */ #define LABEL_NUSES(LABEL) ((LABEL)->fld[5].rtint) -/* The rest is used instead of the above, in a CODE_LABEL, - if bytecode is being output. - We make the slightly kludgy assumption that a LABEL has enough slots - to hold these things. That happens to be true. */ - -/* For static or external objects. */ -#define BYTECODE_LABEL(X) (XSTR ((X), 0)) - -/* For goto labels inside bytecode functions. */ -#define BYTECODE_BC_LABEL(X) (*(struct bc_label **) &XEXP ((X), 1)) - /* The original regno this ADDRESSOF was built for. */ #define ADDRESSOF_REGNO(RTX) ((RTX)->fld[1].rtint) @@ -681,10 +670,6 @@ extern int ceil_log2 PROTO((unsigned HOST_WIDE_INT)); extern rtx plus_constant_wide PROTO((rtx, HOST_WIDE_INT)); extern rtx plus_constant_for_output_wide PROTO((rtx, HOST_WIDE_INT)); -struct bc_label; -extern rtx bc_gen_rtx PROTO ((char *, int, - struct bc_label *)); - extern rtx gen_rtx PVPROTO((enum rtx_code, enum machine_mode, ...)); extern rtvec gen_rtvec PVPROTO((int, ...)); @@ -1254,7 +1239,6 @@ extern void emit_jump PROTO ((rtx)); extern int preserve_subexpressions_p PROTO ((void)); /* In expr.c */ -extern rtx bc_allocate_local PROTO ((int, int)); extern void init_expr_once PROTO ((void)); /* In stupid.c */ diff --git a/gcc/stmt.c b/gcc/stmt.c index 48929aa559f..abda4bf900e 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -53,12 +53,6 @@ Boston, MA 02111-1307, USA. */ #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 struct obstack stmt_obstack; @@ -247,8 +241,7 @@ 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. Complemented by - bc_stack_level (see below) when generating bytecodes. */ + /* Nonzero => value to restore stack to on exit. */ rtx stack_level; /* The NOTE that starts this contour. Used by expand_goto to check whether the destination @@ -276,7 +269,6 @@ struct nesting /* 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; /* Nonzero if this is associated with a EH region. */ int exception_region; /* The saved target_temp_slot_level from our outer block. @@ -307,10 +299,6 @@ 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; it is first built as an AVL tree. During expand_end_case, this is converted to a list, and may be rearranged into a nearly balanced binary tree. */ @@ -422,21 +410,6 @@ 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; @@ -457,32 +430,13 @@ static int using_eh_for_cleanups_p = 0; static void expand_goto_internal PROTO((tree, rtx, rtx)); -static void bc_expand_goto_internal PROTO((enum bytecode_opcode, - struct bc_label *, tree)); static int expand_fixup PROTO((tree, rtx, rtx)); -static void bc_expand_fixup PROTO((enum bytecode_opcode, - struct bc_label *, int)); static void fixup_gotos PROTO((struct nesting *, rtx, tree, rtx, int)); -static void bc_fixup_gotos PROTO((struct nesting *, int, tree, - rtx, int)); -static void bc_expand_start_cond PROTO((tree, int)); -static void bc_expand_end_cond PROTO((void)); -static void bc_expand_start_else PROTO((void)); -static void bc_expand_end_loop PROTO((void)); -static void bc_expand_end_bindings PROTO((tree, int, int)); -static void bc_expand_decl PROTO((tree, tree)); -static void bc_expand_variable_local_init PROTO((tree)); -static void bc_expand_decl_init PROTO((tree)); static void expand_null_return_1 PROTO((rtx, int)); static void expand_value_return PROTO((rtx)); static int tail_recursion_args PROTO((tree, tree)); static void expand_cleanups PROTO((tree, tree, int, int)); -static void bc_expand_start_case PROTO((struct nesting *, tree, - tree, char *)); -static int bc_pushcase PROTO((tree, tree)); -static void bc_check_for_full_enumeration_handling PROTO((tree)); -static void bc_expand_end_case PROTO((tree)); static void do_jump_if_equal PROTO((rtx, rtx, rtx, int)); static int estimate_case_costs PROTO((case_node_ptr)); static void group_case_nodes PROTO((case_node_ptr)); @@ -496,8 +450,6 @@ static void emit_case_nodes PROTO((rtx, case_node_ptr, rtx, tree)); static int add_case_node PROTO((tree, tree, tree, tree *)); static struct case_node *case_tree2list PROTO((case_node *, case_node *)); -extern rtx bc_allocate_local (); -extern rtx bc_allocate_variable_array (); void using_eh_for_cleanups () @@ -585,15 +537,12 @@ emit_nop () { rtx last_insn; - if (!output_bytecode) - { - last_insn = get_last_insn (); - if (!optimize - && (GET_CODE (last_insn) == CODE_LABEL - || (GET_CODE (last_insn) == NOTE - && prev_real_insn (last_insn) == 0))) - emit_insn (gen_nop ()); - } + last_insn = get_last_insn (); + if (!optimize + && (GET_CODE (last_insn) == CODE_LABEL + || (GET_CODE (last_insn) == NOTE + && prev_real_insn (last_insn) == 0))) + emit_insn (gen_nop ()); } /* Return the rtx-label that corresponds to a LABEL_DECL, @@ -630,28 +579,20 @@ void expand_computed_goto (exp) tree exp; { - if (output_bytecode) - { - bc_expand_expr (exp); - bc_emit_instruction (jumpP); - } - else - { - rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0); + rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0); #ifdef POINTERS_EXTEND_UNSIGNED - x = convert_memory_address (Pmode, x); + x = convert_memory_address (Pmode, x); #endif - emit_queue (); - /* Be sure the function is executable. */ - if (flag_check_memory_usage) - emit_library_call (chkr_check_exec_libfunc, 1, - VOIDmode, 1, x, ptr_mode); + emit_queue (); + /* Be sure the function is executable. */ + if (flag_check_memory_usage) + emit_library_call (chkr_check_exec_libfunc, 1, + VOIDmode, 1, x, ptr_mode); - do_pending_stack_adjust (); - emit_indirect_jump (x); - } + do_pending_stack_adjust (); + emit_indirect_jump (x); } /* Handle goto statements and the labels that they can go to. */ @@ -673,15 +614,6 @@ 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 (BYTECODE_BC_LABEL (DECL_RTL (label)))) - error ("multiply defined label"); - return; - } - do_pending_stack_adjust (); emit_label (label_rtx (label)); if (DECL_NAME (label)) @@ -725,12 +657,6 @@ expand_goto (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. */ context = decl_function_context (label); if (context != 0 && context != current_function_decl) @@ -813,16 +739,6 @@ 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 (); @@ -876,78 +792,6 @@ 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 (BYTECODE_BC_LABEL (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, 1, 1); - 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. @@ -1076,34 +920,6 @@ expand_fixup (tree_label, rtl_label, last_insn) } -/* 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 -} /* Expand any needed fixups in the outputmost binding level of the function. FIRST_INSN is the first insn in the function. */ @@ -1138,15 +954,6 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) { register struct goto_fixup *f, *prev; - if (output_bytecode) - { - /* ??? The second arg is the bc stack level, which is not the same - as STACK_LEVEL. I have no idea what should go here, so I'll - just pass 0. */ - bc_fixup_gotos (thisblock, 0, 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 @@ -1295,70 +1102,6 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) } -/* 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, @@ -1368,12 +1111,6 @@ void expand_asm (body) tree body; { - if (output_bytecode) - { - error ("`asm' is invalid when generating bytecode"); - return; - } - if (flag_check_memory_usage) { error ("`asm' cannot be used with `-fcheck-memory-usage'"); @@ -1430,12 +1167,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) if (noutputs == 0) vol = 1; - if (output_bytecode) - { - error ("`asm' is invalid when generating bytecode"); - return; - } - if (flag_check_memory_usage) { error ("`asm' cannot be used with `-fcheck-memory-usage'"); @@ -1789,22 +1520,6 @@ 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. */ @@ -1982,10 +1697,6 @@ 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. */ momentary = suspend_momentary (); @@ -2014,38 +1725,6 @@ 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) @@ -2109,10 +1788,7 @@ expand_start_cond (cond, exitflag) cond_stack = thiscond; nesting_stack = thiscond; - if (output_bytecode) - bc_expand_start_cond (cond, exitflag); - else - do_jump (cond, thiscond->data.cond.next_label, NULL_RTX); + do_jump (cond, thiscond->data.cond.next_label, NULL_RTX); } /* Generate RTL between then-clause and the elseif-clause @@ -2139,12 +1815,6 @@ 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. */ @@ -2169,76 +1839,17 @@ expand_end_cond () { struct nesting *thiscond = cond_stack; - 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); - } + 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. */ - -static void -bc_expand_start_cond (cond, exitflag) - tree cond; - int exitflag; -{ - struct nesting *thiscond = cond_stack; - - thiscond->data.case_stmt.nominal_type = cond; - if (! exitflag) - thiscond->exit_label = gen_label_rtx (); - bc_expand_expr (cond); - bc_emit_bytecode (xjumpifnot); - bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label)); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif -} - -/* Generate the label for the end of an if with - no else- clause. */ - -static void -bc_expand_end_cond () -{ - struct nesting *thiscond = cond_stack; - - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->exit_label)); -} - -/* Generate code for the start of the else- clause of - an if-then-else. */ - -static 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 (BYTECODE_BC_LABEL (thiscond->exit_label)); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->data.cond.endif_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 @@ -2266,12 +1877,6 @@ expand_start_loop (exit_flag) loop_stack = thisloop; nesting_stack = thisloop; - if (output_bytecode) - { - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->data.loop.start_label)); - return thisloop; - } - do_pending_stack_adjust (); emit_queue (); emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG); @@ -2300,36 +1905,11 @@ expand_start_loop_continue_elsewhere (exit_flag) void expand_loop_continue_here () { - if (output_bytecode) - { - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (loop_stack->data.loop.continue_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 (BYTECODE_BC_LABEL (thisloop->data.loop.start_label)); - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->exit_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. */ @@ -2341,12 +1921,6 @@ expand_end_loop () 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; @@ -2497,35 +2071,26 @@ expand_exit_loop_if_false (whichloop, cond) struct nesting *whichloop; tree cond; { + rtx label = gen_label_rtx (); + rtx last_insn; last_expr_type = 0; + if (whichloop == 0) whichloop = loop_stack; if (whichloop == 0) return 0; - if (output_bytecode) - { - bc_expand_expr (cond); - bc_expand_goto_internal (xjumpifnot, - BYTECODE_BC_LABEL (whichloop->exit_label), - NULL_TREE); - } - else - { - /* In order to handle fixups, we actually create a conditional jump - around a unconditional branch to exit the loop. If fixups are - necessary, they go before the unconditional branch. */ + /* In order to handle fixups, we actually create a conditional jump + around a unconditional branch to exit the loop. If fixups are + necessary, they go before the unconditional branch. */ - rtx label = gen_label_rtx (); - rtx last_insn; - - do_jump (cond, NULL_RTX, label); - last_insn = get_last_insn (); - if (GET_CODE (last_insn) == CODE_LABEL) - whichloop->data.loop.alt_end_label = last_insn; - expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, - NULL_RTX); - emit_label (label); - } + + do_jump (cond, NULL_RTX, label); + last_insn = get_last_insn (); + if (GET_CODE (last_insn) == CODE_LABEL) + whichloop->data.loop.alt_end_label = last_insn; + expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, + NULL_RTX); + emit_label (label); return 1; } @@ -2589,12 +2154,6 @@ 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) @@ -2726,15 +2285,6 @@ 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) { @@ -3110,7 +2660,7 @@ expand_start_bindings (exit_flag) int exit_flag; { struct nesting *thisblock = ALLOC_NESTING (); - rtx note = output_bytecode ? 0 : emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG); + rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG); /* Make an entry on block_stack for the block we are entering. */ @@ -3143,11 +2693,8 @@ expand_start_bindings (exit_flag) block_stack = thisblock; nesting_stack = thisblock; - if (!output_bytecode) - { - /* Make a new level for allocating stack slots. */ - push_temp_slots (); - } + /* Make a new level for allocating stack slots. */ + push_temp_slots (); } /* Specify the scope of temporaries created by TARGET_EXPRs. Similar @@ -3278,12 +2825,6 @@ expand_end_bindings (vars, mark_ends, dont_jump_in) expand_end_bindings (NULL_TREE, 0, 0); } - if (output_bytecode) - { - bc_expand_end_bindings (vars, mark_ends, dont_jump_in); - return; - } - /* Since expand_eh_region_start does an expand_start_bindings, we have to first end all the bindings that were created by expand_eh_region_start. */ @@ -3529,33 +3070,6 @@ expand_end_bindings (vars, mark_ends, dont_jump_in) } -/* 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. */ - -static 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'"); - - if (thisbind->exit_label) - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisbind->exit_label)); - - /* Pop block/bindings off stack */ - POPSTACK (block_stack); -} /* Generate RTL for the automatic variable declaration DECL. (Other kinds of declarations are simply ignored if seen here.) */ @@ -3567,12 +3081,6 @@ expand_decl (decl) struct nesting *thisblock = block_stack; tree type; - if (output_bytecode) - { - bc_expand_decl (decl, 0); - return; - } - type = TREE_TYPE (decl); /* Only automatic variables need any expansion done. @@ -3742,50 +3250,6 @@ expand_decl (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. */ - -static 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. */ @@ -3795,12 +3259,6 @@ expand_decl_init (decl) { int was_used = TREE_USED (decl); - if (output_bytecode) - { - bc_expand_decl_init (decl); - return; - } - /* If this is a CONST_DECL, we don't have to generate any code, but if DECL_INITIAL is a constant, call expand_expr to force TREE_CST_RTL to be set while in the obstack containing the constant. If we don't @@ -3844,83 +3302,6 @@ 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. */ - -static void -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. */ - -static 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, 0, 0); - } - else if (DECL_INITIAL (decl)) - expand_assignment (TREE_TYPE (decl), decl, 0, 0); - - /* 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. @@ -4383,12 +3764,6 @@ 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 @@ -4402,32 +3777,6 @@ expand_start_case (exit_flag, expr, type, printname) } -/* Enter a case statement. It is assumed that the caller has pushed - the current context onto the case stack. */ - -static 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 (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_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 @@ -4501,9 +3850,6 @@ 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; @@ -4886,60 +4232,6 @@ add_case_node (low, high, 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. */ - -static 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; -} /* Returns the number of possible values of TYPE. Returns -1 if the number is unknown or variable. @@ -5190,12 +4482,6 @@ check_for_full_enumeration_handling (type) long bytes_needed; tree t; - if (output_bytecode) - { - bc_check_for_full_enumeration_handling (type); - return; - } - if (! warn_switch) return; @@ -5303,46 +4589,6 @@ 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. */ - -static 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. @@ -5366,12 +4612,6 @@ expand_end_case (orig_index) tree index_expr, index_type; 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; index_type = TREE_TYPE (index_expr); @@ -5764,110 +5004,6 @@ case_tree2list (node, right) return node; } -/* Terminate a case statement. EXPR is the original index - expression. */ - -static 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 (BYTECODE_BC_LABEL (thiscase->exit_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 (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_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 (BYTECODE_BC_LABEL (DECL_RTL (thiscase->data.case_stmt.default_label))); - else - bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->exit_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 (BYTECODE_BC_LABEL (DECL_RTL (c->code_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 (BYTECODE_BC_LABEL (DECL_RTL (c->code_label))); - } - else - /* Bad mode */ - abort (); - - - bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->exit_label)); - - /* Possibly issue enumeration warnings. */ - - if (!thiscase->data.case_stmt.default_label - && TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE - && TREE_CODE (expr) != INTEGER_CST - && warn_switch) - check_for_full_enumeration_handling (TREE_TYPE (expr)); - - -#ifdef DEBUG_PRINT_CODE - fputc ('\n', stderr); -#endif - - POPSTACK (case_stack); -} - - -/* Return unique bytecode ID. */ - -int -bc_new_uid () -{ - static int bc_uid = 0; - - return (++bc_uid); -} - /* Generate code to jump to LABEL if OP1 and OP2 are equal. */ static void diff --git a/gcc/toplev.c b/gcc/toplev.c index 2932f395cdf..83873006689 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -72,8 +72,6 @@ Boston, MA 02111-1307, USA. */ #include "insn-attr.h" #include "defaults.h" #include "output.h" -#include "bytecode.h" -#include "bc-emit.h" #include "except.h" #ifdef XCOFF_DEBUGGING_INFO @@ -306,9 +304,6 @@ 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. DECL is the declaration in question. VERBOSITY determines what information will be printed: @@ -751,7 +746,6 @@ struct { char *string; int *variable; int on_value;} f_options[] = {"regmove", &flag_regmove, 1}, {"pack-struct", &flag_pack_struct, 1}, {"stack-check", &flag_stack_check, 1}, - {"bytecode", &output_bytecode, 1}, {"argument-alias", &flag_argument_noalias, 0}, {"argument-noalias", &flag_argument_noalias, 1}, {"argument-noalias-global", &flag_argument_noalias, 2}, @@ -1111,11 +1105,8 @@ fatal_insn (message, insn) char *message; rtx insn; { - if (!output_bytecode) - { - error (message); - debug_rtx (insn); - } + error (message); + debug_rtx (insn); if (asm_out_file) fflush (asm_out_file); if (aux_info_file) @@ -2262,8 +2253,6 @@ compile_file (name) #else init_lex (); #endif - /* 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 @@ -2431,36 +2420,27 @@ compile_file (name) if (main_input_filename == 0) main_input_filename = name; - if (!output_bytecode) - { - ASM_FILE_START (asm_out_file); + ASM_FILE_START (asm_out_file); #ifdef ASM_COMMENT_START - if (flag_verbose_asm) - { - /* Print the list of options in effect. */ - print_version (asm_out_file, ASM_COMMENT_START); - print_switch_values (asm_out_file, 0, MAX_LINE, + if (flag_verbose_asm) + { + /* Print the list of options in effect. */ + print_version (asm_out_file, ASM_COMMENT_START); + print_switch_values (asm_out_file, 0, MAX_LINE, ASM_COMMENT_START, " ", "\n"); - /* Add a blank line here so it appears in assembler output but not - screen output. */ - fprintf (asm_out_file, "\n"); - } -#endif + /* Add a blank line here so it appears in assembler output but not + screen output. */ + fprintf (asm_out_file, "\n"); } +#endif - /* 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 - { + /* Output something to inform GDB that this compilation was by GCC. */ #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 @@ -2485,28 +2465,20 @@ compile_file (name) if (flag_function_sections && write_symbols != NO_DEBUG) warning ("-ffunction-sections may affect debugging on some targets."); - 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. */ + /* ??? 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); - } + /* 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. */ @@ -2535,8 +2507,7 @@ compile_file (name) /* Initialize yet another pass. */ - if (!output_bytecode) - init_final (main_input_filename); + init_final (main_input_filename); init_branch_prob (dump_base_name); start_time = get_run_time (); @@ -2792,23 +2763,17 @@ compile_file (name) /* Output some stuff at end of file if nec. */ - if (!output_bytecode) - { - end_final (dump_base_name); - end_branch_prob (branch_prob_dump_file); + end_final (dump_base_name); + end_branch_prob (branch_prob_dump_file); #ifdef ASM_FILE_END - ASM_FILE_END (asm_out_file); + ASM_FILE_END (asm_out_file); #endif - } /* Language-specific end of compilation actions. */ lang_finish (); - if (output_bytecode) - bc_write_file (asm_out_file); - /* Close the dump files. */ if (flag_gen_aux_info) @@ -2893,29 +2858,26 @@ compile_file (name) fprintf (stderr,"\n"); print_time ("parse", parse_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 ("branch-prob", branch_prob_time); - print_time ("flow", flow_time); - print_time ("combine", combine_time); - print_time ("regmove", regmove_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); - } + 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 ("branch-prob", branch_prob_time); + print_time ("flow", flow_time); + print_time ("combine", combine_time); + print_time ("regmove", regmove_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); } } @@ -2966,8 +2928,7 @@ rest_of_decl_compilation (decl, asmspec, top_level, at_end) && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))) assemble_variable (decl, top_level, at_end, 0); - if (!output_bytecode - && decl == last_assemble_variable_decl) + if (decl == last_assemble_variable_decl) { ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl, top_level, at_end); @@ -3033,9 +2994,6 @@ 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. */ @@ -4392,18 +4350,6 @@ main (argc, argv, envp) if (flag_check_memory_usage) flag_omit_frame_pointer = 0; - /* 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 not supported for this target"); -#else - bc_initialize (); -#endif - } - if (optimize == 0) { /* Inlining does not work if not optimizing, diff --git a/gcc/tree.h b/gcc/tree.h index e951a427635..6a5f5e2078f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1964,8 +1964,6 @@ extern tree reorder_blocks PROTO ((tree *, tree, extern void free_temps_for_rtl_expr PROTO ((tree)); extern void instantiate_virtual_regs PROTO ((tree, struct rtx_def *)); extern int max_parm_reg_num PROTO ((void)); -extern void bc_expand_function_start PROTO ((tree, int)); -extern void bc_expand_function_end PROTO ((void)); extern void push_function_context PROTO ((void)); extern void pop_function_context PROTO ((void)); extern void push_function_context_to PROTO ((tree)); @@ -1987,8 +1985,6 @@ extern void indent_to PROTO ((FILE *, int)); /* In expr.c */ extern void emit_queue PROTO ((void)); extern int apply_args_register_offset PROTO ((int)); -extern char * bc_gen_constr_label PROTO ((void)); -extern struct rtx_def *bc_allocate_variable_array PROTO ((tree)); extern struct rtx_def *expand_builtin_return_addr PROTO ((enum built_in_function, int, struct rtx_def *)); extern void do_pending_stack_adjust PROTO ((void)); diff --git a/gcc/varasm.c b/gcc/varasm.c index 5e0e3e4092c..d7f0605c146 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -41,7 +41,6 @@ Boston, MA 02111-1307, USA. */ #include "regs.h" #include "defaults.h" #include "real.h" -#include "bytecode.h" #include "obstack.h" #include "c-pragma.h" @@ -138,9 +137,7 @@ struct constant_descriptor; struct rtx_const; struct pool_constant; -static void bc_make_decl_rtl PROTO((tree, char *, int)); static char *strip_reg_name PROTO((char *)); -static void bc_output_ascii PROTO((FILE *, char *, int)); static int contains_pointers_p PROTO((tree)); static void decode_addr_const PROTO((tree, struct addr_const *)); static int const_hash PROTO((tree)); @@ -163,7 +160,6 @@ static void mark_constant_pool PROTO((void)); static void mark_constants PROTO((rtx)); static int output_addressed_constants PROTO((tree)); static void output_after_function_constants PROTO((void)); -static void bc_assemble_integer PROTO((tree, int)); static void output_constructor PROTO((tree, int)); static enum in_section { no_section, in_text, in_data, in_named @@ -198,11 +194,7 @@ text_section () { if (in_section != in_text) { - if (output_bytecode) - bc_text (); - else - fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); - + fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); in_section = in_text; } } @@ -214,21 +206,16 @@ data_section () { if (in_section != in_data) { - if (output_bytecode) - bc_data (); - else + if (flag_shared_data) { - 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; } @@ -329,17 +316,12 @@ bss_section () { if (in_section != in_bss) { - if (output_bytecode) - bc_data (); - else - { #ifdef SHARED_BSS_SECTION_ASM_OP - if (flag_shared_data) - fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP); - else + if (flag_shared_data) + fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP); + else #endif - fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); - } + fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); in_section = in_bss; } @@ -501,16 +483,6 @@ make_function_rtl (decl) char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); char *new_name = name; - 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 @@ -556,47 +528,6 @@ 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. */ - -static 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)) - 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 && !TREE_PUBLIC (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 * @@ -689,12 +620,6 @@ make_decl_rtl (decl, asmspec, top_level) register char *name = 0; 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) @@ -889,12 +814,6 @@ 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) @@ -1025,12 +944,7 @@ 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) - { - if (output_bytecode) - BC_OUTPUT_ALIGN (asm_out_file, align); - else - ASM_OUTPUT_ALIGN (asm_out_file, align); - } + ASM_OUTPUT_ALIGN (asm_out_file, align); #ifdef ASM_OUTPUT_FUNCTION_PREFIX ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname); @@ -1067,24 +981,16 @@ assemble_start_function (decl, fnname) ASM_WEAKEN_LABEL (asm_out_file, fnname); else #endif - if (output_bytecode) - BC_GLOBALIZE_LABEL (asm_out_file, fnname); - else - ASM_GLOBALIZE_LABEL (asm_out_file, fnname); + ASM_GLOBALIZE_LABEL (asm_out_file, fnname); } /* Do any machine/system dependent processing of the function name */ - if (output_bytecode) - BC_OUTPUT_LABEL (asm_out_file, fnname); - else - { #ifdef ASM_DECLARE_FUNCTION_NAME - ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl); + 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); + /* Standard thing is just output label for the function. */ + ASM_OUTPUT_LABEL (asm_out_file, fnname); #endif /* ASM_DECLARE_FUNCTION_NAME */ - } } /* Output assembler code associated with defining the size of the @@ -1114,12 +1020,6 @@ 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. */ @@ -1153,12 +1053,7 @@ assemble_zeros (size) else #endif if (size > 0) - { - if (output_bytecode) - BC_OUTPUT_SKIP (asm_out_file, size); - else - ASM_OUTPUT_SKIP (asm_out_file, size); - } + ASM_OUTPUT_SKIP (asm_out_file, size); } /* Assemble an alignment pseudo op for an ALIGN-bit boundary. */ @@ -1182,12 +1077,6 @@ 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) @@ -1196,26 +1085,13 @@ assemble_string (p, size) if (thissize > maximum) thissize = maximum; - if (output_bytecode) - bc_output_ascii (asm_out_file, p, thissize); - else - { - ASM_OUTPUT_ASCII (asm_out_file, p, thissize); - } + ASM_OUTPUT_ASCII (asm_out_file, p, thissize); pos += thissize; p += thissize; } } -static void -bc_output_ascii (file, p, size) - FILE *file; - char *p; - int size; -{ - BC_OUTPUT_ASCII (file, p, size); -} /* Assemble everything that is needed for a variable or function declaration. Not used for automatic variables, and not used for function definitions. @@ -1242,9 +1118,6 @@ assemble_variable (decl, top_level, at_end, dont_output_data) last_assemble_variable_decl = 0; - if (output_bytecode) - return; - if (GET_CODE (DECL_RTL (decl)) == REG) { /* Do output symbol info for global register variables, but do nothing @@ -1254,22 +1127,19 @@ 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 @@ -1422,11 +1292,6 @@ 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_DECL_COMMON ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, @@ -1449,11 +1314,6 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded); else #endif - if (output_bytecode) - { - BC_OUTPUT_BSS (asm_out_file, name, size, rounded); - } - else { #ifdef ASM_OUTPUT_ALIGNED_BSS ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, @@ -1471,11 +1331,6 @@ 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_DECL_LOCAL ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, @@ -1601,26 +1456,16 @@ assemble_variable (decl, top_level, at_end, dont_output_data) DECL_ALIGN (decl) = align; if (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)); - } + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); /* Do any machine/system dependent processing of the object. */ - if (output_bytecode) - BC_OUTPUT_LABEL (asm_out_file, name); - else - { #ifdef ASM_DECLARE_OBJECT_NAME - last_assemble_variable_decl = decl; - ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); + last_assemble_variable_decl = decl; + 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); + /* Standard thing is just output label for the object. */ + ASM_OUTPUT_LABEL (asm_out_file, name); #endif /* ASM_DECLARE_OBJECT_NAME */ - } if (!dont_output_data) { @@ -1693,55 +1538,6 @@ contains_pointers_p (type) } } -/* Output text storage for constructor CONSTR. */ - -void -bc_output_constructor (constr, size) - tree constr; - int size; -{ - 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, size); -} - -/* 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. */ @@ -1750,9 +1546,6 @@ 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)) @@ -1777,14 +1570,11 @@ assemble_external_libcall (fun) rtx fun; { #ifdef ASM_OUTPUT_EXTERNAL_LIBCALL - if (!output_bytecode) + /* Declare library function name external when first used, if nec. */ + if (! SYMBOL_REF_USED (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); - } + SYMBOL_REF_USED (fun) = 1; + ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun); } #endif } @@ -1804,10 +1594,7 @@ void assemble_label (name) char *name; { - if (output_bytecode) - BC_OUTPUT_LABEL (asm_out_file, name); - else - ASM_OUTPUT_LABEL (asm_out_file, name); + ASM_OUTPUT_LABEL (asm_out_file, name); } /* Output to FILE a reference to the assembler name of a C-level name NAME. @@ -1834,19 +1621,9 @@ assemble_name (file, name) TREE_SYMBOL_REFERENCED (id) = 1; if (name[0] == '*') - { - if (output_bytecode) - bc_emit_labelref (name, 0); - else - fputs (&name[1], file); - } + fputs (&name[1], file); else - { - if (output_bytecode) - BC_OUTPUT_LABELREF (file, name); - else - ASM_OUTPUT_LABELREF (file, name); - } + ASM_OUTPUT_LABELREF (file, name); } /* Allocate SIZE bytes writable static space with a gensym name @@ -1877,28 +1654,18 @@ assemble_static_space (size) strlen (name) + 2); strcpy (namestring, name); - if (output_bytecode) - x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0); - else - x = gen_rtx_SYMBOL_REF (Pmode, namestring); + x = gen_rtx_SYMBOL_REF (Pmode, namestring); - if (output_bytecode) - { - BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded); - } - else - { #ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL - ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size, - BIGGEST_ALIGNMENT); + ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size, + BIGGEST_ALIGNMENT); #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 #endif - } return x; } @@ -1914,10 +1681,6 @@ 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 @@ -2385,13 +2148,9 @@ decode_addr_const (exp, value) break; case LABEL_DECL: - 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)))); + x = gen_rtx_MEM (FUNCTION_MODE, + gen_rtx_LABEL_REF (VOIDmode, + label_rtx (TREE_OPERAND (exp, 0)))); break; case REAL_CST: @@ -2406,12 +2165,9 @@ decode_addr_const (exp, value) abort (); } - if (!output_bytecode) - { - if (GET_CODE (x) != MEM) - abort (); - x = XEXP (x, 0); - } + if (GET_CODE (x) != MEM) + abort (); + x = XEXP (x, 0); value->base = x; value->offset = offset; @@ -3179,16 +2935,7 @@ output_constant_def_contents (exp, reloc, labelno) #endif if (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)); - } - } + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); /* Output the label itself. */ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno); @@ -3994,10 +3741,7 @@ output_constant (exp, size) This means to fill the space with zeros. */ if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0) { - if (output_bytecode) - bc_emit_const_skip (size); - else - assemble_zeros (size); + assemble_zeros (size); return; } @@ -4091,107 +3835,6 @@ output_constant (exp, size) assemble_zeros (size); } -/* Bytecode specific code to output assembler for integer. */ - -static 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 - || TREE_CODE (exp) == NON_LVALUE_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 - || TREE_CODE (const_part) == NON_LVALUE_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 - || TREE_CODE (addr_part) == NON_LVALUE_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); - } - size -= 8; - } - } - else - if (size == 4 - && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL) - bc_emit_labelref (IDENTIFIER_POINTER - (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). @@ -4299,10 +3942,7 @@ output_constructor (exp, size) if each element has the proper size. */ if ((field != 0 || index != 0) && bitpos != total_bytes) { - if (!output_bytecode) - assemble_zeros (bitpos - total_bytes); - else - bc_emit_const_skip (bitpos - total_bytes); + assemble_zeros (bitpos - total_bytes); total_bytes = bitpos; } @@ -4563,9 +4203,6 @@ assemble_alias (decl, target) ASM_WEAKEN_LABEL (asm_out_file, name); else #endif - if (output_bytecode) - BC_GLOBALIZE_LABEL (asm_out_file, name); - else ASM_GLOBALIZE_LABEL (asm_out_file, name); } -- 2.30.2