aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Costa <roberto.costa@st.com>2006-09-07 07:37:27 +0000
committerRoberto Costa <roberto.costa@st.com>2006-09-07 07:37:27 +0000
commit7dfcf8e3dc169b61646d9e4e680c6fa36e69f4b5 (patch)
treee917976b6d7545cbbe302e2e143303647a9f5e91
parenta735fba5dfb5e5c3b75af915f7132b438effd1ff (diff)
Initial support for CLI back-end
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/st/cli@116745 138bc75d-0d04-0410-961f-82ee72b054a4
-rwxr-xr-xcil32-crosstool.sh187
-rwxr-xr-xconfig.sub5
-rwxr-xr-xconfigure4
-rw-r--r--configure.in4
-rw-r--r--gcc/config.gcc9
-rw-r--r--gcc/config/cil32/cil32-modes.def42
-rw-r--r--gcc/config/cil32/cil32-protos.h29
-rw-r--r--gcc/config/cil32/cil32.c232
-rw-r--r--gcc/config/cil32/cil32.h539
-rw-r--r--gcc/config/cil32/cil32.md211
-rw-r--r--gcc/config/cil32/cil32.opt53
-rw-r--r--gcc/config/cil32/gcc4net.cs106
-rw-r--r--gcc/config/cil32/gen-cil.c3562
-rw-r--r--gcc/config/cil32/gen-cil.h47
-rw-r--r--gcc/config/cil32/t-cil3260
-rw-r--r--gcc/config/cil32/tree-simp-cil.c2166
-rw-r--r--gcc/config/cil32/tree-simp-cil.h39
-rw-r--r--gcc/opts.c3
-rw-r--r--gcc/passes.c9
-rw-r--r--gcc/pointer-set.c27
-rw-r--r--gcc/pointer-set.h12
-rw-r--r--gcc/varasm.c5
22 files changed, 7350 insertions, 1 deletions
diff --git a/cil32-crosstool.sh b/cil32-crosstool.sh
new file mode 100755
index 00000000000..53cf09e75e2
--- /dev/null
+++ b/cil32-crosstool.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+
+
+INSTALL_GCC=yes
+
+TARGET=cil32
+
+BUILD_DIR=${BUILD_DIR-`pwd`}
+SOURCE_DIR=${SOURCE_DIR-`dirname $0`}
+SOURCE_DIR=`cd $SOURCE_DIR; pwd`
+PREFIX=${PREFIX-`pwd`/newbuild}
+SYSROOT=${PREFIX}/${TARGET}
+LANGUAGES=c
+
+_help()
+{
+ echo "Options:"
+ echo " -nogcc : build only binutils (no compiler)"
+ echo " -cpp : build also C++ compiler"
+ echo " -help : this message"
+}
+
+while [ $# -gt 0 ] ; do
+
+if [ "x$1" == x-help ] ; then
+ _help ;
+ exit 0
+elif [ "x$1" == x-cpp ] ; then
+ LANGUAGES=c,c++
+elif [ "x$1" == x-nogcc ] ; then
+ INSTALL_GCC=no
+else
+ echo "Unrecognized option: " $1
+ _help ;
+ exit 1
+fi
+
+shift 1
+done
+
+echo "DIRECTORIES:"
+echo " BUILD_DIR: " ${BUILD_DIR}
+echo " SOURCE_DIR: " ${SOURCE_DIR}
+echo " SYSROOT: " ${SYSROOT}
+echo " PREFIX: " ${PREFIX}
+
+
+PATH="${PREFIX}/bin:${PATH}"
+export PATH
+
+# Create directories
+
+mkdir -p ${PREFIX}
+mkdir -p ${PREFIX}/bin
+mkdir -p ${PREFIX}/include
+mkdir -p ${PREFIX}/lib
+# SYSROOT must be = ${PREFIX}/${TARGET}
+mkdir -p ${SYSROOT}
+mkdir -p ${SYSROOT}/bin
+( cd ${SYSROOT} ; ln -fs ../include . )
+( cd ${SYSROOT} ; ln -fs ../lib . )
+
+# Install Binutils
+
+CIL_AS=${CIL_AS-`which ilasm`}
+CIL_LD=${CIL_LD-`which ilalink`}
+
+echo "Tools:"
+echo " CIL ASSEMBLER: " ${CIL_AS}
+echo " CIL LINKER: " ${CIL_LD}
+
+echo
+echo "Installing Bin Utils"
+
+cat > ${SYSROOT}/bin/tool_not_exist <<_EOF_
+#!/bin/sh
+echo "Tool " \`basename \$0\` " not provided"
+exit 1
+_EOF_
+chmod 755 ${SYSROOT}/bin/tool_not_exist
+
+cat > ${SYSROOT}/bin/as <<_EOF_
+#!/bin/sh
+
+${CIL_AS} "\$@"
+_EOF_
+chmod 755 ${SYSROOT}/bin/as
+
+cat > ${SYSROOT}/bin/ld <<_EOF_
+#!/bin/sh
+
+PARAM=
+
+for i in "\$@" ; do
+ case "\$i" in
+ -lm)
+ ;;
+ /tmp*)
+ PARAM="\${PARAM} /\${i}";
+ ;;
+ *)
+ PARAM="\${PARAM} \${i}";
+ ;;
+ esac
+done
+
+${CIL_LD} \$PARAM
+
+_EOF_
+chmod 755 ${SYSROOT}/bin/ld
+
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/addr2line
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/ar
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/nm
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/objcopy
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/objdump
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/ranlib
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/readelf
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/size
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/strings
+cp ${SYSROOT}/bin/tool_not_exist ${SYSROOT}/bin/strip
+
+
+cp ${SYSROOT}/bin/addr2line ${PREFIX}/bin/${TARGET}-addr2line
+cp ${SYSROOT}/bin/ar ${PREFIX}/bin/${TARGET}-ar
+cp ${SYSROOT}/bin/as ${PREFIX}/bin/${TARGET}-as
+cp ${SYSROOT}/bin/ld ${PREFIX}/bin/${TARGET}-ld
+cp ${SYSROOT}/bin/nm ${PREFIX}/bin/${TARGET}-nm
+cp ${SYSROOT}/bin/objcopy ${PREFIX}/bin/${TARGET}-objcopy
+cp ${SYSROOT}/bin/objdump ${PREFIX}/bin/${TARGET}-objdump
+cp ${SYSROOT}/bin/ranlib ${PREFIX}/bin/${TARGET}-ranlib
+cp ${SYSROOT}/bin/readelf ${PREFIX}/bin/${TARGET}-readelf
+cp ${SYSROOT}/bin/size ${PREFIX}/bin/${TARGET}-size
+cp ${SYSROOT}/bin/strings ${PREFIX}/bin/${TARGET}-strings
+cp ${SYSROOT}/bin/strip ${PREFIX}/bin/${TARGET}-strip
+
+echo
+echo "Installing vm wrappers"
+
+cat > ${PREFIX}/bin/${TARGET}-ilrun <<_EOF_
+#!/bin/sh
+
+ilrun -L ${PREFIX}/lib "\$@"
+_EOF_
+chmod 755 ${PREFIX}/bin/${TARGET}-ilrun
+
+cat > ${PREFIX}/bin/${TARGET}-mono <<_EOF_
+#!/bin/sh
+
+export MONO_PATH=${PREFIX}/lib
+
+mono "\$@"
+_EOF_
+chmod 755 ${PREFIX}/bin/${TARGET}-mono
+
+# ... To Be Completed with needed binutil tools
+
+# ... To Be Completed with libraries
+
+if test "x${INSTALL_GCC}" == "xno"
+then
+ exit 0
+fi
+
+# Configure gcc
+
+echo
+echo "Configuring GCC"
+
+mkdir -p ${BUILD_DIR}/build-gcc
+cd ${BUILD_DIR}/build-gcc
+
+${SOURCE_DIR}/configure --target=${TARGET} \
+ --enable-languages=${LANGUAGES} \
+ --disable-bootstrap \
+ --prefix=${PREFIX} \
+ --with-local-prefix=${SYSROOT}
+
+# Build and install gcc
+
+echo
+echo "Building GCC"
+make all
+
+echo
+echo "Installing GCC"
+make install
diff --git a/config.sub b/config.sub
index 4d936e23942..03e8910a9ca 100755
--- a/config.sub
+++ b/config.sub
@@ -288,6 +288,9 @@ case $basic_machine in
| z8k)
basic_machine=$basic_machine-unknown
;;
+ cil32)
+ basic_machine=$basic_machine-unknown
+ ;;
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
basic_machine=$basic_machine-unknown
@@ -372,6 +375,8 @@ case $basic_machine in
| ymp-* \
| z8k-*)
;;
+ cil32-*)
+ ;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
386bsd)
diff --git a/configure b/configure
index 22cdb87e473..0780b324d03 100755
--- a/configure
+++ b/configure
@@ -1342,6 +1342,10 @@ case "${target}" in
c54x*-*-* | tic54x-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3 target-libgloss ${libgcj} gcc gdb newlib"
;;
+ cil32-*-*)
+ unsupported_languages="$unsupported_languages ada fortran java"
+ noconfigdirs="$noconfigdirs target-libssp target-libiberty target-libmudflap"
+ ;;
cris-*-* | crisv32-*-*)
unsupported_languages="$unsupported_languages java"
case "${target}" in
diff --git a/configure.in b/configure.in
index 0c83351863c..2ab1abd1512 100644
--- a/configure.in
+++ b/configure.in
@@ -518,6 +518,10 @@ case "${target}" in
c54x*-*-* | tic54x-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3 target-libgloss ${libgcj} gcc gdb newlib"
;;
+ cil32-*-*)
+ unsupported_languages="$unsupported_languages ada fortran java"
+ noconfigdirs="$noconfigdirs target-libssp target-libiberty target-libmudflap"
+ ;;
cris-*-* | crisv32-*-*)
unsupported_languages="$unsupported_languages java"
case "${target}" in
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 7ea15d34b5e..571dba31047 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -257,6 +257,9 @@ arm*-*-*)
bfin*-*)
cpu_type=bfin
;;
+cil32-*-*)
+ cpu_type=cil32
+ ;;
ep9312*-*-*)
cpu_type=arm
;;
@@ -799,6 +802,12 @@ c4x-* | tic4x-*)
c_target_objs="c4x-c.o"
cxx_target_objs="c4x-c.o"
;;
+cil32-*-*)
+ gas=no
+ use_collect2=no
+ extra_objs="tree-simp-cil.o gen-cil.o"
+ target_gtfiles="\$(srcdir)/config/cil32/gen-cil.c"
+ ;;
cris-*-aout)
tm_file="dbxelf.h ${tm_file} cris/aout.h"
gas=yes
diff --git a/gcc/config/cil32/cil32-modes.def b/gcc/config/cil32/cil32-modes.def
new file mode 100644
index 00000000000..db119f94fda
--- /dev/null
+++ b/gcc/config/cil32/cil32-modes.def
@@ -0,0 +1,42 @@
+/* Definitions of target machine for GCC for CIL32.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+/* Vector modes. */
+VECTOR_MODES (INT, 4); /* V4QI V2HI */
+VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI */
+VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */
+VECTOR_MODES (FLOAT, 8); /* V4HF V2SF */
+VECTOR_MODES (FLOAT, 16); /* V8HF V4SF V2DF */
+VECTOR_MODE (INT, DI, 4); /* V4DI */
+VECTOR_MODE (INT, SI, 8); /* V8SI */
+VECTOR_MODE (INT, HI, 16); /* V16HI */
+VECTOR_MODE (INT, QI, 32); /* V32QI */
+VECTOR_MODE (FLOAT, DF, 4); /* V4DF */
+VECTOR_MODE (FLOAT, SF, 8); /* V8SF */
diff --git a/gcc/config/cil32/cil32-protos.h b/gcc/config/cil32/cil32-protos.h
new file mode 100644
index 00000000000..57cbd7c05f1
--- /dev/null
+++ b/gcc/config/cil32/cil32-protos.h
@@ -0,0 +1,29 @@
+/* Definitions for GCC. Part of the machine description for cil32.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
diff --git a/gcc/config/cil32/cil32.c b/gcc/config/cil32/cil32.c
new file mode 100644
index 00000000000..7cf4938b285
--- /dev/null
+++ b/gcc/config/cil32/cil32.c
@@ -0,0 +1,232 @@
+/* Definitions for GCC. Part of the machine description for cil32.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "tree.h"
+#include "expr.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#include "recog.h"
+#include "reload.h"
+#include "tm_p.h"
+#include "debug.h"
+#include "output.h"
+#include "target.h"
+#include "target-def.h"
+#include "ggc.h"
+#include "optabs.h"
+#include "langhooks.h"
+#include "gen-cil.h"
+
+/* Per-function machine data. */
+struct machine_function GTY(())
+ {
+ char dummy;
+ };
+
+static tree cil32_handle_function_attribute (tree *, tree, tree, int, bool *);
+static void cil32_file_start (void);
+static void cil32_file_end (void);
+static void cil32_named_section (const char *, unsigned int, tree);
+static void cil32_globalize_label (FILE *, const char *);
+static bool cil32_assemble_integer (rtx, unsigned int, int);
+
+static void cil32_init_builtins (void);
+static tree cil32_build_builtin_va_list (void);
+static tree cil32_gimplify_va_arg (tree, tree, tree*, tree*);
+
+static bool cil32_vector_mode_supported_p (enum machine_mode);
+
+const struct attribute_spec cil32_attribute_table[];
+
+/* Initialize the GCC target structure. */
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE cil32_attribute_table
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS cil32_init_builtins
+
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START cil32_file_start
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END cil32_file_end
+#undef TARGET_ASM_NAMED_SECTION
+#define TARGET_ASM_NAMED_SECTION cil32_named_section
+#undef TARGET_ASM_GLOBALIZE_LABEL
+#define TARGET_ASM_GLOBALIZE_LABEL cil32_globalize_label
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER cil32_assemble_integer
+
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST cil32_build_builtin_va_list
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR cil32_gimplify_va_arg
+
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P cil32_vector_mode_supported_p
+
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+/* CIL32 Code */
+
+static tree
+cil32_handle_function_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (strcmp (IDENTIFIER_POINTER (name), "pinvoke") == 0)
+ cil_add_pinvoke(*node);
+
+ return NULL_TREE;
+}
+
+/* Table of valid machine attributes. */
+const struct attribute_spec cil32_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "assembly_name", 1,1,false,false,false, cil32_handle_function_attribute },
+ { "cil_name", 1,1,false,false,false, cil32_handle_function_attribute },
+ { "pinvoke", 1,2,false,false,false, cil32_handle_function_attribute },
+ { NULL, 0,0,false,false,false, NULL }
+};
+
+static void
+cil32_file_start (void)
+{
+ gen_cil_init ();
+}
+
+static void
+cil32_file_end (void)
+{
+ gen_cil_fini ();
+}
+
+static void
+cil32_named_section (const char *name ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
+{
+}
+
+static void
+cil32_globalize_label (FILE *stream ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+}
+
+static bool
+cil32_assemble_integer (rtx x ATTRIBUTE_UNUSED,
+ unsigned int size ATTRIBUTE_UNUSED,
+ int aligned_p ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+static tree cil32_builtin_va_arg_decl;
+
+static void
+cil32_init_builtins (void)
+{
+
+ tree arglist = build_tree_list (NULL_TREE, ptr_type_node);
+ arglist = tree_cons (NULL_TREE, va_list_type_node, arglist);
+ cil32_builtin_va_arg_decl = lang_hooks.builtin_function ("__builtin_va_arg",
+ build_function_type (ptr_type_node,
+ arglist),
+ CIL32_BUILTIN_VA_ARG,
+ BUILT_IN_MD,
+ NULL,
+ NULL_TREE);
+}
+
+static tree
+cil32_build_builtin_va_list (void)
+{
+ tree f_dummy, record, type_decl;
+
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list"), record);
+
+ f_dummy = build_decl (FIELD_DECL, get_identifier ("__dummy"), ptr_type_node);
+
+ DECL_FIELD_CONTEXT (f_dummy) = record;
+
+ TREE_CHAIN (record) = type_decl;
+ TYPE_NAME (record) = type_decl;
+ TYPE_FIELDS (record) = f_dummy;
+
+ layout_type (record);
+ return record;
+}
+
+static tree
+cil32_gimplify_va_arg (tree valist, tree type, tree *pre_p ATTRIBUTE_UNUSED, tree *post_p ATTRIBUTE_UNUSED)
+{
+ tree fcall;
+ tree ptr_type = build_pointer_type(type);
+ tree arglist = build_tree_list (NULL_TREE, build_int_cstu (ptr_type,0));
+ arglist = tree_cons (NULL_TREE, valist, arglist);
+ fcall = build_function_call_expr (cil32_builtin_va_arg_decl, arglist);
+ TREE_TYPE (fcall) = ptr_type;
+ return build1(INDIRECT_REF,type,fcall);
+}
+
+/* Target hook for vector_mode_supported_p. */
+static bool
+cil32_vector_mode_supported_p (enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+#include "gt-cil32.h"
diff --git a/gcc/config/cil32/cil32.h b/gcc/config/cil32/cil32.h
new file mode 100644
index 00000000000..43af5cf5eda
--- /dev/null
+++ b/gcc/config/cil32/cil32.h
@@ -0,0 +1,539 @@
+/* Definitions for GCC. Part of the machine description for cil32.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#define DISABLE_RTL_PASSES 1
+
+#define IN_NAMED_SECTION(DECL) 0
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) do { } while(0)
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) do { } while(0)
+
+/* make_decl_cil (stream, decl); */
+#define TARGET_DECLARE_VARIABLE(STREAM,DECL) make_decl_cil(STREAM,DECL)
+
+/* Node: Driver */
+
+#define CC1_SPEC "%{!mnoopensystemc:-mopensystemc}"
+#define LIB_SPEC ""
+#define LIBGCC_SPEC ""
+#define LINK_SPEC "--no-stdlib %{!nostdlib:-l gcc4net.dll} %{shared:--format dll}"
+#define STARTFILE_SPEC ""
+#define ENDFILE_SPEC ""
+
+/* Node: Run-time Target */
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("__cil32__"); \
+ builtin_define_std ("__GNU_CIL__"); \
+ builtin_assert ("cpu=cil32"); \
+ builtin_assert ("machine=cil32"); \
+ } \
+ while(0)
+
+/* This needs to be at least 32 bits. */
+extern int target_flags;
+
+/* Print subsidiary information on the compiler version in use.
+ Do not use VD.D syntax (D=digit), since this will cause confusion
+ with the base gcc version among users, when we ask which version of
+ gcc-cil32 they are using. Please use some flavor of "R<number>" for
+ the version (no need for major.minor versions, I believe). */
+#define TARGET_VERSION \
+ fprintf (stderr, " [cil32]")
+
+/* Node: Storage Layout */
+
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 0
+#define WORDS_BIG_ENDIAN 0
+
+#define UNITS_PER_WORD 4
+#define UNITS_PER_SIMD_WORD 4
+
+/* Unused by cil32 machine */
+#define PARM_BOUNDARY 32
+
+/* Unused by cil32 machine */
+#define STACK_BOUNDARY 64
+
+/* Unused by cil32 machine */
+#define FUNCTION_BOUNDARY 16
+
+#define BIGGEST_ALIGNMENT 64
+
+#define STRICT_ALIGNMENT 1
+
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+#define MAX_FIXED_MODE_SIZE 64
+
+
+/* Node: Type Layout */
+
+/* Note that DOUBLE_TYPE_SIZE is not defined anymore, since the default
+ value gives a 64-bit double, which is what we now use. */
+
+/* For compatibility and historical reasons, a char should be signed. */
+#define DEFAULT_SIGNED_CHAR 1
+
+/* Note that WCHAR_TYPE_SIZE is used in cexp.y,
+ where TARGET_SHORT is not available. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+
+/* Node: Register Basics */
+
+#define FIRST_PSEUDO_REGISTER (1)
+#define FIXED_REGISTERS {0}
+#define CALL_USED_REGISTERS {0}
+
+/* Node: Allocation Order */
+
+#define REG_ALLOC_ORDER {0}
+
+
+/* Node: Values in Registers */
+
+/* The VOIDmode test is so we can omit mode on anonymous insns. FIXME:
+ Still needed in 2.9x, at least for Axis-20000319. */
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ (MODE == VOIDmode \
+ ? 1 : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+#define MODES_TIEABLE_P(MODE1, MODE2) 1
+
+
+/* Node: Leaf Functions */
+/* (no definitions) */
+
+/* Node: Stack Registers */
+/* (no definitions) */
+
+
+/* Node: Register Classes */
+
+enum reg_class
+ {
+ NO_REGS,
+ GENERAL_REGS, ALL_REGS,
+ LIM_REG_CLASSES
+ };
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES \
+ {"NO_REGS", \
+ "GENERAL_REGS", "ALL_REGS"}
+
+/* Count in the faked argument register in GENERAL_REGS. Keep out SRP. */
+#define REG_CLASS_CONTENTS \
+ { \
+ {0}, \
+ {1}, \
+ {1} \
+ }
+
+#define REGNO_REG_CLASS(REGNO) GENERAL_REGS
+
+#define BASE_REG_CLASS GENERAL_REGS
+
+#define INDEX_REG_CLASS GENERAL_REGS
+
+#define REG_CLASS_FROM_LETTER(C) NO_REGS
+
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ ((REGNO) == CIL32_FAKE_REG)
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) GENERAL_REGS
+
+#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) NO_REGS
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((MODE) == VOIDmode \
+ ? 1 \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+#define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR) 0
+
+#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(VALUE, C, STR) 0
+
+/* We want the unary operators visible for constraint checking.
+ (will always be the case in 4.2). */
+#define KEEP_UNARY_OPERATORS_AT_CONSTRAINT_CHECKING
+
+
+/* Node: Frame Layout */
+
+#define STACK_GROWS_DOWNWARD
+#define FRAME_GROWS_DOWNWARD 1
+
+/* It seems to be indicated in the code (at least 2.1) that this is
+ better a constant, and best 0. */
+#define STARTING_FRAME_OFFSET 0
+
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, CIL32_FAKE_REG)
+
+#define EH_RETURN_DATA_REGNO(N) CIL32_FAKE_REG
+
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, CIL32_FAKE_REG)
+
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (CIL32_FAKE_REG)
+
+/* FIXME: Move this to right node (it's not documented properly yet).
+ FIXME: Check what alignment we can assume regarding
+ TARGET_STACK_ALIGN and TARGET_ALIGN_BY_32. */
+#define DWARF_CIE_DATA_ALIGNMENT -1
+
+/* If we would ever need an exact mapping between canonical register
+ number and dwarf frame register, we would either need to include all
+ registers in the gcc description (with some marked fixed of course), or
+ an inverse mapping from dwarf register to gcc register. There is one
+ need in dwarf2out.c:expand_builtin_init_dwarf_reg_sizes. Right now, I
+ don't see that we need exact correspondence between DWARF *frame*
+ registers and DBX_REGISTER_NUMBER, so map them onto GCC registers. */
+#define DWARF_FRAME_REGNUM(REG) (REG)
+
+/* Node: Stack Checking */
+/* (no definitions) */
+
+/* Node: Frame Registers */
+
+#define STACK_POINTER_REGNUM CIL32_FAKE_REG
+
+/* Register used for frame pointer. This is also the last of the saved
+ registers, when a frame pointer is not used. */
+#define FRAME_POINTER_REGNUM CIL32_FAKE_REG
+
+/* Faked register, is always eliminated. We need it to eliminate
+ allocating stack slots for the return address and the frame pointer. */
+#define ARG_POINTER_REGNUM CIL32_FAKE_REG
+
+#define STATIC_CHAIN_REGNUM CIL32_FAKE_REG
+
+
+/* Node: Elimination */
+
+/* Really only needed if the stack frame has variable length (alloca
+ or variable sized local arguments (GNU C extension). */
+#define FRAME_POINTER_REQUIRED 0
+
+#define INITIAL_FRAME_POINTER_OFFSET(n) \
+ do { n = 0; } while(0)
+
+/* We need not worry about when the frame-pointer is required for other
+ reasons. */
+#define CAN_ELIMINATE(FROM, TO) 1
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) (gcc_unreachable ())
+
+
+/* Node: Stack Arguments */
+
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0
+
+
+/* Node: Register Arguments */
+
+/* The void_type_node is sent as a "closing" call. */
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+ (NULL_RTX)
+
+/* This no longer *needs* to be a structure; but keeping it as such should
+ not hurt (and hacking the ABI is simpler). */
+#define CUMULATIVE_ARGS struct cum_args
+struct cum_args {int regs;};
+
+/* The regs member is an integer, the number of arguments got into
+ registers so far. */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+ ((CUM).regs = 0)
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ ((CUM).regs += 1)
+
+#define FUNCTION_ARG_REGNO_P(REGNO) 0
+
+
+/* Node: Scalar Return */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ gen_rtx_REG (TYPE_MODE (VALTYPE), CIL32_FAKE_REG)
+
+#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, CIL32_FAKE_REG)
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == CIL32_FAKE_REG)
+
+
+/* Node: Aggregate Return */
+/* (no definitions) */
+
+/* Node: Caller Saves */
+/* (no definitions) */
+
+/* Node: Function entry */
+/* (no definitions) */
+
+/* Node: Profiling */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ error ("no FUNCTION_PROFILER for CIL32 yet")
+
+/* FIXME: Some of the undefined macros might be mandatory. If so, fix
+ documentation. */
+
+
+/* Node: Trampolines */
+/* TODO */
+
+#define TRAMPOLINE_SIZE 0
+
+#define TRAMPOLINE_ALIGNMENT 0
+
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ do {} while(0)
+
+/* Node: Library Calls */
+
+/* If you change this, you have to check whatever libraries and systems
+ that use it. */
+#define TARGET_EDOM 33
+
+
+/* Node: Addressing Modes */
+
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+
+#define MAX_REGS_PER_ADDRESS 2
+
+#define CONSTANT_INDEX_P(X) \
+ (CONSTANT_P (X))
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+ { \
+ if (REG_P (X)) \
+ goto ADDR; \
+ if (CONSTANT_INDEX_P (X)) \
+ goto ADDR; \
+ if (GET_CODE (X) == PLUS) \
+ { \
+ rtx x1 = XEXP (X, 0); \
+ rtx x2 = XEXP (X, 1); \
+ /* BDAP o, Rd. */ \
+ if ((REG_P (x1) || CONSTANT_INDEX_P (x1)) \
+ && (REG_P (x2) && CONSTANT_INDEX_P (x2))) \
+ goto ADDR; \
+ } \
+ }
+
+#ifndef REG_OK_STRICT
+ /* Nonzero if X is a hard reg that can be used as a base reg
+ or if it is a pseudo reg. */
+# define REG_OK_FOR_BASE_P(X) 1
+#else
+ /* Nonzero if X is a hard reg that can be used as a base reg. */
+# define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#endif
+
+#ifndef REG_OK_STRICT
+ /* Nonzero if X is a hard reg that can be used as an index
+ or if it is a pseudo reg. */
+# define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
+#else
+ /* Nonzero if X is a hard reg that can be used as an index. */
+# define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+#endif
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
+ do {} while(0)
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+
+
+/* Node: Condition Code */
+
+#define NOTICE_UPDATE_CC(EXP, INSN) (gcc_unreachable ())
+
+
+/* Node: Costs */
+
+#define SLOW_BYTE_ACCESS 0
+
+
+/* Node: Sections */
+
+#define TEXT_SECTION_ASM_OP ""
+
+#define DATA_SECTION_ASM_OP ""
+
+
+/* Node: PIC */
+/* (no definitions) */
+
+/* Node: File Framework */
+
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE, SIZE) \
+ do {} while(0)
+
+#define ASM_APP_ON ""
+#define ASM_APP_OFF ""
+
+
+/* Node: Data Output */
+
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) (C) == '@'
+
+/* Node: Uninitialized Data */
+
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \
+ do {} while(0)
+
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+ do {} while(0)
+
+/* Node: Label Output */
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.global "
+
+#define SUPPORTS_WEAK 1
+
+/* Remove any previous definition (elfos.h). */
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
+ sprintf (LABEL, "*%s%s%ld", LOCAL_LABEL_PREFIX, PREFIX, (long) NUM)
+
+/* Node: Initialization */
+/* (no definitions) */
+
+/* Node: Macros for Initialization */
+/* (no definitions) */
+
+/* Node: Instruction Output */
+
+#define REGISTER_NAMES {"fake"}
+
+#define PRINT_OPERAND(FILE, X, CODE) (gcc_unreachable ())
+
+/* For delay-slot handling. */
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) 0
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) (gcc_unreachable ())
+
+#define LOCAL_LABEL_PREFIX "."
+
+#define REGISTER_PREFIX "$"
+
+#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) (gcc_unreachable ())
+#define ASM_OUTPUT_REG_POP(FILE, REGNO) (gcc_unreachable ())
+
+
+/* Node: Dispatch Tables */
+/* (no definitions) */
+
+/* Node: Exception Region Output */
+/* (no definitions) */
+
+/* Node: Alignment Output */
+
+/* Node: All Debuggers */
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+
+/* Node: DBX Options */
+/* (no definitions) */
+
+/* Node: DBX Hooks */
+/* (no definitions) */
+
+/* Node: File names and DBX */
+/* (no definitions) */
+
+
+/* Node: SDB and DWARF */
+/* (no definitions) */
+
+/* Node: Misc */
+
+#define CASE_VECTOR_MODE HImode
+
+/* The maximum number of bytes that a single instruction can move quickly
+ between memory and registers or between two memory locations. */
+#define MOVE_MAX 8
+#define MOVE_MAX_PIECES 4
+
+/* Determine whether to use move_by_pieces or block move insn. */
+#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
+ ( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 || (SIZE) == 8 )
+
+/* Determine whether to use clear_by_pieces or block clear insn. */
+#define CLEAR_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+
+/* This macro is used to determine whether store_by_pieces should be
+ called to "memset" storage with byte values other than zero, or
+ to "memcpy" storage when the source is a constant string. */
+#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define Pmode SImode
+
+#define FUNCTION_MODE QImode
+
+#define NO_IMPLICIT_EXTERN_C
+
+extern struct tree_opt_pass pass_gen_cil;
+extern struct tree_opt_pass pass_simp_cil;
+
+/* cil32 builtin ID */
+enum cil32_builtin
+{
+ CIL32_BUILTIN_VA_ARG
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/gcc/config/cil32/cil32.md b/gcc/config/cil32/cil32.md
new file mode 100644
index 00000000000..6b6587ff76b
--- /dev/null
+++ b/gcc/config/cil32/cil32.md
@@ -0,0 +1,211 @@
+;; GCC machine description for cil32.
+;;
+;; Copyright (C) 2006 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC 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.
+;;
+;; GCC 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 GCC; see the file COPYING. If not, write to the Free
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+;;
+;; Authors:
+;; Andrea Bona
+;; Andrea Ornstein
+;; Erven Rohou
+;; Roberto Costa
+;;
+;; Contact information at STMicroelectronics:
+;; Roberto Costa <roberto.costa@st.com>
+
+;; See files "md.texi" and "rtl.def" for documentation on define_insn,
+;; match_*, et. al.
+
+;; Register numbers.
+(define_constants
+ [(CIL32_FAKE_REG 0)]
+)
+
+
+(define_mode_macro ALLMODES [SI HI QI DI SF DF])
+(define_mode_macro ALLEVALMODES [SI DI SF DF])
+(define_mode_macro ALLINTEVALMODES [SI DI])
+
+(define_mode_macro VECMODES [V8QI V4HI V2SI V4QI V2HI])
+
+
+;; Jump and branch insns.
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ "1"
+ ""
+ [])
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+ ""
+ "")
+
+;; Move insns.
+
+(define_insn "mov<mode>"
+ [(set (match_operand:ALLMODES 0 "nonimmediate_operand" "")
+ (match_operand:ALLMODES 1 "general_operand" ""))]
+ ""
+ "")
+
+;; Move for vectors
+(define_insn "mov<mode>"
+ [(set (match_operand:VECMODES 0 "nonimmediate_operand" "")
+ (match_operand:VECMODES 1 "general_operand" ""))]
+ ""
+ "")
+
+
+;; Add insns.
+
+(define_insn "add<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (plus:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "add")
+
+(define_insn "sub<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (minus:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "sub")
+
+(define_insn "mul<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (mult:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "mul")
+
+(define_insn "div<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (div:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "div")
+
+(define_insn "udiv<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (udiv:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "div.un")
+
+(define_insn "mod<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (mod:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "rem")
+
+(define_insn "umod<mode>3"
+ [(set (match_operand:ALLEVALMODES 0 "nonimmediate_operand" "")
+ (umod:ALLEVALMODES
+ (match_operand:ALLEVALMODES 1 "general_operand" "")
+ (match_operand:ALLEVALMODES 2 "general_operand" "")))]
+ ""
+ "rem.un")
+
+(define_insn "and<mode>3"
+ [(set (match_operand:ALLINTEVALMODES 0 "nonimmediate_operand" "")
+ (and:ALLINTEVALMODES
+ (match_operand:ALLINTEVALMODES 1 "general_operand" "")
+ (match_operand:ALLINTEVALMODES 2 "general_operand" "")))]
+ ""
+ "and")
+
+;; and works in SIMD mode
+(define_insn "and<mode>3"
+ [(set (match_operand:VECMODES 0 "nonimmediate_operand" "")
+ (and:VECMODES
+ (match_operand:VECMODES 1 "general_operand" "")
+ (match_operand:VECMODES 2 "general_operand" "")))]
+ ""
+ "and")
+
+(define_insn "ior<mode>3"
+ [(set (match_operand:ALLINTEVALMODES 0 "nonimmediate_operand" "")
+ (ior:ALLINTEVALMODES
+ (match_operand:ALLINTEVALMODES 1 "general_operand" "")
+ (match_operand:ALLINTEVALMODES 2 "general_operand" "")))]
+ ""
+ "or")
+
+;; or works in SIMD mode
+(define_insn "ior<mode>3"
+ [(set (match_operand:VECMODES 0 "nonimmediate_operand" "")
+ (ior:VECMODES
+ (match_operand:VECMODES 1 "general_operand" "")
+ (match_operand:VECMODES 2 "general_operand" "")))]
+ ""
+ "or")
+
+(define_insn "xor<mode>3"
+ [(set (match_operand:ALLINTEVALMODES 0 "nonimmediate_operand" "")
+ (xor:ALLINTEVALMODES
+ (match_operand:ALLINTEVALMODES 1 "general_operand" "")
+ (match_operand:ALLINTEVALMODES 2 "general_operand" "")))]
+ ""
+ "xor")
+
+;; xor works in SIMD mode
+(define_insn "xor<mode>3"
+ [(set (match_operand:VECMODES 0 "nonimmediate_operand" "")
+ (xor:VECMODES
+ (match_operand:VECMODES 1 "general_operand" "")
+ (match_operand:VECMODES 2 "general_operand" "")))]
+ ""
+ "xor")
+
+
+;; Call insns.
+
+(define_insn "call"
+ [(call (match_operand 0 "general_operand" "")
+ (match_operand 1 "general_operand" ""))]
+ ""
+ "")
+
+(define_insn "call_value"
+ [(set (match_operand 0 "" "")
+ (call (match_operand 1 "general_operand" "")
+ (match_operand 2 "general_operand" "")))]
+ ""
+ "")
+
+;; Local variables:
+;; mode:emacs-lisp
+;; comment-start: ";; "
+;; eval: (set-syntax-table (copy-sequence (syntax-table)))
+;; eval: (modify-syntax-entry ?[ "(]")
+;; eval: (modify-syntax-entry ?] ")[")
+;; eval: (modify-syntax-entry ?{ "(}")
+;; eval: (modify-syntax-entry ?} "){")
+;; eval: (setq indent-tabs-mode t)
+;; End:
diff --git a/gcc/config/cil32/cil32.opt b/gcc/config/cil32/cil32.opt
new file mode 100644
index 00000000000..79fdcc0291d
--- /dev/null
+++ b/gcc/config/cil32/cil32.opt
@@ -0,0 +1,53 @@
+; Options for the CIL32 port of the compiler.
+;
+; Copyright (C) 2006 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC 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.
+;
+; GCC 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 GCC; see the file COPYING. If not, write to the Free
+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA.
+;
+; Authors:
+; Andrea Bona
+; Andrea Ornstein
+; Erven Rohou
+; Roberto Costa
+;
+; Contact information at STMicroelectronics:
+; Roberto Costa <roberto.costa@st.com>
+
+mopensystemc
+Target Undocumented Mask(OPENSYSTEMC)
+Use OpenSystem.C Attributes
+
+mnoopensystemc
+Target InverseMask(OPENSYSTEMC)
+Disable use of OpenSystem.C Attributes
+
+mexpand-abs
+Target Mask(EXPAND_ABS)
+Expand abs (absolute value) instead of generating a call to Crt::abs
+
+mexpand-minmax
+Target Mask(EXPAND_MINMAX)
+Expand min and max instead of generating a call to Crt::{min,max}
+
+memit-gimple-comments
+Target Mask(EMIT_GIMPLE_COMMENTS)
+Emits the GIMPLE node as a CIL comment before the CIL sequence
+
+memit-external-assembly
+Target Mask(EMIT_EXTERNAL_ASSEMBLY)
+Emits all external symbols as if defined in an assembly called ExternalAssembly
diff --git a/gcc/config/cil32/gcc4net.cs b/gcc/config/cil32/gcc4net.cs
new file mode 100644
index 00000000000..fff17f545a9
--- /dev/null
+++ b/gcc/config/cil32/gcc4net.cs
@@ -0,0 +1,106 @@
+/* Run-time support required by CIL binaries.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace gcc4net {
+ public unsafe sealed class StartupHelper {
+
+ public unsafe static IntPtr GetArgv(out int argc) {
+ String[] argv = Environment.GetCommandLineArgs();
+ argc = argv.Length;
+ int ptr_size = (int)(sizeof(void*));
+ int size = (argc + 1) * ptr_size;
+ IntPtr res = Marshal.AllocHGlobal(size);
+
+ for (int i=0; i < argc; ++i) {
+ Marshal.WriteIntPtr(res, ptr_size * i,
+ Marshal.StringToHGlobalAnsi(argv[i]));
+ }
+ Marshal.WriteIntPtr(res, ptr_size * argc, IntPtr.Zero);
+
+ return res;
+ }
+
+ public unsafe static void Startup() {
+ Module mainModule;
+ Assembly assembly;
+ Type type;
+
+ // Find the module that contains the "main" function.
+ mainModule = null;
+ assembly = Assembly.GetEntryAssembly();
+ type = assembly.GetType("<Module>");
+ // Invoke the application's ".init" function, if present.
+ MethodInfo initMethod = type.GetMethod(".init");
+ if(initMethod != null)
+ initMethod.Invoke(null, null);
+ }
+
+ public unsafe static void Shutdown(int status) {
+ }
+
+ }
+
+ public sealed class Crt {
+ public static int __minsi3(int a, int b) { return (a<=b) ? a : b; }
+ public static long __minti3(long a, long b) { return (a<=b) ? a : b; }
+ public static uint __uminsi3(uint a, uint b) { return (a<=b) ? a : b; }
+ public static ulong __uminti3(ulong a, ulong b) { return (a<=b) ? a : b; }
+ public static float __minsf3(float a, float b) { return (a<=b) ? a : b; }
+ public static double __mindf3(double a, double b) { return (a<=b) ? a : b; }
+
+ public static int __maxsi3(int a, int b) { return (a>=b) ? a : b; }
+ public static long __maxti3(long a, long b) { return (a>=b) ? a : b; }
+ public static uint __umaxsi3(uint a, uint b) { return (a>=b) ? a : b; }
+ public static ulong __umaxti3(ulong a, ulong b) { return (a>=b) ? a : b; }
+ public static float __maxsf3(float a, float b) { return (a>=b) ? a : b; }
+ public static double __maxdf3(double a, double b) { return (a>=b) ? a : b; }
+
+ public static int __abssi2(int a) { return (a>=0) ? a : -a; }
+ public static long __absti2(long a) { return (a>=0) ? a : -a; }
+ public static float __abssf2(float a) { return (a>=0) ? a : -a; }
+ public static double __absdf2(double a) { return (a>=0) ? a : -a; }
+
+ unsafe public static void memset(void* dest , byte val, int len) {
+ byte* ptr = (byte*)dest;
+ while (len-- > 0)
+ *ptr++ = val;
+ }
+ unsafe public static void memcpy (void* dest, void* src, int len) {
+ byte* d = (byte*)dest;
+ byte* s = (byte*)src;
+ while (len-- > 0)
+ *d++ = *s++;
+ }
+ }
+}
diff --git a/gcc/config/cil32/gen-cil.c b/gcc/config/cil32/gen-cil.c
new file mode 100644
index 00000000000..0f74ce6ac88
--- /dev/null
+++ b/gcc/config/cil32/gen-cil.c
@@ -0,0 +1,3562 @@
+/* Dump of the GENERIC trees in CIL.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "real.h"
+#include "hashtab.h"
+#include "tree-flow.h"
+#include "langhooks.h"
+#include "tree-iterator.h"
+#include "tree-chrec.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "assert.h"
+#include "toplev.h"
+#include "pointer-set.h"
+#include "output.h"
+#include "varray.h"
+#include "ggc.h"
+#include "tree-simp-cil.h"
+#include "gen-cil.h"
+
+/* Nonzero for a type which is at file scope. */
+#define TYPE_FILE_SCOPE_P(EXP) \
+ (! TYPE_CONTEXT (EXP) \
+ || TREE_CODE (TYPE_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL)
+
+struct fnct_attr {
+ const char *assembly_name;
+ const char *cil_name;
+ const char *pinvoke_assembly;
+ const char *pinvoke_fname;
+};
+
+/* Local functions, macros and variables. */
+static void decode_function_attrs (tree, struct fnct_attr *);
+static void mark_var_defs_uses (tree);
+static void remove_stloc_ldloc (block_stmt_iterator, tree *, bool *);
+static void mark_referenced_type (tree);
+static void mark_referenced_string (tree);
+static void dump_decl_name (FILE *, tree);
+static void dump_string_name (FILE *, tree);
+static void dump_label_name (FILE *, tree);
+static void dump_fun_type (FILE *, tree, tree, const char *, bool);
+static void dump_valuetype_name (FILE *, tree);
+static void compute_addr_expr (FILE *, tree);
+static void print_type_suffix (FILE *, tree, tree, bool);
+static void gen_cil_modify_expr (FILE *, tree);
+static char * append_string (char *, const char *,
+ unsigned int *, unsigned int *);
+static char * append_coded_type (char *, tree, unsigned int *, unsigned int *);
+static char * get_md5 (const char *, size_t, size_t *);
+static tree make_valuetype_identifier (tree);
+static void print_valuetype_decl (FILE *, tree);
+static void dump_type (FILE *, tree, bool);
+static void dump_type_promotion (FILE *, tree, bool);
+static void dump_type_promoted_type_def (FILE *, tree, bool);
+static void dump_type_for_builtin (FILE *, tree, bool);
+static void dump_type_eval_mode (FILE *, tree, bool);
+
+static void stack_set (unsigned int) ATTRIBUTE_UNUSED;
+static void stack_reset (void);
+static void stack_push (unsigned int);
+static void stack_pop (unsigned int);
+static void gen_start_function (FILE *);
+static unsigned int gen_cil (void);
+static void gen_cil_1 (FILE *);
+static void gen_cil_node (FILE *, tree);
+static bool gen_cil_gate (void);
+static void create_init_method(tree);
+
+static struct pointer_set_t *defd_vars;
+static struct pointer_set_t *defd_more_than_once_vars;
+static struct pointer_set_t *used_vars;
+static struct pointer_set_t *used_more_than_once_vars;
+static struct pointer_set_t *useless_vars;
+static struct pointer_set_t *referenced_types;
+static GTY(()) varray_type referenced_strings;
+static struct pointer_set_t *referenced_string_ptrs;
+static struct pointer_set_t *referenced_pinvoke;
+static GTY(()) varray_type pending_ctors;
+static unsigned int stack;
+static unsigned int max_stack;
+
+
+/* Recursively mark the definitions and the uses of the non-static
+ non-volatile local variables used in tree NODE. */
+
+static void
+mark_var_defs_uses (tree node)
+{
+ if (node == NULL_TREE)
+ return; /* ER: was spc */
+
+ switch (TREE_CODE (node))
+ {
+ case COND_EXPR:
+ mark_var_defs_uses (COND_EXPR_COND (node));
+ break;
+
+ case SWITCH_EXPR:
+ mark_var_defs_uses (SWITCH_COND (node));
+ break;
+
+ case CALL_EXPR:
+ {
+ tree args = TREE_OPERAND (node, 1);
+
+ mark_var_defs_uses (TREE_OPERAND (node, 0));
+
+ while (args)
+ {
+ mark_var_defs_uses (TREE_VALUE (args));
+ args = TREE_CHAIN (args);
+ }
+ }
+ break;
+
+ case MULT_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case RDIV_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case EXACT_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ mark_var_defs_uses (TREE_OPERAND (node, 0));
+ mark_var_defs_uses (TREE_OPERAND (node, 1));
+ break;
+
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ {
+ tree lhs = TREE_OPERAND (node, 0);
+ tree rhs = TREE_OPERAND (node, 1);
+
+ if (TREE_CODE (lhs) == VAR_DECL)
+ {
+ if (! TREE_ADDRESSABLE (lhs)
+ && ! TREE_STATIC (lhs)
+ && ! TREE_THIS_VOLATILE (lhs)
+ && ! DECL_FILE_SCOPE_P (lhs))
+ {
+ if (!pointer_set_contains (defd_vars, lhs))
+ pointer_set_insert (defd_vars, lhs);
+ else if (!pointer_set_contains (defd_more_than_once_vars, lhs))
+ pointer_set_insert (defd_more_than_once_vars, lhs);
+ }
+ }
+ else
+ mark_var_defs_uses (lhs);
+
+ mark_var_defs_uses (rhs);
+ gcc_assert (TREE_CODE (rhs) != CONSTRUCTOR
+ && TREE_CODE (rhs) != STRING_CST);
+ }
+ break;
+
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case INDIRECT_REF:
+ case BIT_FIELD_REF:
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case ABS_EXPR:
+ case RETURN_EXPR:
+ case WITH_SIZE_EXPR:
+ mark_var_defs_uses (TREE_OPERAND (node, 0));
+ break;
+
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case VECTOR_CST:
+ case PARM_DECL:
+ case FUNCTION_DECL:
+ case LABEL_DECL:
+ case LABEL_EXPR:
+ case GOTO_EXPR:
+ case ASM_EXPR:
+ break;
+
+ case VAR_DECL:
+ if (! TREE_ADDRESSABLE (node)
+ && ! TREE_STATIC (node)
+ && ! TREE_THIS_VOLATILE (node)
+ && ! DECL_FILE_SCOPE_P (node))
+ {
+ if (! pointer_set_contains (used_vars, node))
+ pointer_set_insert (used_vars, node);
+ else if (! pointer_set_contains (used_more_than_once_vars, node))
+ pointer_set_insert (used_more_than_once_vars, node);
+ }
+ break;
+
+ default:
+ fprintf (stderr, "mark_var_defs_uses: Cannot handle ");
+ debug_generic_expr (node);
+ gcc_assert (0);
+ }
+}
+
+/* Avoids couple of useless stloc - ldloc from being emitted by removing
+ non-static non-volatile local variables used exactly once
+ throughout the entire function from tree NODE_PTR.
+ BSI is the statement iterator pointing to the statement containing NODE_PTR.
+ The bool pointed by MOD is set if the function changed anything,
+ otherwise its value is not modified.
+ This function works recursively, looking for VAR_DECLs corresponding
+ to local non-static non-volatile local variables used exactly once
+ in the function.
+ When such a variable is found, if its only definition is in
+ the statement immediately preceding BSI, then the use of the variable is
+ replaced by its definition (and that statement is removed).
+ By doing so, the code exits GIMPLE form; however, the CIL emission
+ mechanism is able to handle such a hybrid GIMPLE representation. */
+
+static void
+remove_stloc_ldloc (block_stmt_iterator bsi, tree *node_ptr, bool *mod)
+{
+ tree node = *node_ptr;
+ block_stmt_iterator prev_bsi;
+
+ if (node == NULL_TREE)
+ return; /* ER: was spc */
+
+ /* Get iterator for the previous statememt */
+ prev_bsi = bsi;
+ bsi_prev (&prev_bsi);
+
+ /* No remotion is possible if the statement is the first in the block */
+ if (bsi_end_p (prev_bsi))
+ return;
+
+ switch (TREE_CODE (node))
+ {
+ case COND_EXPR:
+ remove_stloc_ldloc (bsi, &COND_EXPR_COND (node), mod);
+ break;
+
+ case SWITCH_EXPR:
+ remove_stloc_ldloc (bsi, &SWITCH_COND (node), mod);
+ break;
+
+ case CALL_EXPR:
+ {
+ tree args = TREE_OPERAND (node, 1);
+
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod);
+
+ while (args)
+ {
+ remove_stloc_ldloc (bsi, &TREE_VALUE (args), mod);
+ args = TREE_CHAIN (args);
+ }
+ }
+ break;
+
+ case MULT_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case RDIV_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case EXACT_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod);
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 1), mod);
+ break;
+
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ if (! AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0))))
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 1), mod);
+ gcc_assert (TREE_CODE (TREE_OPERAND (node, 1)) != CONSTRUCTOR
+ && TREE_CODE (TREE_OPERAND (node, 1)) != STRING_CST);
+ break;
+
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case BIT_FIELD_REF:
+ case ABS_EXPR:
+ case RETURN_EXPR:
+ case WITH_SIZE_EXPR:
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod);
+ break;
+
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ if (! AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0))))
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod);
+ break;
+
+ case INDIRECT_REF:
+ if (! AGGREGATE_TYPE_P (TREE_TYPE (node)))
+ remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod);
+ break;
+
+ case VAR_DECL:
+ if (! TREE_ADDRESSABLE (node)
+ && ! TREE_STATIC (node)
+ && ! TREE_THIS_VOLATILE (node)
+ && ! DECL_FILE_SCOPE_P (node))
+ {
+ tree prev_stmt;
+
+ /* Get the previous statement */
+ prev_stmt = bsi_stmt (prev_bsi);
+
+ /* If the variable is used exactly once and the definition
+ is in the previous statement, then remove it */
+ if (TREE_CODE (prev_stmt) == MODIFY_EXPR
+ && TREE_OPERAND (prev_stmt, 0) == node
+ && pointer_set_contains (used_vars, node)
+ && ! pointer_set_contains (used_more_than_once_vars, node))
+ {
+ /* If the definition is unique, set that
+ the variable has become useless. */
+ if (! pointer_set_contains (defd_more_than_once_vars, node))
+ pointer_set_insert (useless_vars, node);
+
+ /* Replace variable's use with the definition */
+ *node_ptr = TREE_OPERAND (prev_stmt, 1);
+
+ /* Remove the previous statement */
+ bsi_remove (&prev_bsi, true);
+
+ /* Set that the function changed something */
+ *mod = true;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+}
+
+
+/* stack_* functions are used to keep track of the number of elements
+ in the evaluation stack, in order to record the maximum number.
+ This is emitted in .maxstack directive for each function. */
+
+/* Set that the evaluation stack contains n elements. */
+
+static void
+stack_set (unsigned int n)
+{
+ stack = n;
+ if (stack > max_stack)
+ max_stack = stack;
+}
+
+/* Set that the evaluation stack is empty. */
+
+static inline void
+stack_reset (void)
+{
+ stack = 0;
+}
+
+/* Add n elements to the evaluation stack. */
+
+static void
+stack_push (unsigned int n)
+{
+ stack += n;
+ if (stack > max_stack)
+ max_stack = stack;
+}
+
+/* Remove n elements from the evaluation stack. */
+
+static inline void
+stack_pop (unsigned int n)
+{
+ gcc_assert (stack >= n);
+ stack -= n;
+}
+
+/* Given the FUNCTION_DECL tree T, decode its CIL-specific function
+ attributes and record them in ATTRS. */
+
+static void
+decode_function_attrs (tree t, struct fnct_attr *attrs)
+{
+ tree tmp;
+
+ gcc_assert (TREE_CODE (t) == FUNCTION_DECL);
+
+ attrs->assembly_name = 0;
+ attrs->cil_name = 0;
+ attrs->pinvoke_assembly = 0;
+ attrs->pinvoke_fname = 0;
+
+ tmp = DECL_ATTRIBUTES (t);
+ while (tmp)
+ {
+ const char *attr_name = IDENTIFIER_POINTER (TREE_PURPOSE (tmp));
+ tree params = TREE_VALUE (tmp);
+
+ if (strcmp (attr_name, "assembly_name") == 0)
+ attrs->assembly_name = TREE_STRING_POINTER (TREE_VALUE (params));
+ else if (strcmp (attr_name, "cil_name") == 0)
+ attrs->cil_name = TREE_STRING_POINTER (TREE_VALUE (params));
+ else if (strcmp (attr_name, "pinvoke") == 0)
+ {
+ attrs->pinvoke_assembly = TREE_STRING_POINTER (TREE_VALUE (params));
+ if (TREE_CHAIN (params))
+ attrs->pinvoke_fname = TREE_STRING_POINTER (TREE_VALUE (TREE_CHAIN (params)));
+ }
+ tmp = TREE_CHAIN (tmp);
+ }
+}
+
+/* Mark the type represented by tree T as referenced.
+ This function works recursively, since types referenced by type T
+ itself are also marked as referenced.
+ Referenced types are emitted at the end of the compilation unit,
+ non-referenced types are not.
+ T must be a type node. */
+
+static void
+mark_referenced_type (tree t)
+{
+ t = TYPE_MAIN_VARIANT (t);
+
+ /* If the type was already referenced, nothing else to do */
+ if (pointer_set_contains (referenced_types, t))
+ return;
+
+ /* Give the aggregate a name unless it has it already */
+ switch (TREE_CODE (t))
+ {
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case ARRAY_TYPE:
+ if (TYPE_NAME (t) == 0)
+ {
+ tree type_decl = build0 (TYPE_DECL, t);
+ DECL_NAME (type_decl) = make_valuetype_identifier (t);
+ TYPE_NAME (t) = type_decl;
+ }
+ break;
+
+ default:
+ /* Nothing to do for the other types */
+ ;
+ }
+
+ /* Transform local-scope types into global-scope types */
+ if (!TYPE_FILE_SCOPE_P (t))
+ {
+ tree type_name = TYPE_NAME (t);
+ const char *orig_name;
+ size_t tmp_name_max_len = 256;
+ size_t tmp_name_len = 0;
+ char *tmp_name;
+ char suffix[32];
+
+ gcc_assert (type_name != 0);
+ gcc_assert (DECL_P (type_name)
+ || TREE_CODE (type_name) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (type_name) == IDENTIFIER_NODE)
+ orig_name = IDENTIFIER_POINTER (type_name);
+ else
+ orig_name = IDENTIFIER_POINTER (DECL_NAME (type_name));
+
+ snprintf (suffix, 31, "?vt%lu", (unsigned long)t);
+
+ tmp_name = (char *)xmalloc (tmp_name_max_len);
+ tmp_name = append_string (tmp_name, orig_name,
+ &tmp_name_len, &tmp_name_max_len);
+ tmp_name = append_string (tmp_name, suffix,
+ &tmp_name_len, &tmp_name_max_len);
+
+ TYPE_NAME (t) = get_identifier_with_length (tmp_name, tmp_name_len);
+ TYPE_CONTEXT (t) = 0;
+ free (tmp_name);
+ }
+
+ switch (TREE_CODE (t))
+ {
+ case ENUMERAL_TYPE:
+ pointer_set_insert (referenced_types, t);
+ break;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ tree tmp;
+
+ pointer_set_insert (referenced_types, t);
+ tmp = TYPE_FIELDS (t);
+
+ while (tmp)
+ {
+ mark_referenced_type (TREE_TYPE (tmp));
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ mark_referenced_type (TREE_TYPE (t));
+ break;
+
+ case ARRAY_TYPE:
+ pointer_set_insert (referenced_types, t);
+ mark_referenced_type (TREE_TYPE (t));
+ break;
+
+ case FUNCTION_TYPE:
+ {
+ tree args_type;
+ mark_referenced_type (TREE_TYPE (t));
+ args_type = TYPE_ARG_TYPES (t);
+ while (args_type)
+ {
+ mark_referenced_type (TREE_VALUE (args_type));
+ args_type = TREE_CHAIN (args_type);
+ }
+ }
+ break;
+
+ default:
+ /* Nothing to do for the other types */
+ ;
+ }
+}
+
+/* Mark the string represented by tree T as referenced.
+ Referenced strings are emitted at the end of the compilation unit,
+ non-referenced strings are not.
+ T must be a STRING_CST node. */
+
+static void
+mark_referenced_string (tree t)
+{
+ gcc_assert (TREE_CODE (t) == STRING_CST);
+ if (!pointer_set_contains (referenced_string_ptrs,
+ (void *)(TREE_STRING_POINTER (t))))
+ {
+ VARRAY_PUSH_TREE (referenced_strings, t);
+ pointer_set_insert (referenced_string_ptrs,
+ (void *)(TREE_STRING_POINTER (t)));
+ mark_referenced_type (TREE_TYPE (t));
+ }
+}
+
+/* Mark the function represented by tree T as a pinvoke.
+ T must be a FUNCTION_DECL node. */
+
+void
+cil_add_pinvoke (tree t)
+{
+ gcc_assert (TREE_CODE (t) == FUNCTION_DECL);
+ pointer_set_insert (referenced_pinvoke, t);
+ mark_referenced_type (TREE_TYPE (t));
+}
+
+/* Dump the name of a _DECL node. */
+
+static void
+dump_decl_name (FILE* file, tree node)
+{
+ gcc_assert (DECL_P (node) || TREE_CODE (node) == IDENTIFIER_NODE);
+ fputs ("'", file);
+
+ if (DECL_ASSEMBLER_NAME_SET_P (node))
+ {
+ fprintf (file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node)));
+ }
+ else if (TREE_CODE (node) == IDENTIFIER_NODE)
+ fprintf (file, IDENTIFIER_POINTER (node));
+ else if (DECL_NAME (node))
+ {
+ mark_decl_referenced (node);
+ fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node)));
+ }
+ else
+ fprintf (file, "?UNNAMED%d", DECL_UID (node));
+
+ fputs ("'", file);
+}
+
+/* Dump the name of a STRING_CST node. */
+
+static void
+dump_string_name (FILE* file, tree node)
+{
+ gcc_assert (TREE_CODE (node) == STRING_CST);
+
+ fprintf (file, "'?string%lu'", (unsigned long)TREE_STRING_POINTER (node));
+}
+
+/* Dump the name of a label. */
+
+static void
+dump_label_name (FILE* file, tree node)
+{
+ /* Always print the label id. */
+ fprintf (file, "?L" HOST_WIDE_INT_PRINT_DEC, LABEL_DECL_UID (node));
+
+ /* For convenience, also print the identifier when available. Note that the
+ identifier alone is incorrect: in case of inlining, several labels can
+ end up with the same id. */
+ if (DECL_NAME (node))
+ {
+ fputs ("_", file);
+ fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node)));
+ }
+}
+
+/* Dump the name of a valuetype.
+ T must be an aggregate type or an enumeral type, since these are
+ the types emitted as CIL valuetypes. */
+
+static void
+dump_valuetype_name (FILE *file, tree t)
+{
+ tree type_name;
+
+ gcc_assert (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == ENUMERAL_TYPE);
+ gcc_assert (TYPE_MAIN_VARIANT (t) == t);
+ gcc_assert (TYPE_FILE_SCOPE_P (t));
+ gcc_assert (TYPE_NAME (t));
+
+ type_name = TYPE_NAME (t);
+ gcc_assert (DECL_P (type_name) || TREE_CODE (type_name) == IDENTIFIER_NODE);
+
+ fputs ("'", file);
+ if (TREE_CODE (type_name) == IDENTIFIER_NODE)
+ fprintf (file, IDENTIFIER_POINTER (type_name));
+ else if (DECL_NAME (type_name))
+ fprintf (file, IDENTIFIER_POINTER (DECL_NAME (type_name)));
+ else
+ fprintf (file, "?UNNAMED%d", DECL_UID (type_name));
+ fputs ("'", file);
+}
+
+/* Dump the signature of function type FUN_TYPE.
+ The function name that is dumped is taken from function_decl FUN
+ or from NAME. Only and exactly one of the two must be non-null.
+ REF tells whether the function type (and the types of the return value
+ and of the incoming parameters) have to be marked as referenced.
+ FUN_TYPE must be a FUNCTION_TYPE.
+ FUN, if not null, must be a FUNCTION_DECL. */
+
+static void
+dump_fun_type (FILE *stream, tree fun_type, tree fun, const char *name, bool ref)
+{
+ tree args_type;
+ tree last_arg_type = NULL;
+ bool varargs = FALSE;
+
+ gcc_assert (! (fun && name));
+
+ mark_referenced_type (fun_type);
+
+ args_type = TYPE_ARG_TYPES (fun_type);
+
+ if (args_type == NULL)
+ warning (0,
+ "Missing function %s prototype, guessing it, you should fix the code",
+ fun?IDENTIFIER_POINTER (DECL_NAME (fun)):"");
+ else
+ {
+ last_arg_type = args_type;
+ while (TREE_CHAIN (last_arg_type))
+ last_arg_type = TREE_CHAIN (last_arg_type);
+
+ if (TREE_VALUE (last_arg_type) != void_type_node)
+ {
+ last_arg_type = NULL;
+ varargs = TRUE;
+ }
+ }
+
+ if (varargs)
+ fputs ("vararg ", stream);
+
+ dump_type (stream, TREE_TYPE (fun_type), ref);
+
+ fputs (" ", stream);
+ if (fun)
+ {
+ struct fnct_attr attrs;
+
+ decode_function_attrs (fun, &attrs);
+
+ if (attrs.assembly_name)
+ fprintf (stream, "[%s]", attrs.assembly_name);
+ else if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (fun))
+ fputs ("[ExternalAssembly]ExternalAssembly::", stream);
+
+ if (attrs.cil_name)
+ fprintf (stream, "%s", attrs.cil_name);
+ else
+ dump_decl_name (stream, fun);
+ }
+
+ if (name)
+ fputs (name, stream);
+
+ fputs ("(", stream);
+
+ while (args_type != last_arg_type)
+ {
+ dump_type (stream, TREE_VALUE (args_type), ref);
+ args_type = TREE_CHAIN (args_type);
+
+ if (args_type != last_arg_type)
+ fputs (", ", stream);
+ }
+
+ if (varargs)
+ fputs (", ...", stream);
+
+ fputs (")", stream);
+}
+
+/* Dump type NODE.
+ REF tells whether the function type (and the types of the return value
+ and of the incoming parameters) have to be marked as referenced.
+ NODE must be a type node. */
+
+static void
+dump_type (FILE *file, tree node, bool ref)
+{
+/* node = TYPE_MAIN_VARIANT (node); */
+
+ if (TYPE_MAIN_VARIANT (node) == va_list_type_node) {
+ fputs ("valuetype [mscorlib]System.ArgIterator", file);
+ return;
+ }
+
+ switch (TREE_CODE (node))
+ {
+ case ENUMERAL_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ node = TYPE_MAIN_VARIANT (node);
+
+ /* Reference the type if told to do so */
+ if (ref)
+ mark_referenced_type (node);
+
+ /* Print the name of the structure. */
+ fputs ("valuetype ", file);
+ dump_valuetype_name (file, node);
+ break;
+
+ case VOID_TYPE:
+ fputs ("void", file);
+ break;
+
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ if (TYPE_UNSIGNED (node))
+ fputs ("unsigned ", file);
+
+ switch (type_size)
+ {
+ case 8: fputs ("int8", file); break;
+ case 16: fputs ("int16", file); break;
+ case 32: fputs ("int32", file); break;
+ case 64: fputs ("int64", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ switch (type_size)
+ {
+ case 32: fputs ("float32", file); break;
+ case 64: fputs ("float64", file); break;
+ default:
+ fprintf (stderr, "Unsupported floating point size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ case BOOLEAN_TYPE:
+ fputs ("int8", file);
+ break;
+
+ case POINTER_TYPE:
+ if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE)
+ {
+ fputs ("method ", file);
+ dump_fun_type (file, TREE_TYPE (node), NULL, " * ", ref);
+ }
+ else
+ {
+ dump_type (file, TREE_TYPE (node), ref);
+ fputs (" *", file);
+ }
+ break;
+
+ case FUNCTION_TYPE:
+/* dump_fun_type (file, node, NULL, NULL, ref); */
+ gcc_assert (0);
+ break;
+
+ case VECTOR_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+ tree innertype = TREE_TYPE (node);
+ enum machine_mode innermode = TYPE_MODE (innertype);
+
+ /* Only expect integer vectors */
+ gcc_assert (GET_MODE_CLASS (innermode) == MODE_INT);
+
+ /* and emit as corresponding same-size integer mode */
+ if (TYPE_UNSIGNED (node))
+ fputs ("unsigned ", file);
+
+ switch (type_size)
+ {
+ case 8: fputs ("int8", file); break;
+ case 16: fputs ("int16", file); break;
+ case 32: fputs ("int32", file); break;
+ case 64: fputs ("int64", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ case COMPLEX_TYPE:
+ case REFERENCE_TYPE:
+
+ default:
+ fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+/* Dump type NODE, promoted following C conventions for var args.
+ REF tells whether the function type (and the types of the return value
+ and of the incoming parameters) have to be marked as referenced.
+ NODE must be a type node. */
+
+static void
+dump_type_promotion (FILE *file, tree node, bool ref)
+{
+
+ switch (TREE_CODE (node))
+ {
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ node = TYPE_MAIN_VARIANT (node);
+
+ /* Reference the type if told to do so */
+ if (ref)
+ mark_referenced_type (node);
+
+ /* Print the name of the structure. */
+ fputs ("valuetype ", file);
+ dump_valuetype_name (file, node);
+ break;
+
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ if (TYPE_UNSIGNED (node))
+ {
+ switch (type_size)
+ {
+ case 8:
+ case 16: fputs ("int32", file); break;
+ case 32: fputs ("unsigned int32", file); break;
+ case 64: fputs ("unsigned int64", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ else
+ {
+ switch (type_size)
+ {
+ case 8:
+ case 16:
+ case 32: fputs ("int32", file); break;
+ case 64: fputs ("int64", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ fputs ("float64", file);
+ break;
+
+ case BOOLEAN_TYPE:
+ fputs ("int32", file);
+ break;
+
+ case POINTER_TYPE:
+ fputs ("native int", file);
+ break;
+
+ default:
+ fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+/* Dump the type def of type NODE, promoted following C conventions
+ for var args.
+ REF tells whether the function type (and the types of the return value
+ and of the incoming parameters) have to be marked as referenced.
+ NODE must be a type node. */
+
+static void
+dump_type_promoted_type_def (FILE *stream, tree node, bool ref)
+{
+ switch (TREE_CODE (node))
+ {
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ node = TYPE_MAIN_VARIANT (node);
+
+ /* Reference the type if told to do so */
+ if (ref)
+ mark_referenced_type (node);
+
+ /* Print the name of the structure. */
+ fputs ("valuetype ", stream);
+ dump_valuetype_name (stream, node);
+ break;
+
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ if (TYPE_UNSIGNED (node))
+ {
+ switch (type_size)
+ {
+ case 8:
+ case 16: fputs ("class [mscorlib]System.Int32", stream); break;
+ case 32: fputs ("class [mscorlib]System.UInt32", stream); break;
+ case 64: fputs ("class [mscorlib]System.UInt64", stream); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ else
+ {
+ switch (type_size)
+ {
+ case 8:
+ case 16:
+ case 32: fputs ("class [mscorlib]System.Int32", stream); break;
+ case 64: fputs ("class [mscorlib]System.Int64", stream); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ fputs ("class [mscorlib]System.Double", stream);
+ break;
+
+ case BOOLEAN_TYPE:
+ fputs ("class [mscorlib]System.Int32", stream);
+ break;
+
+ case POINTER_TYPE:
+ fputs ("class [mscorlib]System.IntPtr", stream);
+ break;
+
+ default:
+ fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+static void
+dump_type_for_builtin (FILE *file, tree node, bool all_types)
+{
+/* node = TYPE_MAIN_VARIANT (node); */
+
+ switch (TREE_CODE (node))
+ {
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ if (TYPE_UNSIGNED (node))
+ fputs ("unsigned ", file);
+
+ switch (type_size)
+ {
+ case 8: if (all_types) { fputs ("int8", file); return; }
+ case 16: if (all_types) { fputs ("int16", file); return; }
+ case 32: fputs ("int32", file); break;
+ case 64: fputs ("int64", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ switch (type_size)
+ {
+ case 32: fputs ("float32", file); break;
+ case 64: fputs ("float64", file); break;
+ default:
+ fprintf (stderr, "Unsupported floating point size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ default:
+ fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+static void
+dump_type_eval_mode (FILE *stream, tree node, bool all_types)
+{
+ switch (TREE_CODE (node))
+ {
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ switch (type_size)
+ {
+ case 8: if (all_types) { fputs ("qi", stream); break; }
+ case 16: if (all_types) { fputs ("hi", stream); break; }
+ case 32: fputs ("si", stream); break;
+ case 64: fputs ("ti", stream); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
+
+ switch (type_size)
+ {
+ case 32: fputs ("sf", stream); break;
+ case 64: fputs ("df", stream); break;
+ default:
+ fprintf (stderr, "Unsupported floating point size %d\n",
+ type_size);
+ gcc_assert (0);
+ }
+ }
+ break;
+
+ default:
+ fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+static void
+compute_addr_expr (FILE *file, tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case STRING_CST:
+ mark_referenced_string (t);
+ fputs ("\n\tldsflda\t", file);
+ dump_type (file, TREE_TYPE (t), true);
+ fputs (" ", file);
+ dump_string_name (file, t);
+ stack_push (1);
+ break;
+
+ case VAR_DECL:
+ if (!DECL_FILE_SCOPE_P (t))
+ fputs ("\n\tldloca\t", file);
+ else
+ {
+ fputs ("\n\tldsflda\t", file);
+ if (COMPLETE_TYPE_P (TREE_TYPE (t)))
+ dump_type (file, TREE_TYPE (t), true);
+ else
+ fputs ("native int", file);
+ fputs (" ", file);
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (t))
+ fputs ("[ExternalAssembly]ExternalAssembly::", file);
+ }
+
+ dump_decl_name (file, t);
+ stack_push (1);
+ break;
+
+ case PARM_DECL:
+ fputs ("\n\tldarga\t", file);
+ dump_decl_name (file, t);
+ stack_push (1);
+ break;
+
+ case FUNCTION_DECL:
+ fputs ("\n\tldftn\t", file);
+ dump_fun_type (file, TREE_TYPE (t), t, NULL, true);
+ stack_push (1);
+ break;
+
+ case INDIRECT_REF:
+ gen_cil_node (file, TREE_OPERAND (t, 0));
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree obj = TREE_OPERAND (t, 0);
+ tree fld = TREE_OPERAND (t, 1);
+ tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj));
+
+ gcc_assert (! DECL_BIT_FIELD (fld));
+
+ compute_addr_expr (file, obj);
+ fputs ("\n\tldflda\t", file);
+ dump_type (file, TREE_TYPE (fld), true);
+ fputs (" ", file);
+ mark_referenced_type (obj_type);
+ dump_valuetype_name (file, obj_type);
+ fputs ("::", file);
+ dump_decl_name (file, fld);
+ }
+ break;
+
+ case BIT_FIELD_REF:
+ {
+ tree obj = TREE_OPERAND (t, 0);
+ unsigned int off = TREE_INT_CST_LOW (TREE_OPERAND (t, 2));
+
+ gcc_assert (off % 8 == 0);
+ compute_addr_expr (file, obj);
+ if (off / 8 > 0)
+ {
+ fprintf (file, "\n\tldc.i4\t%d", off / 8);
+ fputs ("\n\tadd", file);
+ stack_push (1);
+ stack_pop (1);
+ }
+ }
+ break;
+
+ default:
+ fprintf (stderr, "%s: %s\n",
+ __func__, tree_code_name[TREE_CODE (t)]);
+ gcc_assert (0);
+ }
+
+ if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ fputs ("\n\tconv.i", file);
+}
+
+static void
+print_type_suffix (FILE *file, tree type_node, tree conv_in_type, bool unsign)
+{
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (type_node));
+
+ switch (TREE_CODE (type_node))
+ {
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ {
+ bool uns = false;
+
+ if (TYPE_UNSIGNED (type_node)
+ || (conv_in_type != NULL_TREE
+ && TYPE_UNSIGNED (conv_in_type)
+ && type_size > GET_MODE_BITSIZE (TYPE_MODE (conv_in_type))))
+ uns = unsign;
+
+ switch (type_size)
+ {
+ case 8: fputs ((uns)?"u1":"i1", file); break;
+ case 16: fputs ((uns)?"u2":"i2", file); break;
+ case 32: fputs ((uns)?"u4":"i4", file); break;
+ case 64: fputs ((uns)?"u8":"i8", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ break;
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ switch (type_size)
+ {
+ case 32: fputs ("r4", file); break;
+ case 64: fputs ("r8", file); break;
+ default:
+ fprintf (stderr, "Unsupported floating point size %d\n", type_size);
+ gcc_assert (0);
+ break;
+ }
+ break;
+
+ case POINTER_TYPE:
+ fputs ("i", file);
+ break;
+
+ case VECTOR_TYPE:
+ {
+ bool uns = false;
+ tree innertype = TREE_TYPE (type_node);
+ enum machine_mode innermode = TYPE_MODE (innertype);
+
+ /* Only expect integer vectors */
+ gcc_assert (GET_MODE_CLASS (innermode) == MODE_INT);
+
+ /* and then emit as corresponding same-size interger mode */
+ if (TYPE_UNSIGNED (type_node) && unsign)
+ uns = true;
+
+ switch (type_size)
+ {
+ case 8: fputs ((uns)?"u1":"i1", file); break;
+ case 16: fputs ((uns)?"u2":"i2", file); break;
+ case 32: fputs ((uns)?"u4":"i4", file); break;
+ case 64: fputs ((uns)?"u8":"i8", file); break;
+ default:
+ fprintf (stderr, "Unsupported integer size %d\n", type_size);
+ gcc_assert (0);
+ break;
+ }
+ break;
+ }
+
+ default:
+ internal_error ("print_type_suffix %s\n",
+ tree_code_name[TREE_CODE (type_node)]);
+ gcc_assert (0);
+ break;
+ }
+}
+
+/* Dump the node NODE in CIL on the file FILE. */
+static void
+gen_cil_node (FILE *file, tree node)
+{
+ tree op0, op1;
+
+ if (node == NULL_TREE)
+ return; /* ER: was spc */
+
+ if (TARGET_EMIT_GIMPLE_COMMENTS && EXPR_HAS_LOCATION (node))
+ {
+ expanded_location xloc = expand_location (EXPR_LOCATION (node));
+ if (xloc.file)
+ fprintf (file, "\n\t/* [file:%s,line:%d] */", xloc.file, xloc.line);
+ else
+ fprintf (file, "\n\t/* [line:%d] */", xloc.line);
+ }
+
+ switch (TREE_CODE (node))
+ {
+ case INTEGER_CST:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (node)));
+
+ switch (type_size)
+ {
+ case 8:
+ case 16:
+ case 32:
+ fprintf (file, "\n\tldc.i4\t%ld", TREE_INT_CST_LOW (node));
+ break;
+
+ case 64:
+ fprintf (file, "\n\tldc.i8\t%ld", TREE_INT_CST_LOW (node));
+ break;
+
+ default:
+ internal_error ("\nldc: unsupported int size %d\n", type_size);
+ break;
+ }
+ if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE)
+ fputs ("\n\tconv.i", file);
+ stack_push (1);
+ }
+ break;
+
+ case REAL_CST:
+ {
+ REAL_VALUE_TYPE d;
+ tree type_tree;
+ int type_size;
+ enum machine_mode mode;
+ char string[100];
+ /* we have 32 and 64 bit reals, real_to_format fills 32 bits per long */
+ long buf[2];
+
+ d = TREE_REAL_CST (node);
+ type_tree = TREE_TYPE (node);
+ mode = TYPE_MODE (type_tree);
+ real_to_target (buf, &d, mode);
+ real_to_decimal (string, &d, sizeof (string), 5, 1);
+ type_size = GET_MODE_BITSIZE (TYPE_MODE (type_tree));
+
+ switch (type_size)
+ {
+ case 32:
+ fprintf (file, "\n\tldc.r4\tfloat32(%#08lx)", buf[0]);
+ break;
+
+ case 64:
+ fprintf (file, "\n\tldc.r8\tfloat64(%#08lx%08lx)", buf[1], buf[0]);
+ break;
+
+ default:
+ internal_error ("\nldc.r: unsupported float size %d\n", type_size);
+ break;
+ }
+ fprintf (file, " /* %s */", string);
+ stack_push (1);
+ break;
+ }
+
+ case VECTOR_CST:
+ {
+ tree elt;
+ unsigned int val = 0;
+ tree vector_type = TREE_TYPE (node);
+ int vector_bitsize = GET_MODE_BITSIZE (TYPE_MODE (vector_type));
+ tree unit_type = TREE_TYPE (vector_type);
+ int unit_bitsize = GET_MODE_BITSIZE (TYPE_MODE (unit_type));
+
+ /* At this time, support only 32 bit vectors */
+ if (vector_bitsize != 32)
+ internal_error ("\nVECTOR_CST size %d\n", vector_bitsize);
+
+ for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt))
+ {
+ tree elt_val = TREE_VALUE (elt);
+ switch (TREE_CODE (elt_val))
+ {
+ case INTEGER_CST:
+ val = (val << unit_bitsize) | TREE_INT_CST_LOW (elt_val);
+ break;
+
+ default:
+ internal_error ("\nldc: unsupported VECTOR_CST type\n");
+ break;
+ }
+ }
+
+ fprintf (file, "\n\tldc.i4\t%#0x", val);
+ stack_push (1);
+ break;
+ }
+
+ case LABEL_DECL:
+ internal_error ("use dump_label_name instead of gen_cil_node\n");
+ break;
+
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ gen_cil_modify_expr (file, node);
+ break;
+
+ case GOTO_EXPR:
+ fputs ("\n\tbr ", file);
+ dump_label_name (file, GOTO_DESTINATION (node));
+ gcc_assert (stack == 0);
+ break;
+
+ case COND_EXPR:
+ /* At this point, both clauses of COND_EXPR must contain simple gotos */
+ gcc_assert (TREE_CODE (COND_EXPR_THEN (node)) == GOTO_EXPR
+ && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR);
+
+ op0 = COND_EXPR_COND (node);
+ if (TREE_CODE (op0) == LE_EXPR
+ || TREE_CODE (op0) == LT_EXPR
+ || TREE_CODE (op0) == GE_EXPR
+ || TREE_CODE (op0) == GT_EXPR
+ || TREE_CODE (op0) == EQ_EXPR
+ || TREE_CODE (op0) == NE_EXPR)
+
+ {
+ tree op00 = TREE_OPERAND (op0, 0);
+ tree op01 = TREE_OPERAND (op0, 1);
+ bool is_unsigned = TYPE_UNSIGNED (TREE_TYPE (op00));
+ gen_cil_node (file, op00);
+ gen_cil_node (file, op01);
+ switch (TREE_CODE (op0))
+ {
+ case LE_EXPR: fputs ("\n\tble", file); break;
+ case LT_EXPR: fputs ("\n\tblt", file); break;
+ case GE_EXPR: fputs ("\n\tbge", file); break;
+ case GT_EXPR: fputs ("\n\tbgt", file); break;
+ case EQ_EXPR: fputs ("\n\tbeq", file); is_unsigned = FALSE; break;
+ case NE_EXPR: fputs ("\n\tbne", file); is_unsigned = TRUE; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (is_unsigned)
+ fputs (".un\t", file);
+ else
+ fputs ("\t", file);
+ dump_label_name (file, GOTO_DESTINATION (COND_EXPR_THEN (node)));
+ stack_pop (2);
+ }
+ else
+ {
+ gen_cil_node (file, op0);
+ fputs ("\n\tldc.i4.0"
+ "\n\tbne.un\t", file);
+ dump_label_name (file, GOTO_DESTINATION (COND_EXPR_THEN (node)));
+ stack_push (1);
+ stack_pop (2);
+ }
+
+ fputs ("\n\tbr\t", file);
+ dump_label_name (file, GOTO_DESTINATION (COND_EXPR_ELSE (node)));
+ gcc_assert (stack == 0);
+ break;
+
+ case SWITCH_EXPR:
+ {
+ tree vec = SWITCH_LABELS (node);
+ unsigned int vec_len, i;
+ bool first_case = true;
+ tree min_val = 0, max_val = 0;
+ double_int max_min_diff;
+ unsigned int switch_n;
+ tree default_label;
+ tree *labels;
+
+ /* The switch body is lowered in gimplify.c, we should never have
+ switches with a non-NULL SWITCH_BODY here. */
+ gcc_assert (vec && !SWITCH_BODY (node));
+ vec_len = TREE_VEC_LENGTH (vec);
+
+ /* Compute range of cases */
+ for (i = 0; i < vec_len - 1 ; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ tree low = CASE_LOW (elt);
+ tree high = CASE_HIGH (elt);
+
+ if (!high)
+ high = low;
+
+ gcc_assert (low && high);
+
+ /* Discard empty ranges. */
+ if (INT_CST_LT (high, low))
+ continue;
+
+ if (first_case)
+ {
+ min_val = low;
+ max_val = high;
+ first_case = false;
+ }
+ else
+ {
+ if (INT_CST_LT (low, min_val))
+ min_val = low;
+
+ if (INT_CST_LT (max_val, high))
+ max_val = high;
+ }
+ }
+ gcc_assert (!INT_CST_LT (max_val, min_val));
+
+ /* Get the default label */
+ gcc_assert (!CASE_HIGH (TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec)- 1)));
+ gcc_assert (!CASE_LOW (TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec) - 1)));
+ default_label = CASE_LABEL (TREE_VEC_ELT (vec,
+ TREE_VEC_LENGTH (vec) - 1));
+
+ /* Prepare a table with the label for each value of the condition */
+ max_min_diff = double_int_add (double_int_neg (TREE_INT_CST (min_val)),
+ TREE_INT_CST (max_val));
+ gcc_assert (max_min_diff.high == 0 && max_min_diff.low < 8192);
+ switch_n = max_min_diff.low + 1;
+ gcc_assert (switch_n > 0);
+ labels = (tree*)xmalloc (switch_n * sizeof (tree));
+
+ for (i=0 ; i < switch_n; ++i)
+ labels[i] = default_label;
+
+ for (i = 0; i < vec_len - 1 ; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ tree low = CASE_LOW (elt);
+ tree high = CASE_HIGH (elt);
+ double_int low_val, high_val, end, j;
+ double_int minus_min_val = double_int_neg (TREE_INT_CST (min_val));
+
+ if (!high)
+ high = low;
+
+ gcc_assert (low && high);
+
+ /* Discard empty ranges. */
+ if (INT_CST_LT (high, low))
+ continue;
+
+ low_val = TREE_INT_CST (low);
+ high_val = TREE_INT_CST (high);
+ end = double_int_add (high_val, double_int_one);
+
+ for (j = low_val;
+ !double_int_equal_p (j, end);
+ j = double_int_add (j, double_int_one)
+ )
+ {
+ double_int norm_j = double_int_add (j, minus_min_val);
+
+ gcc_assert (norm_j.high == 0 && norm_j.low < 8192);
+ labels[norm_j.low] = CASE_LABEL (elt);
+ }
+ }
+
+ /* Emit switch condition */
+ gen_cil_node (file, SWITCH_COND (node));
+
+ /* Emit subtraction to normalize the condition */
+ if (!double_int_equal_p (TREE_INT_CST (min_val), double_int_zero))
+ {
+ double_int min = TREE_INT_CST (min_val);
+
+ fputs ("\n\tldc.i4\t", file);
+
+ if (double_int_negative_p (min))
+ {
+ dump_double_int (file, double_int_neg (min), false);
+ fputs ("\n\tadd", file);
+ }
+ else
+ {
+ dump_double_int (file, min, false);
+ fputs ("\n\tsub", file);
+ }
+
+ stack_push (1);
+ stack_pop (1);
+ }
+
+ /* Emit switch instruction */
+ fputs ("\n\tswitch\t(", file);
+ for (i=0 ; i < switch_n; ++i)
+ {
+ dump_label_name (file, labels[i]);
+ if (i < switch_n - 1)
+ fputs (", ", file);
+ }
+ fputs (")", file);
+ stack_pop (1);
+
+ /* Emit branch for default label */
+ fputs ("\n\tbr\t", file);
+ dump_label_name (file, default_label);
+ gcc_assert (stack == 0);
+ }
+ break;
+
+ case CALL_EXPR:
+ {
+ tree fun_expr = TREE_OPERAND (node, 0);
+ tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr));
+ bool direct_call = (TREE_CODE (fun_expr) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fun_expr, 0)) == FUNCTION_DECL);
+ tree args;
+ tree args_type;
+ tree last_arg_type;
+ bool varargs;
+ unsigned int nargs = 0;
+ tree dfun = 0;
+
+ if (direct_call)
+ dfun = TREE_OPERAND (fun_expr, 0);
+
+ /* Built-in functions must be handled in a special way */
+ if (dfun && DECL_BUILT_IN (dfun))
+ {
+ bool done = false;
+ gcc_assert (direct_call);
+
+ if (DECL_BUILT_IN_CLASS (dfun) == BUILT_IN_MD)
+ {
+ switch (DECL_FUNCTION_CODE (dfun))
+ {
+ case CIL32_BUILTIN_VA_ARG:
+ {
+ tree args = TREE_OPERAND (node, 1);
+ tree va = TREE_VALUE (args);
+ tree dummy = TREE_VALUE (TREE_CHAIN (args));
+ tree type = TREE_TYPE (TREE_TYPE (dummy));
+
+ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (va)) == va_list_type_node);
+ compute_addr_expr (file, va);
+ fputs ("\n\tcall\tinstance typedref [mscorlib]System.ArgIterator::GetNextArg()"
+ "\n\trefanyval ",
+ file);
+
+ dump_type_promoted_type_def (file, type, true);
+ done = true;
+ }
+ break;
+
+ default:
+ gcc_assert (0);
+ }
+ }
+ else
+ {
+ switch (DECL_FUNCTION_CODE (dfun))
+ {
+ case BUILT_IN_VA_START:
+ {
+ tree va = TREE_VALUE (TREE_OPERAND (node, 1));
+
+ /* A lowering phase should have checked that va
+ has no side effects. */
+ gcc_assert (! TREE_SIDE_EFFECTS (va));
+
+ gcc_assert (TREE_CODE (va) == ADDR_EXPR);
+ compute_addr_expr (file, TREE_OPERAND (va, 0));
+ fputs ("\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator",
+ file);
+
+ stack_pop (1);
+
+ compute_addr_expr (file, TREE_OPERAND (va, 0));
+ fputs ("\n\targlist"
+ "\n\tcall\tinstance void "
+ "[mscorlib]System.ArgIterator::.ctor(valuetype "
+ "[mscorlib]System.RuntimeArgumentHandle)",
+ file);
+
+ stack_push (1);
+ stack_pop (2);
+ done = true;
+ }
+ break;
+
+ case BUILT_IN_VA_END:
+ {
+ tree va = TREE_VALUE (TREE_OPERAND (node, 1));
+
+ gcc_assert (TREE_CODE (va) == ADDR_EXPR);
+ compute_addr_expr (file, TREE_OPERAND (va, 0));
+ fputs ("\n\tcall\tinstance void [mscorlib]System.ArgIterator::End()",
+ file);
+
+ stack_pop (1);
+ done = true;
+ }
+ break;
+
+ case BUILT_IN_VA_COPY:
+ {
+ tree args = TREE_OPERAND (node, 1);
+ tree va_dest = TREE_VALUE (args);
+ tree va_src = TREE_VALUE (TREE_CHAIN (args));
+
+ gen_cil_node (file, va_src);
+
+ /* A lowering phase should have checked that the destination
+ in va_copy is a local variable. */
+ gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR);
+ gcc_assert (TREE_CODE (TREE_OPERAND (va_dest, 0)) == VAR_DECL
+ && !DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0)));
+ fputs ("\n\tstloc\t", file);
+ dump_decl_name (file, TREE_OPERAND (va_dest, 0));
+
+ stack_pop (1);
+ done = true;
+ }
+ break;
+
+ case BUILT_IN_MEMSET:
+ {
+ tree args = TREE_OPERAND (node, 1);
+
+ tree ptr = TREE_VALUE (args);
+ tree value = TREE_VALUE (TREE_CHAIN (args));
+ tree size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+
+ gen_cil_node (file, ptr);
+ fputs ("\n\tdup", file);
+ stack_push (1);
+
+ gen_cil_node (file, value);
+ gen_cil_node (file, size);
+
+ fputs ("\n\tunaligned. 1"
+ "\n\tinitblk", file);
+ stack_pop (3);
+ done = true;
+ }
+ break;
+
+ case BUILT_IN_MEMCPY:
+ {
+ tree args = TREE_OPERAND (node, 1);
+
+ tree ptr_dst = TREE_VALUE (args);
+ tree ptr_src = TREE_VALUE (TREE_CHAIN (args));
+ tree size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+
+ gen_cil_node (file, ptr_dst);
+ fputs ("\n\tdup", file);
+ stack_push (1);
+
+ gen_cil_node (file, ptr_src);
+ gen_cil_node (file, size);
+
+ fputs ("\n\tunaligned. 1"
+ "\n\tcpblk", file);
+ stack_pop (3);
+ done = true;
+ }
+ break;
+
+ case BUILT_IN_ALLOCA:
+ {
+ tree args = TREE_OPERAND (node, 1);
+ tree size = TREE_VALUE (args);
+
+ gen_cil_node (file, size);
+ fputs ("\n\tlocalloc", file);
+
+ done = true;
+ }
+ break;
+
+ default:
+ if (DECL_ASSEMBLER_NAME_SET_P (node))
+ {
+ /* Go Ahead as a normal function call */
+ }
+/* else */
+/* { */
+/* fprintf (stderr, */
+/* "unsupported builtin: %s\n", */
+/* IDENTIFIER_POINTER (DECL_NAME (dfun))); */
+/* gcc_assert (0); */
+/* } */
+ }
+ }
+
+ if (done)
+ break;
+ }
+
+ /* Print parameters. */
+ args = TREE_OPERAND (node, 1);
+ while (args)
+ {
+ gen_cil_node (file, TREE_VALUE (args));
+ args = TREE_CHAIN (args);
+ }
+
+ /* Print function pointer, in case of indirect call */
+ if (!direct_call)
+ gen_cil_node (file, fun_expr);
+
+#if 0
+ op1 = TREE_OPERAND (node, 2);
+ if (op1)
+ {
+ gcc_assert (0);
+ fprintf (file, " [static-chain: ");
+ gen_cil_node (file, op1);
+ fprintf (file, "%c", ']');
+ }
+
+ if (0 && CALL_EXPR_RETURN_SLOT_OPT (node))
+ fprintf (file, " [return slot optimization]");
+#endif
+
+ fprintf (file, "\n\t");
+#if 0
+ if (CALL_EXPR_TAILCALL (node))
+ fprintf (file, "tail.");
+#endif
+ if (direct_call)
+ fputs ("call\t", file);
+ else
+ fputs ("calli\t", file);
+
+ args_type = TYPE_ARG_TYPES (fun_type);
+ last_arg_type = 0;
+ varargs = FALSE;
+
+ if (args_type == NULL)
+ {
+ if (direct_call)
+ warning (0,
+ "Missing function %s prototype, guessing it, "
+ "you should fix the code",
+ IDENTIFIER_POINTER (DECL_NAME (dfun)));
+ else
+ warning (0,
+ "Missing indirect function prototype, guessing it, "
+ "you should fix the code");
+ }
+
+ else
+ {
+ last_arg_type = args_type;
+
+ while (TREE_CHAIN (last_arg_type))
+ last_arg_type = TREE_CHAIN (last_arg_type);
+
+ if (TREE_VALUE (last_arg_type) != void_type_node)
+ {
+ last_arg_type = 0;
+ varargs = TRUE;
+ }
+ }
+
+ if (varargs)
+ fputs ("vararg ", file);
+
+ dump_type (file, TREE_TYPE (fun_type), true);
+
+ if (direct_call)
+ {
+ struct fnct_attr attrs;
+ decode_function_attrs (dfun, &attrs);
+
+ fputs (" ", file);
+
+ if (attrs.assembly_name)
+ fprintf (file, "[%s]", attrs.assembly_name);
+ else if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (dfun))
+ fputs ("[ExternalAssembly]ExternalAssembly::", file);
+
+ if (attrs.cil_name)
+ fprintf (file, "%s", attrs.cil_name);
+ else
+ dump_decl_name (file, dfun);
+ }
+
+ fputs (" (", file);
+ args = TREE_OPERAND (node, 1);
+
+ while (args_type != last_arg_type)
+ {
+ ++nargs;
+ dump_type (file, TREE_VALUE (args_type), true);
+ args = TREE_CHAIN (args);
+ args_type = TREE_CHAIN (args_type);
+ if (args_type != last_arg_type)
+ fputs (", ", file);
+ }
+
+ if (varargs && args)
+ fputs (", ..., ", file);
+
+ while (args)
+ {
+ ++nargs;
+ dump_type_promotion (file, TREE_TYPE (TREE_VALUE (args)), true);
+ args = TREE_CHAIN (args);
+ if (args)
+ fputs (", ", file);
+ }
+
+ fputs (")", file);
+
+ if (direct_call)
+ stack_pop (nargs);
+ else
+ stack_pop (nargs + 1);
+
+ if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE)
+ stack_push (1);
+
+ break;
+ }
+
+ case MULT_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case RDIV_EXPR:
+ case LSHIFT_EXPR:
+ case BIT_XOR_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case MULT_EXPR: fputs ("\n\tmul", file); break;
+ case PLUS_EXPR: fputs ("\n\tadd", file); break;
+ case MINUS_EXPR: fputs ("\n\tsub", file); break;
+ case RDIV_EXPR: fputs ("\n\tdiv", file); break;
+ case LSHIFT_EXPR: fputs ("\n\tshl", file); break;
+ case BIT_XOR_EXPR: fputs ("\n\txor", file); break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Values smaller than 32-bits are represented as 32-bit
+ on the evaluation stack, therefore an explicit conversion
+ is required. */
+ if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) < 32)
+ {
+ fputs ("\n\tconv.", file);
+ print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true);
+ }
+
+ stack_pop (1);
+ break;
+
+ case BIT_IOR_EXPR:
+ case BIT_AND_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case BIT_IOR_EXPR: fputs ("\n\tor", file); break;
+ case BIT_AND_EXPR: fputs ("\n\tand", file); break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* No need for conversions even in case of values smaller
+ than 32-bits, since for these operations the output is
+ always less or equal than both operands. */
+
+ stack_pop (1);
+ break;
+
+ case LT_EXPR:
+ case GT_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case LT_EXPR:
+ fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tclt.un":"\n\tclt", file);
+ break;
+
+ case GT_EXPR:
+ fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tcgt.un":"\n\tcgt", file);
+ break;
+
+ case EQ_EXPR: fputs ("\n\tceq", file); break;
+ case NE_EXPR: fputs ("\n\tceq"
+ "\n\tldc.i4.1"
+ "\n\txor", file); break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) == 64)
+ fputs ("\n\tconv.i8", file);
+
+ stack_pop (1);
+ break;
+
+
+ case LE_EXPR:
+ case GE_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case LE_EXPR:
+ fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tcgt.un":"\n\tcgt", file);
+ break;
+
+ case GE_EXPR:
+ fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tclt.un":"\n\tclt", file);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ fputs ("\n\tldc.i4.1"
+ "\n\txor", file);
+
+ if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) == 64)
+ fputs ("\n\tconv.i8", file);
+
+ stack_pop (1);
+ break;
+
+ case EXACT_DIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case RSHIFT_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case EXACT_DIV_EXPR:
+ case TRUNC_DIV_EXPR: fputs ("\n\tdiv", file); break;
+ case TRUNC_MOD_EXPR: fputs ("\n\trem", file); break;
+ case RSHIFT_EXPR: fputs ("\n\tshr", file); break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (TYPE_UNSIGNED (TREE_TYPE (node)))
+ fputs (".un", file);
+
+ /* No need for conversions even in case of values smaller
+ than 32-bits, since for these operations the output is
+ always less or equal than both operands. */
+
+ stack_pop (1);
+ break;
+
+ case FLOOR_DIV_EXPR:
+ {
+ bool is_signed0, is_signed1;
+
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ is_signed0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+ is_signed1 = TYPE_UNSIGNED (TREE_TYPE (op1));
+ /* If both operands are unsigned, the result is positive and thus
+ rounding towards zero is identical to towards -infinity. */
+ if (is_signed0 && is_signed1)
+ {
+ fputs ("\n\tdiv.un", file);
+ }
+ else
+ {
+ fputs ("\n\tcall\t int32 [gcc4net]gcc4net.Crt::floordiv(", file);
+ dump_type_for_builtin (file, TREE_TYPE (op0), true);
+ fputs (", ", file);
+ dump_type_for_builtin (file, TREE_TYPE (op1), true);
+ fputs (")", file);
+ }
+
+ /* No need for conversions even in case of values smaller
+ than 32-bits, since for this operation the output is
+ always less or equal than both operands. */
+
+ stack_pop (1);
+ break;
+ }
+
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ gen_cil_node (file, TREE_OPERAND (node, 0));
+
+ switch (TREE_CODE (node))
+ {
+ case NEGATE_EXPR: fputs ("\n\tneg", file); break;
+ case BIT_NOT_EXPR: fputs ("\n\tnot", file); break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Values smaller than 32-bits are represented as 32-bit
+ on the evaluation stack, therefore an explicit conversion
+ is required.
+ Unfortunately this is true for the negation as well just
+ for the case in which the operand is the smallest negative value.
+ Example: 8-bit negation of -128 gives 0 and not 128. */
+ if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) < 32)
+ {
+ fputs ("\n\tconv.", file);
+ print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true);
+ }
+
+ break;
+
+ case INDIRECT_REF:
+ case BIT_FIELD_REF:
+ compute_addr_expr (file, node);
+ fputs ("\n\tldind.", file);
+ print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true);
+ break;
+
+ case CONVERT_EXPR:
+ /* ER: if flag_trapv is set, we could generate the .ovf version? */
+ /* TODO: */
+ gen_cil_node (file, TREE_OPERAND (node, 0));
+ fputs ("\n\tconv.", file);
+ print_type_suffix (file, TREE_TYPE (node), TREE_TYPE (TREE_OPERAND (node, 0)), true);
+ break;
+
+ case NOP_EXPR:
+ {
+ enum tree_code out_type_code = TREE_CODE (TREE_TYPE (node));
+
+ gen_cil_node (file, TREE_OPERAND (node, 0));
+
+ if (out_type_code == INTEGER_TYPE
+ || out_type_code == ENUMERAL_TYPE
+ || out_type_code == REAL_TYPE
+ || out_type_code == POINTER_TYPE)
+ {
+ fputs ("\n\tconv.", file);
+ print_type_suffix (file, TREE_TYPE (node),
+ TREE_TYPE (TREE_OPERAND (node, 0)), true);
+ }
+ }
+ break;
+
+ case LABEL_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ /* If this is for break or continue, don't bother printing it. */
+ if (DECL_NAME (op0))
+ {
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (op0));
+ if (strcmp (name, "break") == 0
+ || strcmp (name, "continue") == 0)
+ break;
+ }
+ fprintf (file, "\n");
+ dump_label_name (file, op0);
+ fprintf (file, ":");
+
+ if (DECL_NONLOCAL (op0))
+ fprintf (file, " [non-local]");
+
+ break;
+
+ case RETURN_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ if (op0)
+ {
+/* dump_generic_node (file, op0); */
+ if (TREE_CODE (op0) == MODIFY_EXPR)
+ gen_cil_node (file, TREE_OPERAND (op0, 1));
+ else
+ gen_cil_node (file, op0);
+ }
+
+ /* Pre-C99 code may contain void-returns for non-void functions,
+ but the simplification pass should already have avoided this. */
+ gcc_assert (op0
+ || TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl)))
+ == VOID_TYPE);
+
+ fputs ("\n\tret", file);
+ stack_reset ();
+ break;
+
+ case ASM_EXPR:
+ {
+ /* support just a simple string, no input/output/clober */
+ tree asm_string = ASM_STRING (node);
+ const char *str = TREE_STRING_POINTER (asm_string);
+
+ fputs ("\n\t", file);
+ fputs (str, file);
+ break;
+ }
+
+ case MIN_EXPR:
+ case MAX_EXPR:
+ {
+ tree node_type = TREE_TYPE (node);
+
+ gcc_assert (!TARGET_EXPAND_MINMAX);
+
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ gen_cil_node (file, op1);
+
+ /* emit a call */
+ fputs ("\n\tcall\t", file);
+ dump_type_for_builtin (file, node_type, false);
+ fputs (" [gcc4net]gcc4net.Crt::__", file);
+
+ if (TYPE_UNSIGNED (node_type))
+ fputs ("u", file);
+
+ if (TREE_CODE (node) == MIN_EXPR)
+ fputs ("min", file);
+ else
+ fputs ("max", file);
+
+ dump_type_eval_mode (file, node_type, false);
+ fputs ("3(", file);
+ dump_type_for_builtin (file, TREE_TYPE (op0), false);
+ fputs (", ", file);
+ dump_type_for_builtin (file, TREE_TYPE (op1), false);
+ fputs (")", file);
+ stack_pop (1);
+ }
+ break;
+
+ case ABS_EXPR:
+ {
+ tree node_type = TREE_TYPE (node);
+
+ gcc_assert (!TARGET_EXPAND_ABS);
+
+ op0 = TREE_OPERAND (node, 0);
+ gen_cil_node (file, op0);
+
+ /* emit a call */
+ fputs ("\n\tcall\t", file);
+ dump_type_for_builtin (file, node_type, false);
+ fputs (" [gcc4net]gcc4net.Crt::__abs", file);
+ dump_type_eval_mode (file, node_type, false);
+ fputs ("2(", file);
+ dump_type_for_builtin (file, TREE_TYPE (op0), false);
+ fputs (")", file);
+ }
+ break;
+
+ case SSA_NAME:
+ gcc_assert (0);
+ break;
+
+ case VAR_DECL:
+ mark_referenced_type (TREE_TYPE (node));
+
+ if (!DECL_FILE_SCOPE_P (node))
+ fputs ("\n\tldloc\t", file);
+ else
+ {
+ fputs ("\n\tldsfld\t", file);
+ dump_type (file, TREE_TYPE (node), true);
+ fputs (" ", file);
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (node))
+ fputs ("[ExternalAssembly]ExternalAssembly::", file);
+ }
+
+ dump_decl_name (file, node);
+ stack_push (1);
+ break;
+
+ case PARM_DECL:
+ mark_referenced_type (TREE_TYPE (node));
+ fputs ("\n\tldarg\t", file);
+ dump_decl_name (file, node);
+ stack_push (1);
+ break;
+
+ case FIELD_DECL:
+ case NAMESPACE_DECL:
+ fprintf (stderr, "CIL: Cannot handle FIELD_DECL or NAMESPACE_DECL: ");
+ dump_decl_name (stderr, node);
+ gcc_assert (0);
+ break;
+
+ case TREE_LIST:
+ gcc_assert (0);
+ break;
+
+ case FUNCTION_DECL:
+ case CONST_DECL:
+ gcc_assert (0);
+ break;
+
+ case ADDR_EXPR:
+ compute_addr_expr (file, TREE_OPERAND (node, 0));
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree obj = TREE_OPERAND (node, 0);
+ tree fld = TREE_OPERAND (node, 1);
+ tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj));
+ tree fld_type = TREE_TYPE (fld);
+
+ gcc_assert (TREE_CODE (fld) == FIELD_DECL);
+ gcc_assert (! DECL_BIT_FIELD (fld));
+
+ compute_addr_expr (file, obj);
+ fputs ("\n\tldfld\t", file);
+ dump_type (file, fld_type, true);
+ fputs (" ", file);
+ mark_referenced_type (obj_type);
+ dump_valuetype_name (file, obj_type);
+ fputs ("::", file);
+ dump_decl_name (file, fld);
+ }
+ break;
+
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ gen_cil_node (file, TREE_OPERAND (node, 0));
+ fputs ("\n\tconv.", file);
+ print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true);
+ break;
+
+ case TRUTH_NOT_EXPR:
+ gen_cil_node (file, TREE_OPERAND (node, 0));
+ fputs ("\n\tldc.i4.0"
+ "\n\tceq", file);
+ stack_push (1);
+ stack_pop (1);
+ break;
+
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gen_cil_node (file, op0);
+ if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE)
+ {
+ fputs ("\n\tldc.i4.0"
+ "\n\tceq"
+ "\n\tldc.i4.1"
+ "\n\txor", file);
+ stack_push (1);
+ stack_pop (1);
+ }
+
+ gen_cil_node (file, op1);
+ if (TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE)
+ {
+ fputs ("\n\tldc.i4.0"
+ "\n\tceq"
+ "\n\tldc.i4.1"
+ "\n\txor", file);
+ stack_push (1);
+ stack_pop (1);
+ }
+
+ if (TREE_CODE (node) == TRUTH_AND_EXPR)
+ fputs ("\n\tand", file);
+ else if (TREE_CODE (node) == TRUTH_OR_EXPR)
+ fputs ("\n\tor", file);
+ else
+ fputs ("\n\txor"
+ "\n\tldc.i4.1"
+ "\n\tand", file);
+ stack_pop (1);
+ break;
+
+ case ENUMERAL_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case VECTOR_TYPE:
+ case BOOLEAN_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ internal_error ("gen_cil_node does not support TYPE nodes,"
+ " to dump Type name use dump_type.\n");
+ break;
+
+ default:
+ internal_error ("\n\nUnsupported tree in CIL generation: '%s'\n",
+ tree_code_name[TREE_CODE (node)]);
+ break;
+ }
+}
+
+static void
+gen_cil_modify_expr (FILE *file, tree node)
+{
+ tree lhs = TREE_OPERAND (node, 0);
+ tree rhs = TREE_OPERAND (node, 1);
+
+ if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
+ && (TREE_CODE (lhs) == INDIRECT_REF || TREE_CODE (rhs) == INDIRECT_REF))
+ {
+ gcc_assert (AGGREGATE_TYPE_P (TREE_TYPE (lhs)));
+ compute_addr_expr (file, lhs);
+ compute_addr_expr (file, rhs);
+ fprintf (file, "\n\tldc.i4\t%lu",
+ TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (rhs))));
+ fputs ("\n\tcall\tvoid [gcc4net]gcc4net.Crt::memcpy(void*, void*, int32)",file);
+ stack_push (1);
+ stack_pop (3);
+ return;
+ }
+
+ switch (TREE_CODE (lhs))
+ {
+ case SSA_NAME:
+ gcc_assert (0);
+ break;
+
+ case INDIRECT_REF:
+ compute_addr_expr (file, lhs);
+ gen_cil_node (file, rhs);
+ fputs ("\n\tstind.", file);
+ print_type_suffix (file, TREE_TYPE (lhs), NULL_TREE, false);
+ stack_pop (2);
+ break;
+
+ case VAR_DECL:
+ mark_referenced_type (TREE_TYPE (lhs));
+ gen_cil_node (file, rhs);
+
+ if (!DECL_FILE_SCOPE_P (lhs))
+ fputs ("\n\tstloc\t", file);
+ else
+ {
+ fputs ("\n\tstsfld\t", file);
+ dump_type (file, TREE_TYPE (lhs), true);
+ fputs (" ", file);
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (lhs))
+ fputs ("[ExternalAssembly]ExternalAssembly::", file);
+ }
+ dump_decl_name (file, lhs);
+
+ stack_pop (1);
+ break;
+
+ case PARM_DECL:
+ gen_cil_node (file, rhs);
+ fputs ("\n\tstarg\t", file);
+ dump_decl_name (file, lhs);
+ stack_pop (1);
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree obj = TREE_OPERAND (lhs, 0);
+ tree fld = TREE_OPERAND (lhs, 1);
+ tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj));
+ tree fld_type = TREE_TYPE (fld);
+
+ gcc_assert (TREE_CODE (fld) == FIELD_DECL);
+ gcc_assert (! DECL_BIT_FIELD (fld));
+
+ compute_addr_expr (file, obj);
+ gen_cil_node (file, rhs);
+ mark_referenced_type (obj_type);
+ fputs ("\n\tstfld\t", file);
+ dump_type (file, fld_type, true);
+ fputs (" ", file);
+ dump_valuetype_name (file, obj_type);
+ fputs ("::", file);
+ dump_decl_name (file, fld);
+ stack_pop (2);
+ }
+ break;
+
+ default:
+/* { */
+/* fprintf (stderr, "  LHS  "); */
+/* gen_cil_node (file, lhs); */
+/* break; */
+/* } */
+ fprintf (stderr, "CIL: Cannot handle lhs: ");
+ debug_generic_expr (lhs);
+ gcc_assert (0);
+ }
+}
+
+/* Warning: these strings are not null-terminated */
+static char *
+append_string (char *str, const char *to_append,
+ unsigned int *len, unsigned int *max_len)
+{
+ size_t i, orig_len = *len;
+ size_t append_len = strlen (to_append);
+
+ *len += append_len;
+
+ if (*len > *max_len)
+ {
+ while (*len > *max_len)
+ *max_len *= 2;
+ str = (char *)xrealloc (str, *max_len);
+ }
+
+ for (i=0; i < append_len; ++i)
+ str[orig_len + i] = to_append[i];
+
+ return str;
+}
+
+/* Warning: these strings are not null-terminated */
+static char *
+append_coded_type (char *str, tree type,
+ unsigned int *len, unsigned int *max_len)
+{
+ encode_type:
+ type = TYPE_MAIN_VARIANT (type);
+
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (type));
+ char tmp_str[8] = "UI";
+ char *tmp_str_ptr = tmp_str;
+
+ snprintf (tmp_str_ptr + 2, 6, "%d", type_size);
+
+ if (!TYPE_UNSIGNED (type))
+ ++tmp_str_ptr;
+
+ str = append_string (str, tmp_str_ptr, len, max_len);
+ }
+ break;
+
+ case REAL_TYPE:
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (type));
+ char tmp_str[4] = "F";
+
+ snprintf (tmp_str + 1, 3, "%d", type_size);
+
+ str = append_string (str, tmp_str, len, max_len);
+ }
+ break;
+
+ case POINTER_TYPE:
+ str = append_string (str, "*", len, max_len);
+ type = TREE_TYPE (type);
+ goto encode_type;
+
+ case ARRAY_TYPE:
+ str = append_string (str, "[", len, max_len);
+ if (TYPE_DOMAIN (type))
+ {
+ tree domain = TYPE_DOMAIN (type);
+ tree min = TYPE_MIN_VALUE (domain);
+ tree max = TYPE_MAX_VALUE (domain);
+
+ if (min && max
+ && integer_zerop (min)
+ && host_integerp (max, 0))
+ {
+ unsigned int size = TREE_INT_CST_LOW (max) + 1;
+ char tmp_str[32];
+
+ snprintf (tmp_str, 32, "%d", size);
+ str = append_string (str, tmp_str, len, max_len);
+ }
+ else
+ str = append_string (str, "unk", len, max_len);
+ }
+ str = append_string (str, "]", len, max_len);
+ type = TREE_TYPE (type);
+ goto encode_type;
+
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ const char *prefix;
+ const char *type_str;
+ tree type_name;
+
+ /* Give the aggregate a name unless it has it already */
+ if (TYPE_NAME (type) == 0)
+ {
+ tree type_decl = build0 (TYPE_DECL, type);
+ DECL_NAME (type_decl) = make_valuetype_identifier (type);
+ TYPE_NAME (type) = type_decl;
+ }
+
+ type_name = TYPE_NAME (type);
+
+ if (TREE_CODE (type_name) == IDENTIFIER_NODE)
+ type_str = IDENTIFIER_POINTER (type_name);
+ else
+ type_str = IDENTIFIER_POINTER (DECL_NAME (type_name));
+
+ switch (TREE_CODE (type))
+ {
+ case ENUMERAL_TYPE:
+ prefix = "E";
+ break;
+
+ case RECORD_TYPE:
+ prefix = "S";
+ break;
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ prefix = "UN";
+ break;
+
+ default:
+ gcc_assert (0);
+ prefix = "error";
+ }
+
+ str = append_string (str, prefix, len, max_len);
+ str = append_string (str, type_str, len, max_len);
+ }
+ break;
+
+ default:
+ str = append_string (str, "unknown", len, max_len);
+ }
+
+ return str;
+}
+
+static char *
+get_md5 (const char *str, size_t len, size_t *md5_len)
+{
+ char *md5_str;
+
+ /* TODO: unimplemented */
+ *md5_len = len;
+ md5_str = (char *)xmalloc (len);
+ memcpy (md5_str, str, len);
+
+ return md5_str;
+}
+
+static tree
+make_valuetype_identifier (tree t)
+{
+ size_t tmp_name_max_len = 256;
+ size_t tmp_name_len = 0;
+ char *tmp_name;
+ size_t vt_name_len = 0;
+ char *vt_name;
+ tree ident;
+
+ tmp_name = (char *)xmalloc (tmp_name_max_len);
+
+ if (TREE_CODE (t) == ENUMERAL_TYPE)
+ {
+ tree tmp;
+
+ tmp_name = append_string (tmp_name, "enum?",
+ &tmp_name_len, &tmp_name_max_len);
+
+ tmp = TYPE_VALUES (t);
+
+ while (tmp)
+ {
+ tmp_name = append_string (tmp_name,
+ IDENTIFIER_POINTER (TREE_PURPOSE (tmp)),
+ &tmp_name_len, &tmp_name_max_len);
+ tmp_name = append_string (tmp_name, "?",
+ &tmp_name_len, &tmp_name_max_len);
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+ else if (TREE_CODE (t) == ARRAY_TYPE)
+ {
+ tmp_name = append_string (tmp_name, "array?",
+ &tmp_name_len, &tmp_name_max_len);
+ tmp_name = append_coded_type (tmp_name, t,
+ &tmp_name_len, &tmp_name_max_len);
+ }
+ else
+ {
+ tree tmp;
+
+ if (TREE_CODE (t) == RECORD_TYPE)
+ tmp_name = append_string (tmp_name, "struct?",
+ &tmp_name_len, &tmp_name_max_len);
+ else
+ tmp_name = append_string (tmp_name, "union?",
+ &tmp_name_len, &tmp_name_max_len);
+
+ tmp = TYPE_FIELDS (t);
+ while (tmp)
+ {
+ tree ttype = TREE_TYPE (tmp);
+
+ tmp_name = append_coded_type (tmp_name, ttype,
+ &tmp_name_len, &tmp_name_max_len);
+ tmp_name = append_string (tmp_name, "?",
+ &tmp_name_len, &tmp_name_max_len);
+ if (DECL_NAME (tmp) != 0)
+ tmp_name = append_string (tmp_name,
+ IDENTIFIER_POINTER (DECL_NAME (tmp)),
+ &tmp_name_len, &tmp_name_max_len);
+ else
+ /* Unnamed bitfields or unions */
+ tmp_name = append_string (tmp_name, "?unnamed",
+ &tmp_name_len, &tmp_name_max_len);
+ tmp_name = append_string (tmp_name, "?",
+ &tmp_name_len, &tmp_name_max_len);
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+
+ vt_name = get_md5 (tmp_name, tmp_name_len, &vt_name_len);
+ free (tmp_name);
+
+ ident = get_identifier_with_length (vt_name, vt_name_len);
+ free (vt_name);
+
+ return ident;
+}
+
+static void
+print_valuetype_decl (FILE *file, tree t)
+{
+ bool is_enum;
+
+ if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
+ return;
+
+ if (file == 0)
+ return;
+
+ gcc_assert (TYPE_MAIN_VARIANT (t) == t);
+ gcc_assert (TYPE_NAME (t));
+
+ is_enum = (TREE_CODE (t) == ENUMERAL_TYPE);
+
+ /* Print the name of the valuetype. */
+ fputs ("\n.class ", file);
+
+ if (TYPE_FILE_SCOPE_P (t))
+ fputs ("public ", file);
+ else
+ fputs ("private ", file);
+
+ if (!is_enum)
+ fputs ("explicit ", file);
+
+ fputs ("sealed serializable ansi ", file);
+ dump_valuetype_name (file, t);
+ fputs (" extends ['mscorlib']System.", file);
+
+ if (is_enum)
+ fputs ("Enum\n", file);
+ else
+ fputs ("ValueType\n", file);
+
+ /* Print the contents of the valuetype. */
+ fputs ("{\n", file);
+
+ if (is_enum)
+ {
+ int type_size = GET_MODE_BITSIZE (TYPE_MODE (t));
+ char tmp_str[8] = "int";
+ char *base_type_str = tmp_str;
+ tree tmp;
+
+ snprintf (base_type_str + 3, 5, "%d", type_size);
+
+ fputs ("\t.field public specialname rtspecialname ", file);
+
+ if (!TYPE_UNSIGNED (t))
+ fputs ("unsigned ", file);
+
+ fprintf (file, "%s 'value__'\n", base_type_str);
+
+ tmp = TYPE_VALUES (t);
+ while (tmp)
+ {
+ fputs ("\t.field public static literal ", file);
+ dump_type (file, t, false);
+ fputs (" ", file);
+ dump_decl_name (file, TREE_PURPOSE (tmp));
+ fprintf (file, " = %s(%ld)\n",
+ base_type_str, TREE_INT_CST_LOW (TREE_VALUE (tmp)));
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+ else if (TREE_CODE (t) == ARRAY_TYPE)
+ {
+ /* array */
+ fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t)));
+ fprintf (file, "\t.pack %u\n", TYPE_ALIGN_UNIT (t));
+ fputs ("\t.field [0] public specialname ", file);
+ dump_type (file, TREE_TYPE (t), false);
+ fputs (" 'elem__'\n", file);
+ }
+ else
+ {
+ /* struct and union */
+ tree tmp;
+
+ fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t)));
+ fprintf (file, "\t.pack %u\n", TYPE_ALIGN_UNIT (t));
+
+ tmp = TYPE_FIELDS (t);
+ while (tmp)
+ {
+ tree type;
+ unsigned int bit_offset =
+ TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (tmp));
+ unsigned int byte_offset =
+ TREE_INT_CST_LOW (DECL_FIELD_OFFSET (tmp));
+ unsigned int offset;
+
+ /* Skip unnamed bitfields */
+ if (DECL_NAME (tmp) == 0 && DECL_BIT_FIELD (tmp))
+ goto next;
+
+ if (DECL_BIT_FIELD (tmp))
+ {
+ unsigned int type_size;
+
+ type = DECL_BIT_FIELD_TYPE (tmp);
+
+ gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == INTEGER_TYPE
+ || TREE_CODE (TREE_TYPE (tmp)) == BOOLEAN_TYPE);
+ gcc_assert (TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == BOOLEAN_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE);
+
+ type_size = TREE_INT_CST_LOW (TYPE_SIZE (type));
+ offset = byte_offset + (bit_offset & ~(type_size - 1)) / 8;
+ }
+ else
+ {
+ type = TREE_TYPE (tmp);
+ gcc_assert (bit_offset % 8 == 0);
+ offset = byte_offset + bit_offset / 8;
+ }
+
+ fprintf (file, "\t.field [%d] public ", offset);
+ dump_type (file, type, false);
+ fputs (" ", file );
+ dump_decl_name (file, tmp);
+ fputs ("\n", file);
+ next:
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+
+ fputs ("}\n", file);
+}
+
+static void
+print_string_decl (FILE *file, tree t)
+{
+ const char *str;
+ int len, i;
+
+ gcc_assert (TREE_CODE (t) == STRING_CST);
+ str = TREE_STRING_POINTER (t);
+ len = TREE_STRING_LENGTH (t);
+
+ mark_referenced_type (TREE_TYPE (t));
+
+ /* Emit the string in readable form as a comment. */
+ fputs ("// string: \"", file);
+ for (i=0; i < len-1; ++i)
+ {
+ switch (str[i]) {
+ case '\n': fputs ("\\n", file); break;
+ case '"': fputs ("\"", file); break;
+ default: fputc (str[i], file); break;
+ }
+ }
+ fputs ("\"\n", file);
+
+ fprintf (file, ".data 'DataStr%lu' = bytearray(",
+ (unsigned long)TREE_STRING_POINTER (t));
+ for (i=0; i < len; ++i)
+ fprintf (file, "%02x ", str[i]);
+ fputs (")\n", file);
+
+ fputs (".field private static ", file);
+ dump_type (file, TREE_TYPE (t), true);
+ fputs (" ", file);
+ dump_string_name (file, t);
+ fprintf (file, " at 'DataStr%lu'\n",
+ (unsigned long)TREE_STRING_POINTER (t));
+}
+
+static void
+gen_start_function (FILE *stream)
+{
+ int nargs;
+ tree args;
+ for (nargs=0,args = DECL_ARGUMENTS (current_function_decl);
+ args;
+ args = TREE_CHAIN (args),++nargs)
+ {
+ }
+
+ fputs ("\n.method public static void '.start'(class [mscorlib]System.String[] 'args') cil managed",
+ stream);
+ fputs ("\n{"
+ "\n\t.entrypoint"
+ "\n\t.maxstack 2"
+ "\n\t.locals (int32 'argc', int8** 'argv')", stream);
+ /* TODO: add startup code*/
+ switch (nargs)
+ {
+ case 0:
+ fputs ("\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
+ "\n\tcall\tint32 main()", stream);
+ break;
+
+ case 1:
+ fputs ("\n\tldloca\t'argc'"
+ "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)"
+ "\n\tpop"
+ "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
+ "\n\tldloc\t'argc'"
+ "\n\tcall\tint32 main(int32)", stream);
+ break;
+
+ case 2:
+ fputs ("\n\tldloca\t'argc'"
+ "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)"
+ "\n\tstloc\t'argv'"
+ "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
+ "\n\tldloc\t'argc'"
+ "\n\tldloc\t'argv'"
+ "\n\tcall\tint32 main(int32, int8**)", stream);
+ break;
+
+ default:
+ gcc_assert (0);
+ }
+
+ /* TODO: add exit code*/
+ fputs ("\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Shutdown(int32)"
+ "\n\tret"
+ "\n} // .start"
+ "\n\n", stream);
+}
+
+static void
+gen_cil_1 (FILE *stream)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+ bool varargs = FALSE;
+ tree args;
+
+ /* Mark defs and uses of local non-static variables */
+ defd_vars = pointer_set_create ();
+ defd_more_than_once_vars = pointer_set_create ();
+ used_vars = pointer_set_create ();
+ used_more_than_once_vars = pointer_set_create ();
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ mark_var_defs_uses (bsi_stmt (bsi));
+ }
+ }
+ pointer_set_destroy (defd_vars);
+
+ /* Remove useless pairs of stloc - ldloc */
+ useless_vars = pointer_set_create ();
+ FOR_EACH_BB (bb)
+ {
+ /* Start from the second statement, if any */
+ bsi = bsi_start (bb);
+ if (! bsi_end_p (bsi))
+ bsi_next (&bsi);
+
+ for (; !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ bool changed;
+
+ /* Remove stloc - ldloc pairs until no change is done
+ to the current statement */
+ do {
+ changed = false;
+ remove_stloc_ldloc (bsi, bsi_stmt_ptr (bsi), &changed);
+ } while (changed);
+ }
+ }
+ pointer_set_destroy (defd_more_than_once_vars);
+ pointer_set_destroy (used_vars);
+ pointer_set_destroy (used_more_than_once_vars);
+
+ /* Remove useless vars (only used in removed stloc - ldloc pairs) */
+ {
+ tree cell, prev_cell = NULL_TREE;
+
+ for (cell = cfun->unexpanded_var_list;
+ cell;
+ cell = TREE_CHAIN (cell))
+ {
+ tree var = TREE_VALUE (cell);
+
+ if (pointer_set_contains (useless_vars, var))
+ {
+ if (prev_cell == NULL_TREE)
+ cfun->unexpanded_var_list = TREE_CHAIN (cell);
+ else
+ TREE_CHAIN (prev_cell) = TREE_CHAIN (cell);
+ }
+ else
+ prev_cell = cell;
+ }
+ }
+ pointer_set_destroy (useless_vars);
+
+ stack_reset ();
+ max_stack = 0;
+
+ if (strcmp ("main",
+ lang_hooks.decl_printable_name (current_function_decl, 1)) == 0)
+ gen_start_function (stream);
+
+ {
+ tree var, cell;
+
+ for (cell = cfun->unexpanded_var_list;
+ cell;
+ cell = TREE_CHAIN (cell))
+ {
+ var = TREE_VALUE (cell);
+
+ if (TREE_STATIC (var) && TREE_ASM_WRITTEN (var) == 0)
+ make_decl_cil (stream, var);
+ }
+ }
+
+ {
+ tree args_type = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl));
+
+ if (args_type != NULL)
+ {
+ while (TREE_CHAIN (args_type))
+ args_type = TREE_CHAIN (args_type);
+
+ if (TREE_VALUE (args_type) != void_type_node)
+ varargs = TRUE;
+ }
+ }
+
+ fputs ("\n.method ", stream);
+
+ if (TREE_PUBLIC (current_function_decl))
+ fputs ("public ", stream);
+ else
+ fputs ("private ", stream);
+
+ fputs ("static ", stream);
+ if (varargs)
+ fputs ("vararg ", stream);
+ dump_type (stream, TREE_TYPE (TREE_TYPE (current_function_decl)), true);
+ fprintf (stream, " '%s' (",
+ lang_hooks.decl_printable_name (current_function_decl, 1));
+
+ args = DECL_ARGUMENTS (current_function_decl);
+
+ while (args)
+ {
+ dump_type (stream, DECL_ARG_TYPE (args), true);
+ fputs (" ", stream);
+ dump_decl_name (stream, args);
+ args = TREE_CHAIN (args);
+
+ if (args)
+ fputs (", ", stream);
+ else if (varargs)
+ fputs (", ...", stream);
+ }
+
+ fputs (") cil managed"
+ "\n{"
+ "\n\t.locals init (", stream);
+ {
+ tree var, cell;
+ bool first = true;
+
+ for (cell = cfun->unexpanded_var_list;
+ cell;
+ cell = TREE_CHAIN (cell))
+ {
+ var = TREE_VALUE (cell);
+ if (!TREE_STATIC (var))
+ {
+ if (!first)
+ fputs (", ", stream);
+ first = false;
+ dump_type (stream, TREE_TYPE (var), true);
+ fputs (" ", stream);
+ dump_decl_name (stream, var);
+ }
+ }
+ }
+ fputs (")\n", stream);
+
+ if (DECL_STATIC_CONSTRUCTOR (current_function_decl))
+ {
+ if (TARGET_OPENSYSTEMC)
+ fputs ("\n\t.custom instance "
+ "void ['OpenSystem.C']'OpenSystem.C'.InitializerAttribute::.ctor() "
+ "= (01 00 00 00)", stream);
+ }
+
+ FOR_EACH_BB (bb)
+ {
+ tree stmt = NULL_TREE;
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ stmt = bsi_stmt (bsi);
+ if (TARGET_EMIT_GIMPLE_COMMENTS)
+ {
+ fprintf (stream, "\n\t/* ");
+ print_generic_expr (stream, stmt, 0);
+ fprintf (stream, " */");
+ }
+ gcc_assert (stack == 0);
+
+ if (TREE_CODE (stmt) != NOP_EXPR
+ || TREE_CODE (TREE_OPERAND (stmt, 0)) != INTEGER_CST)
+ gen_cil_node (stream, stmt);
+
+ if (TREE_CODE (stmt) == CALL_EXPR)
+ {
+ tree fun_expr = TREE_OPERAND (stmt, 0);
+ tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr));
+
+ if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE)
+ {
+ fputs ("\n\tpop", stream);
+ stack_pop (1);
+ }
+ }
+ }
+
+ if ((!stmt || (TREE_CODE (stmt) != COND_EXPR)) && single_succ_p (bb))
+ {
+ basic_block succ = single_succ (bb);
+
+ /* The last part of the test (succ != bb->next_bb) is a HACK. It
+ avoids generating a branch to the successor in case of a
+ fallthrough. To be fixed when we have a proper layout of basic
+ blocks. Note that branches from COND_EXPR are still generated,
+ even to a fallthrough. */
+ if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb))
+ {
+ tree label = tree_block_label (succ);
+ fputs ("\n\tbr ", stream);
+ dump_label_name (stream, label);
+ gcc_assert (stack == 0);
+ }
+ }
+ }
+
+ fprintf (stream, "\n\t.maxstack %d\n", max_stack);
+ fprintf (stream, "\n} // %s\n",
+ lang_hooks.decl_printable_name (current_function_decl, 1));
+ TREE_ASM_WRITTEN (current_function_decl) = 1;
+}
+
+static void
+create_init_method (tree decl)
+{
+ static int init_counter = 0;
+ tree init;
+ char name[30];
+ tree fun_type;
+ tree fun_decl;
+ tree init_expr = NULL;
+ tree result;
+
+ ++init_counter;
+ sprintf (name, "?init-%d", init_counter);
+
+ fun_type = build_function_type (void_type_node, void_list_node);
+ fun_decl = build_decl (FUNCTION_DECL, get_identifier (name), fun_type);
+
+ result = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
+ DECL_ARTIFICIAL (result) = 1;
+ DECL_IGNORED_P (result) = 1;
+ DECL_RESULT (fun_decl) = result;
+
+ allocate_struct_function (fun_decl);
+
+
+ TREE_STATIC (fun_decl) = 1;
+ TREE_USED (fun_decl) = 1;
+ DECL_ARTIFICIAL (fun_decl) = 1;
+ DECL_IGNORED_P (fun_decl) = 0;
+ TREE_PUBLIC (fun_decl) = 0;
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fun_decl) = 1;
+ DECL_UNINLINABLE (fun_decl) = 1;
+ DECL_EXTERNAL (fun_decl) = 0;
+ DECL_STATIC_CONSTRUCTOR (fun_decl) = 1;
+ DECL_CONTEXT (fun_decl) = NULL_TREE;
+ DECL_INITIAL (fun_decl) = make_node (BLOCK);
+
+ init = DECL_INITIAL (decl);
+ DECL_INITIAL (decl) = NULL_TREE;
+
+ DECL_SOURCE_LOCATION (fun_decl) = EXPR_LOCATION (init);
+
+ expand_init_to_stmt_list (decl, init, &init_expr, false);
+
+ DECL_SAVED_TREE (fun_decl) = init_expr;
+
+ gimplify_function_tree (fun_decl);
+ tree_lowering_passes (fun_decl);
+ tree_rest_of_compilation (fun_decl);
+}
+
+void
+make_decl_cil (FILE *stream, tree decl)
+{
+ if (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || TREE_PUBLIC (decl)))
+ {
+ tree init = DECL_INITIAL (decl);
+
+ fputs ("\n.field ", stream);
+
+ if (TREE_PUBLIC (decl))
+ fputs ("public ", stream);
+ else
+ fputs ("private ", stream);
+
+ fputs ("static ", stream);
+ dump_type (stream, TREE_TYPE (decl), true);
+ fputs (" ", stream);
+ dump_decl_name (stream, decl);
+ fputs ("\n", stream);
+
+ if (init && init != error_mark_node)
+ VARRAY_PUSH_TREE (pending_ctors, decl);
+
+ TREE_ASM_WRITTEN (decl) = 1;
+ }
+}
+
+void
+gen_cil_init (void)
+{
+ FILE *stream = asm_out_file;
+
+ fputs (".assembly extern gcc4net {}", stream);
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY)
+ fputs ("\n.assembly '_C_MONO_ASSEMBLY' {}", stream);
+ fputs ("\n.module '<Module>'", stream);
+
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY)
+ fputs ("\n.class public '_C_MONO_MODULE'"
+ "\n{", stream);
+
+ if (TARGET_OPENSYSTEMC)
+ fputs ("\n.custom instance "
+ "void ['OpenSystem.C']'OpenSystem.C'.ModuleAttribute::.ctor() "
+ "= (01 00 00 00)"
+ "\n", stream);
+
+ referenced_types = pointer_set_create ();
+ VARRAY_TREE_INIT (referenced_strings, 32, "strings used in current unit");
+ referenced_string_ptrs = pointer_set_create ();
+ referenced_pinvoke = pointer_set_create ();
+ VARRAY_TREE_INIT (pending_ctors, 32, "pending ctors");
+}
+
+void
+gen_cil_fini (void)
+{
+ FILE *stream = asm_out_file;
+ struct pointer_set_iter_t it;
+ int i, n;
+
+
+ i = 0;
+ n = VARRAY_ACTIVE_SIZE (pending_ctors);
+ while (i<n)
+ {
+ for (; i < n; ++i)
+ {
+ tree decl = VARRAY_TREE (pending_ctors, i);
+ create_init_method (decl);
+ }
+ n = VARRAY_ACTIVE_SIZE (pending_ctors);
+ }
+ VARRAY_CLEAR (pending_ctors);
+
+ i = 0;
+ n = VARRAY_ACTIVE_SIZE (referenced_strings);
+ for (; i < n; ++i)
+ {
+ tree type = VARRAY_TREE (referenced_strings, i);
+ print_string_decl (stream, type);
+ }
+ VARRAY_CLEAR (referenced_strings);
+ pointer_set_destroy (referenced_string_ptrs);
+
+ if (TARGET_EMIT_EXTERNAL_ASSEMBLY)
+ fputs ("\n} // _C_MONO_MODULE\n", stream);
+
+ /* There may be distinct tree types that correspond to identical types.
+ In order not to slow down mark_referenced_type(...) function (which
+ may typically be called several times for the same type), insertion
+ of types in the mark set makes only sure that the same tree type
+ pointer is not inserted twice. As a consequence, there may still be
+ distinct tree types that correspond to identical types in the
+ reference type set.
+ Hence, before emitting a type, make sure no type with the same name
+ has already been emitted. */
+
+ it = pointer_set_begin (referenced_types);
+ while (!POINTER_SET_ITER_IS_END (it))
+ {
+ tree type = (tree)POINTER_SET_ITER_ELEM (it);
+ bool found = false;
+ struct pointer_set_iter_t it2;
+ tree type_name = TYPE_NAME (type);
+ const char* type_str;
+
+ if (COMPLETE_TYPE_P (type))
+ {
+ gcc_assert (DECL_P (type_name)
+ || TREE_CODE (type_name) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (type_name) == IDENTIFIER_NODE)
+ type_str = IDENTIFIER_POINTER (type_name);
+ else
+ type_str = IDENTIFIER_POINTER (DECL_NAME (type_name));
+
+ it2 = pointer_set_begin (referenced_types);
+ while (!found && POINTER_SET_ITER_ELEM (it2) != type)
+ {
+ tree type2 = (tree)POINTER_SET_ITER_ELEM (it2);
+ tree type2_name = TYPE_NAME (type2);
+ const char* type2_str;
+
+ gcc_assert (DECL_P (type2_name)
+ || TREE_CODE (type2_name) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (type2_name) == IDENTIFIER_NODE)
+ type2_str = IDENTIFIER_POINTER (type2_name);
+ else
+ type2_str = IDENTIFIER_POINTER (DECL_NAME (type2_name));
+
+ found = strcmp (type2_str, type_str) == 0;
+ it2 = pointer_set_next (referenced_types, it2);
+ }
+
+ if (!found)
+ print_valuetype_decl (stream, type);
+ }
+
+ it = pointer_set_next (referenced_types, it);
+ }
+ pointer_set_destroy (referenced_types);
+
+ it = pointer_set_begin (referenced_pinvoke);
+ while (!POINTER_SET_ITER_IS_END (it))
+ {
+ tree fun = (tree)POINTER_SET_ITER_ELEM (it);
+ tree fun_type = TREE_TYPE (fun);
+ struct fnct_attr attributes;
+
+ decode_function_attrs (fun, &attributes);
+
+ fputs (".method ", stream);
+
+ if (TREE_PUBLIC (fun))
+ fputs ("public ", stream);
+ else
+ fputs ("private ", stream);
+
+ fprintf (stream, "static pinvokeimpl(\"%s\"", attributes.pinvoke_assembly);
+
+ if (attributes.pinvoke_fname)
+ fprintf (stream, " as \"%s\"", attributes.pinvoke_fname);
+
+ fputs (") ", stream);
+
+ dump_fun_type (stream, fun_type, fun, NULL, false);
+
+ fputs (" cil managed {}\n", stream);
+ it = pointer_set_next (referenced_pinvoke, it);
+ }
+ pointer_set_destroy (referenced_pinvoke);
+}
+
+static bool
+gen_cil_gate (void)
+{
+ return current_function_decl != NULL;
+}
+
+static unsigned int
+gen_cil (void)
+{
+ gen_cil_1 (asm_out_file);
+ return 0;
+}
+
+/* Define the parameters of the gen-CIL pass. */
+
+struct tree_opt_pass pass_gen_cil =
+{
+ "cil", /* name */
+ gen_cil_gate, /* gate */
+ gen_cil, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REST_OF_COMPILATION, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ /* ??? If TER is enabled, we also kill gimple. */
+ 0, /* properties_destroyed */
+ 0,
+ 0,
+ 0 /* letter */
+};
+
+#include "gt-gen-cil.h"
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/gen-cil.h b/gcc/config/cil32/gen-cil.h
new file mode 100644
index 00000000000..e019dd8aec1
--- /dev/null
+++ b/gcc/config/cil32/gen-cil.h
@@ -0,0 +1,47 @@
+/* CIL generation definitions for GNU compiler.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#ifndef GEN_CIL_H
+#define GEN_CIL_H
+
+#include "tree.h"
+
+void
+make_decl_cil (FILE *, tree);
+
+void
+cil_add_pinvoke(tree);
+
+void
+gen_cil_init (void);
+void
+gen_cil_fini (void);
+
+#endif /* GEN_CIL_H */
diff --git a/gcc/config/cil32/t-cil32 b/gcc/config/cil32/t-cil32
new file mode 100644
index 00000000000..78bb2c5c78c
--- /dev/null
+++ b/gcc/config/cil32/t-cil32
@@ -0,0 +1,60 @@
+# Hi emacs, use Makefile syntax mode. -*-mode: Makefile; -*-
+
+# Copyright (C) 2006 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC 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.
+#
+# GCC 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 GCC; see the file COPYING. If not, write to the Free
+# Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# Authors:
+# Andrea Bona
+# Andrea Ornstein
+# Erven Rohou
+# Roberto Costa
+#
+# Contact information at STMicroelectronics:
+# Roberto Costa <roberto.costa@st.com>
+
+
+gen-cil.o: $(srcdir)/config/cil32/gen-cil.c $(srcdir)/config/cil32/gen-cil.h \
+ $(srcdir)/config/cil32/tree-simp-cil.h gt-gen-cil.h\
+ $(CONFIG_H) $(SYSTEM_H) \
+ $(TREE_H) $(DIAGNOSTIC_H) real.h $(HASHTAB_H) $(TREE_FLOW_H) \
+ $(TM_H) coretypes.h tree-iterator.h tree-chrec.h langhooks.h tree-pass.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+tree-simp-cil.o: $(srcdir)/config/cil32/tree-simp-cil.c \
+ $(srcdir)/config/cil32/tree-simp-cil.h \
+ $(CONFIG_H) $(SYSTEM_H) \
+ $(TREE_H) $(DIAGNOSTIC_H) real.h $(HASHTAB_H) $(TREE_FLOW_H) \
+ $(TM_H) coretypes.h tree-iterator.h tree-chrec.h langhooks.h tree-pass.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+$(out_object_file): gt-gen-cil.h
+gt-gen-cil.h : s-gtype ; @true
+
+
+LIBGCC =
+INSTALL_LIBGCC = install-gcc4net
+
+install-gcc4net: gcc4net.dll installdirs
+ $(INSTALL_DATA) gcc4net.dll $(DESTDIR)$(libdir)/
+ $(INSTALL_DATA) gcc4net.dll $(DESTDIR)$(libsubdir)/
+
+MCS=mcs
+
+gcc4net.dll: $(srcdir)/config/cil32/gcc4net.cs
+ $(MCS) $< -unsafe -target:library -out:$@
diff --git a/gcc/config/cil32/tree-simp-cil.c b/gcc/config/cil32/tree-simp-cil.c
new file mode 100644
index 00000000000..8e43c2fbee9
--- /dev/null
+++ b/gcc/config/cil32/tree-simp-cil.c
@@ -0,0 +1,2166 @@
+/* Simplify GENERIC trees before CIL emission.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "real.h"
+#include "hashtab.h"
+#include "tree-flow.h"
+#include "langhooks.h"
+#include "tree-iterator.h"
+#include "tree-chrec.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "assert.h"
+#include "toplev.h"
+#include "output.h"
+#include "tree-simp-cil.h"
+
+/* The purpose of this pass is to simplify GIMPLE trees in order
+ to make CIL emission easier.
+ As a matter of fact, there are some transformations that are
+ difficult at emission time (pass gen_cil), i.e. those that
+ involve generating new local temporary variables, modifications
+ in the control-flow graph or in types...
+ On the other hand, these transformations can be well performed
+ in GIMPLE representation.
+ The choice that is taken is to add restrictions to the GIMPLE trees
+ gen_cil pass can handle and to make simp_cil pass enforce them.
+
+ Currently, these are the transformations performed by cil_simp pass:
+
+ *) Removal of RESULT_DECL nodes. CIL doesn't treat the value
+ returned by a function in any special way: if it has to be
+ temporarily stored, this must be in a local.
+ A new local variable is generated and each RESULT_DECL node is
+ transformed into a VAR_DECL of that variable.
+
+ *) Expansion of ABS_EXPR nodes (in case of -mexpand-abs option).
+ The expansion requires changes to the control-flow graph.
+
+ *) Expansion of MAX_EXPR and MIN_EXPR nodes (in case of
+ -mexpand-minmax option).
+ The expansion requires changes to the control-flow graph.
+
+ *) Expansion of SWITCH_EXPR, when it is not profitable to have
+ a switch table (heuristic decision is based on case density).
+ CIL emission pass (gen_cil) always emits a SWITCH_EXPR to a
+ CIL switch opcode. When a low case density makes compare trees
+ preferable, the SWITCH_EXPR is expanded; otherwise the
+ SWITCH_EXPR is not modified.
+ The expansion requires changes to the control-flow graph.
+
+ *) Expansion of COMPONENT_REF nodes operating on bit-fields.
+ CIL has no direct support for bit-field access; hence,
+ equivalent code that extracts the bit pattern and applies the
+ appropriate bit mask is generated.
+ Memory access is performed by using INDIRECT_REF nodes.
+ Beware that such a COMPONENT_REF on the left-hand side of an
+ assignment also requires a load from memory; from the memory
+ access point of view, the operation cannot be made atomic.
+
+ *) Expansion of TARGET_MEM_REF nodes.
+ Emission of such nodes is not difficult in gen_cil pass;
+ however, a previous expansion may trigger further optimizations
+ (since there is no similar construct in CIL bytecodes).
+
+ *) Expansion of ARRAY_REF nodes.
+ Emission of such nodes is not difficult in gen_cil pass;
+ however, a previous expansion may generate better code (i.e.:
+ it may fold constants) or trigger further optimizations
+ (CIL arrays cannot be used for C-style arrays).
+
+ *) Expansion of CONSTRUCTOR nodes used as right-hand sides of
+ INIT_EXPR and MODIFY_EXPR nodes.
+ Such CONSTRUCTOR nodes must be implemented in CIL bytecode through
+ a sequence of finer grain initializations.
+ Hence, initializer statements containing CONSTRUCTOR nodes
+ are expanded into an equivalent list of initializer statements,
+ with no more CONSTRUCTOR nodes.
+ Since the same expansion must occur for global variables (which
+ is performed by other passes), function
+ expand_init_to_stmt_list (...) is exported.
+
+ *) Expansion of LROTATE_EXPR and RROTATE_EXPR nodes.
+ In CIL there no are opcodes for rotation and they have
+ to be emulated through shifts and bit operations.
+ A previous expansion may generate better code (i.e.:
+ it may fold constants) or trigger further optimizations.
+
+ *) The second operand of LSHIFT_EXPR and RSHIFT_EXPR
+ is converted to a 32-bit size in the very rare
+ cases it isn't already. This is always safe, because shifts with
+ shift amounts bigger than the size of the operand to be shifted
+ produce undefined results.
+ The reason is that CIL shift operations require a shift operand
+ of type int32.
+
+ *) Rename of inlined variables to unique names.
+ Emitted variables by gen_cil pass keep the original name.
+ In case of variables declared within inlined functions,
+ renaming them is needed clashes.
+
+ *) Globalization of function static variables.
+ CIL locals can be used for function non-static variables;
+ there is no CIL feature to do the same with function static
+ variables. Therefore, those variables have their scope changed
+ (they become global), and their name as well, to avoid clashes.
+
+ *) Expansion of initializers of local variables.
+ In order to simplify gen_cil, the initialization of local
+ variables (for those that have it) is expanded into the body
+ of the entry basic block of the function.
+*/
+
+/* Local functions, macros and variables. */
+static tree get_unsigned_integer_type (int);
+static bool is_copy_required (tree);
+static bool mostly_zeros_p (tree);
+static bool all_zeros_p (tree);
+static void simp_switch (block_stmt_iterator *, tree *);
+static void simp_trivial_switch (block_stmt_iterator *, tree *);
+static void simp_abs (block_stmt_iterator *, tree *);
+static void simp_min_max (block_stmt_iterator *, tree *);
+static void simp_rotate (block_stmt_iterator *, tree *);
+static void simp_shift (block_stmt_iterator *, tree);
+static void simp_target_mem_ref (block_stmt_iterator *, tree *);
+static void simp_array_ref (block_stmt_iterator *, tree *);
+static void simp_rhs_bitfield_component_ref (block_stmt_iterator *, tree *);
+static void simp_lhs_bitfield_component_ref (block_stmt_iterator *, tree *);
+static void pre_simp_init (block_stmt_iterator *, tree);
+static void simp_cil_node (block_stmt_iterator *, tree *);
+static void split_use (block_stmt_iterator, tree *);
+static void rename_var (tree, const char*);
+static void simp_vars (void);
+static unsigned int simp_cil (void);
+static bool simp_cil_gate (void);
+
+static tree res_var;
+static tree uint32_type;
+
+/* Return the unsigned integer type with size BITS bits */
+
+static tree
+get_unsigned_integer_type (int bits)
+{
+ if (GET_MODE_BITSIZE (TYPE_MODE (unsigned_type_node)) == bits)
+ return unsigned_type_node;
+ else if (GET_MODE_BITSIZE (TYPE_MODE (long_unsigned_type_node)) == bits)
+ return long_unsigned_type_node;
+ else if (GET_MODE_BITSIZE (TYPE_MODE (short_unsigned_type_node)) == bits)
+ return short_unsigned_type_node;
+ else if (GET_MODE_BITSIZE (TYPE_MODE (long_long_unsigned_type_node))
+ == bits)
+ return long_long_unsigned_type_node;
+ else if (GET_MODE_BITSIZE (TYPE_MODE (unsigned_char_type_node)) == bits)
+ return unsigned_char_type_node;
+ else
+ {
+ gcc_assert (0);
+ return NULL_TREE;
+ }
+}
+
+/* In the case of multiple uses of tree NODE, return whether
+ it is required to compute NODE only once or not.
+ If NODE has side effects, TRUE is obviously always returned.
+ If NODE has no side effects, TRUE is still returned if
+ it looks more profitable to compute NODE only once,
+ FALSE otherwise (this is a heuristic decision). */
+
+static bool
+is_copy_required (tree node)
+{
+ if (TREE_SIDE_EFFECTS (node))
+ return TRUE;
+
+ switch (TREE_CODE (node))
+ {
+ case INTEGER_CST:
+ case REAL_CST:
+ case VAR_DECL:
+ case PARM_DECL:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+/* Simplify the node pointed by NODE_PTR in order to make CIL emission easier.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions may be inserted,
+ new basic blocks created...
+ NODE is passed by reference because simplification may require
+ replacing the node. */
+
+static void
+simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+
+ if (node == NULL_TREE)
+ return; /* ER: was spc */
+
+ switch (TREE_CODE (node))
+ {
+ case COND_EXPR:
+ simp_cil_node (bsi, &COND_EXPR_COND (node));
+ break;
+
+ case SWITCH_EXPR:
+ simp_cil_node (bsi, &SWITCH_COND (node));
+ simp_switch (bsi, node_ptr);
+ break;
+
+ case CALL_EXPR:
+ {
+ tree args = TREE_OPERAND (node, 1);
+
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+
+ while (args)
+ {
+ simp_cil_node (bsi, &TREE_VALUE (args));
+ args = TREE_CHAIN (args);
+ }
+ }
+ break;
+
+ case MULT_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case RDIV_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case EXACT_DIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ break;
+
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (node, 1))))
+ > 32)
+ simp_shift (bsi, node);
+ break;
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ simp_rotate (bsi, node_ptr);
+ break;
+
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ gcc_assert (TREE_CODE (TREE_OPERAND (node, 1)) != CONSTRUCTOR
+ && TREE_CODE (TREE_OPERAND (node, 1)) != STRING_CST);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 1)))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (node, 1)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 1));
+ break;
+
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case BIT_FIELD_REF:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case ADDR_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0)))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case INDIRECT_REF:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ if (AGGREGATE_TYPE_P (TREE_TYPE (node))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case COMPONENT_REF:
+ gcc_assert (TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL);
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0)))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 0));
+ if (DECL_BIT_FIELD (TREE_OPERAND (node, 1)))
+ {
+ tree stmt = bsi_stmt (*bsi);
+
+ if (TREE_CODE (stmt) == MODIFY_EXPR
+ && TREE_OPERAND (stmt, 0) == node)
+ simp_lhs_bitfield_component_ref (bsi, node_ptr);
+ else
+ simp_rhs_bitfield_component_ref (bsi, node_ptr);
+ }
+ break;
+
+ case TARGET_MEM_REF:
+ simp_cil_node (bsi, &TMR_SYMBOL (node));
+ simp_cil_node (bsi, &TMR_BASE (node));
+ simp_cil_node (bsi, &TMR_INDEX (node));
+ simp_target_mem_ref (bsi, node_ptr);
+ node = *node_ptr;
+ gcc_assert (TREE_CODE (node) == INDIRECT_REF);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (node))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case ARRAY_REF:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ simp_array_ref (bsi, node_ptr);
+ node = *node_ptr;
+ gcc_assert (TREE_CODE (node) == INDIRECT_REF);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (node))
+ && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR)
+ split_use (*bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case RETURN_EXPR:
+ if (!TREE_OPERAND (node, 0)
+ && TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl)))
+ != VOID_TYPE)
+ {
+ /* Pre-C99 code may contain void-returns for non-void functions.
+ In this case, return the result variable. */
+
+ if (res_var == NULL_TREE)
+ res_var = create_tmp_var (TREE_TYPE (DECL_RESULT (current_function_decl)),
+ "cilsimp");
+
+ TREE_OPERAND (node, 0) = res_var;
+ }
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ break;
+
+ case RESULT_DECL:
+ if (res_var == NULL_TREE)
+ res_var = create_tmp_var (TREE_TYPE (node), "cilsimp");
+
+ *node_ptr = res_var;
+ break;
+
+ case ABS_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ if (TARGET_EXPAND_ABS)
+ simp_abs (bsi, node_ptr);
+ break;
+
+ case MAX_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ if (TARGET_EXPAND_MINMAX)
+ simp_min_max (bsi, node_ptr);
+ break;
+
+ case MIN_EXPR:
+ simp_cil_node (bsi, &TREE_OPERAND (node, 0));
+ simp_cil_node (bsi, &TREE_OPERAND (node, 1));
+ if (TARGET_EXPAND_MINMAX)
+ simp_min_max (bsi, node_ptr);
+ break;
+
+ default:
+ ;
+ }
+}
+
+/* Expand the SWITCH_EXPR pointed by NODE_PTR by inserting
+ compare trees. The expansion occurs only if heuristics say
+ it is profitable; the current heuristic is based on case label
+ density.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted,
+ new basic blocks created...
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_switch (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree vec = SWITCH_LABELS (node), vec1, vec2;
+ unsigned int vec_len, i;
+ bool first_case = true;
+ tree min_val = 0, max_val = 0;
+ double_int range, n_elems = double_int_zero, density1000, tmp_elems;
+ unsigned int sw1_last;
+ tree sw1_last_int_cst;
+ tree sw1_stmt, sw2_stmt;
+ block_stmt_iterator tmp_bsi;
+ basic_block bb_orig_sw, bb1, bb2;
+ tree cmp_stmt;
+ tree label1_decl, label2_decl, label1, label2;
+ edge_iterator ei;
+ edge e1, e2, tmp_edge;
+
+ /* The switch body is lowered in gimplify.c, we should never have
+ switches with a non-NULL SWITCH_BODY here. */
+ gcc_assert (TREE_CODE (node) == SWITCH_EXPR && vec && !SWITCH_BODY (node));
+
+ vec_len = TREE_VEC_LENGTH (vec);
+
+ /* Switches made of one case are always separately (they are always
+ transformed into if ... then ... else ... */
+ if (vec_len == 2)
+ simp_trivial_switch (bsi, node_ptr);
+
+ /* Compute range of cases */
+ for (i = 0; i < vec_len - 1; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ tree low = CASE_LOW (elt);
+ tree high = CASE_HIGH (elt);
+
+ if (!high)
+ high = low;
+
+ gcc_assert (low && high);
+
+ /* Discard empty ranges. */
+ if (INT_CST_LT (high, low))
+ continue;
+
+ /* Increment number of elements seen so far */
+ n_elems = double_int_add (n_elems, TREE_INT_CST (high));
+ n_elems = double_int_add (n_elems, double_int_one);
+ n_elems = double_int_add (n_elems, double_int_neg (TREE_INT_CST (low)));
+
+ if (first_case)
+ {
+ min_val = low;
+ max_val = high;
+ first_case = false;
+ }
+ else
+ {
+ if (INT_CST_LT (low, min_val))
+ min_val = low;
+
+ if (INT_CST_LT (max_val, high))
+ max_val = high;
+ }
+ }
+ gcc_assert (!INT_CST_LT (max_val, min_val));
+ range = double_int_add (TREE_INT_CST (max_val), double_int_one);
+ range = double_int_add (range, double_int_neg (TREE_INT_CST (min_val)));
+
+ /* If the range density is not high, keep the switch statement */
+ density1000 = double_int_udiv (double_int_mul (n_elems,
+ shwi_to_double_int (1000)),
+ range,
+ TRUNC_DIV_EXPR);
+ if (! double_int_negative_p (double_int_add (density1000,
+ shwi_to_double_int (-333))))
+ return;
+
+ /* Insert a copy of the switch condition, if required */
+ if (is_copy_required (SWITCH_COND (node)))
+ {
+ tree cond = SWITCH_COND (node);
+ tree var = create_tmp_var (TREE_TYPE (cond), "cilsimp");
+ tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (cond), var, cond);
+
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
+ SWITCH_COND (node) = var;
+ }
+
+ /* Compute the last CASE_LABEL_EXPR that will go to the 1st switch.
+ To do that, count number of elements until tmp_elems >= 0 */
+ tmp_elems = double_int_neg (double_int_udiv (n_elems,
+ double_int_two,
+ TRUNC_DIV_EXPR));
+ for (i = 0; i < vec_len - 1; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ tree low = CASE_LOW (elt);
+ tree high = CASE_HIGH (elt);
+
+ if (!high)
+ high = low;
+
+ gcc_assert (low && high);
+
+ /* Discard empty ranges. */
+ if (INT_CST_LT (high, low))
+ continue;
+
+ /* Increment number of elements seen so far */
+ tmp_elems = double_int_add (tmp_elems, TREE_INT_CST (high));
+ tmp_elems = double_int_add (tmp_elems, double_int_one);
+ tmp_elems = double_int_add (tmp_elems,
+ double_int_neg (TREE_INT_CST (low)));
+
+ if (! double_int_negative_p (tmp_elems))
+ break;
+ }
+ gcc_assert (! double_int_negative_p (tmp_elems));
+ gcc_assert (i <= vec_len - 2);
+ if (i == vec_len - 2)
+ /* It's the last case! Then, take the previous case */
+ i = vec_len - 3;
+ sw1_last = i;
+ sw1_last_int_cst = CASE_HIGH (TREE_VEC_ELT (vec, sw1_last));
+ if (! sw1_last_int_cst)
+ sw1_last_int_cst = CASE_LOW (TREE_VEC_ELT (vec, sw1_last));
+
+ /* Build a COND_EXPR, replace the switch with the COND_EXPR */
+ bb_orig_sw = bb_for_stmt (bsi_stmt (*bsi));
+ label1_decl = create_artificial_label ();
+ label2_decl = create_artificial_label ();
+ cmp_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (GT_EXPR, boolean_type_node,
+ SWITCH_COND (node), sw1_last_int_cst),
+ build1 (GOTO_EXPR, void_type_node, label2_decl),
+ build1 (GOTO_EXPR, void_type_node, label1_decl));
+ SET_EXPR_LOCATION (cmp_stmt, locus);
+ gcc_assert (stmt_ends_bb_p (node) && bb_for_stmt (node) == bb_orig_sw);
+
+ /* Replace the original switch with the COND_EXPR */
+ *node_ptr = cmp_stmt;
+ set_bb_for_stmt (cmp_stmt, bb_orig_sw);
+
+ /* Update the basic block statement iterator */
+ *bsi = bsi_last (bb_orig_sw);
+
+ /* Generate a basic block with the first switch */
+ bb1 = create_empty_bb (bb_orig_sw);
+ bb1->count = bb_orig_sw->count / 2;
+ label1 = build1 (LABEL_EXPR, void_type_node, label1_decl);
+ vec1 = make_tree_vec (sw1_last + 2);
+ sw1_stmt = build3 (SWITCH_EXPR, TREE_TYPE (node),
+ SWITCH_COND (node), NULL, vec1);
+ SET_EXPR_LOCATION (sw1_stmt, locus);
+ tmp_bsi = bsi_start (bb1);
+ bsi_insert_after (&tmp_bsi, label1, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, sw1_stmt, BSI_SAME_STMT);
+
+ /* Generate a basic block with the second switch */
+ bb2 = create_empty_bb (bb1);
+ bb2->count = bb_orig_sw->count - bb1->count;
+ label2 = build1 (LABEL_EXPR, void_type_node, label2_decl);
+ vec2 = make_tree_vec (vec_len - sw1_last - 1);
+ sw2_stmt = build3 (SWITCH_EXPR, TREE_TYPE (node),
+ SWITCH_COND (node), NULL, vec2);
+ SET_EXPR_LOCATION (sw2_stmt, locus);
+ tmp_bsi = bsi_start (bb2);
+ bsi_insert_after (&tmp_bsi, label2, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, sw2_stmt, BSI_SAME_STMT);
+
+ /* Build the case labels for the 1st new switch and the out-edges
+ of its basic block. */
+ for (i = 0; i < sw1_last + 1; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ basic_block target_bb = label_to_block (CASE_LABEL (elt));
+ edge e = make_edge (bb1, target_bb, 0);
+
+ if (!e)
+ e = find_edge (bb1, target_bb);
+
+ e->count = 0;
+ e->probability = 0;
+
+ TREE_VEC_ELT (vec1, i) = elt;
+ }
+ {
+ tree elt = TREE_VEC_ELT (vec, vec_len - 1);
+ basic_block target_bb = label_to_block (CASE_LABEL (elt));
+ edge e = make_edge (bb1, target_bb, 0);
+
+ if (!e)
+ e = find_edge (bb1, target_bb);
+
+ e->count = bb1->count;
+ e->probability = REG_BR_PROB_BASE;
+
+ TREE_VEC_ELT (vec1, sw1_last + 1) = elt;
+ }
+
+ /* Build the case labels for the 2nd new switch and the out-edges
+ of its basic block. */
+ for (; i < vec_len - 1; ++i)
+ {
+ tree elt = TREE_VEC_ELT (vec, i);
+ basic_block target_bb = label_to_block (CASE_LABEL (elt));
+ edge e = make_edge (bb2, target_bb, 0);
+
+ if (!e)
+ e = find_edge (bb2, target_bb);
+
+ e->count = 0;
+ e->probability = 0;
+
+ TREE_VEC_ELT (vec2, i - sw1_last - 1) = elt;
+ }
+ {
+ tree elt = TREE_VEC_ELT (vec, vec_len - 1);
+ basic_block target_bb = label_to_block (CASE_LABEL (elt));
+ edge e = make_edge (bb2, target_bb, 0);
+
+ if (!e)
+ e = find_edge (bb2, target_bb);
+
+ e->count = bb2->count;
+ e->probability = REG_BR_PROB_BASE;
+
+ TREE_VEC_ELT (vec2, vec_len - sw1_last - 2) = elt;
+ }
+
+ /* Update out-edges of original switch basic block */
+ for (ei = ei_start (bb_orig_sw->succs); (tmp_edge = ei_safe_edge (ei)); )
+ {
+ remove_edge (tmp_edge);
+ }
+ e1 = unchecked_make_edge (bb_orig_sw, bb1, EDGE_FALSE_VALUE);
+ e2 = unchecked_make_edge (bb_orig_sw, bb2, EDGE_TRUE_VALUE);
+ e1->probability = REG_BR_PROB_BASE / 2;
+ e1->count = bb1->count;
+ e2->probability = REG_BR_PROB_BASE - e1->probability;
+ e2->count = bb2->count;
+
+ /* TODO: probabilities of the out-edges of the new basic blocks
+ currently do not reflect those of the out-edges of the
+ original switch basic block.
+ In order to "preserve" them, the new edges should be given
+ probabilities based on the original edges, but normalized. */
+
+ /* TODO: basic block frequencies are not updated, this makes
+ the profile information sanity check to fail. */
+}
+
+/* Expand the SWITCH_EXPR pointed by NODE_PTR, composed of just
+ one case, into a COND_EXPR (or GOTO_EXPR).
+ The expansion always occurs, since generally profitable.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted,
+ new basic blocks may be created...
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_trivial_switch (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree one_case = TREE_VEC_ELT (SWITCH_LABELS (node), 0);
+ basic_block bb_sw = bb_for_stmt (bsi_stmt (*bsi));
+ basic_block bb_case = label_to_block (CASE_LABEL (one_case));
+
+ /* The switch body is lowered in gimplify.c, we should never have
+ switches with a non-NULL SWITCH_BODY here. */
+ gcc_assert (TREE_CODE (node) == SWITCH_EXPR
+ && !SWITCH_BODY (node)
+ && SWITCH_LABELS (node)
+ && TREE_VEC_LENGTH (SWITCH_LABELS (node)) == 2);
+
+ gcc_assert (stmt_ends_bb_p (node) && bb_for_stmt (node) == bb_sw);
+
+ /* Check for the easiest situation: the one case and default go
+ to the same basic block.
+ If so, SWITCH_EXPR is replaced by a GOTO_EXPR. */
+ if (single_succ_p (bb_sw))
+ {
+ tree goto_stmt;
+ edge e;
+
+ gcc_assert (bb_case
+ == label_to_block (CASE_LABEL (TREE_VEC_ELT (SWITCH_LABELS (node), 1))));
+
+ /* Build the GOTO_EXPR */
+ goto_stmt = build1 (GOTO_EXPR, void_type_node, CASE_LABEL (one_case));
+ SET_EXPR_LOCATION (goto_stmt, locus);
+
+ /* Update CFG */
+ e = find_edge (bb_sw, bb_case);
+ e->flags |= EDGE_FALLTHRU;
+
+ /* Replace the original switch with the GOTO_EXPR */
+ *node_ptr = goto_stmt;
+ set_bb_for_stmt (goto_stmt, bb_sw);
+
+ /* Update the basic block statement iterator */
+ *bsi = bsi_last (bb_sw);
+ }
+
+ /* Check whether the one case is not a range.
+ If it is not, SWITCH_EXPR is replaced by a single COND_EXPR. */
+ else if (! CASE_HIGH (one_case))
+ {
+ tree deft = TREE_VEC_ELT (SWITCH_LABELS (node), 1);
+ tree cmp_stmt;
+ basic_block bb_deft = label_to_block (CASE_LABEL (deft));
+ edge e1, e2;
+
+ /* Build the COND_EXPR */
+ cmp_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (EQ_EXPR, boolean_type_node,
+ SWITCH_COND (node),
+ CASE_LOW (one_case)),
+ build1 (GOTO_EXPR, void_type_node,
+ CASE_LABEL (one_case)),
+ build1 (GOTO_EXPR, void_type_node,
+ CASE_LABEL (deft)));
+ SET_EXPR_LOCATION (cmp_stmt, locus);
+
+ /* Update CFG */
+ e1 = find_edge (bb_sw, bb_case);
+ e2 = find_edge (bb_sw, bb_deft);
+ gcc_assert (e1 && e2 && e1 != e2);
+ gcc_assert ((e1->flags & EDGE_FALSE_VALUE) == 0);
+ gcc_assert ((e2->flags & EDGE_TRUE_VALUE) == 0);
+ e1->flags |= EDGE_TRUE_VALUE;
+ e2->flags |= EDGE_FALSE_VALUE;
+
+ /* Replace the original switch with the COND_EXPR */
+ *node_ptr = cmp_stmt;
+ set_bb_for_stmt (cmp_stmt, bb_sw);
+
+ /* Update the basic block statement iterator */
+ *bsi = bsi_last (bb_sw);
+ }
+
+ /* The one case is a range.
+ Therefore, SWITCH_EXPR is replaced by a couple of COND_EXPRs. */
+ else
+ {
+ tree deft = TREE_VEC_ELT (SWITCH_LABELS (node), 1);
+ tree label_decl = create_artificial_label ();
+ tree cmp1_stmt, cmp2_stmt, label;
+ basic_block bb_deft = label_to_block (CASE_LABEL (deft));
+ basic_block bb_new;
+ block_stmt_iterator tmp_bsi;
+ edge e1, e2, e3, e4;
+ int e1_orig_prob, e2_orig_prob;
+
+ /* Build the 1st COND_EXPR */
+ cmp1_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (GE_EXPR, boolean_type_node,
+ SWITCH_COND (node),
+ CASE_LOW (one_case)),
+ build1 (GOTO_EXPR, void_type_node, label_decl),
+ build1 (GOTO_EXPR, void_type_node,
+ CASE_LABEL (deft)));
+ SET_EXPR_LOCATION (cmp1_stmt, locus);
+
+ /* Replace the original switch with the 1st COND_EXPR */
+ *node_ptr = cmp1_stmt;
+ set_bb_for_stmt (cmp1_stmt, bb_sw);
+
+ /* Build the 2nd COND_EXPR */
+ cmp2_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (LE_EXPR, boolean_type_node,
+ SWITCH_COND (node),
+ CASE_HIGH (one_case)),
+ build1 (GOTO_EXPR, void_type_node,
+ CASE_LABEL (one_case)),
+ build1 (GOTO_EXPR, void_type_node,
+ CASE_LABEL (deft)));
+ SET_EXPR_LOCATION (cmp2_stmt, locus);
+
+ /* Create new basic block and insert the 2nd COND_EXPR */
+ bb_new = create_empty_bb (bb_sw);
+ label = build1 (LABEL_EXPR, void_type_node, label_decl);
+ tmp_bsi = bsi_start (bb_new);
+ bsi_insert_after (&tmp_bsi, label, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, cmp2_stmt, BSI_SAME_STMT);
+
+ /* Update CFG */
+ e1 = find_edge (bb_sw, bb_case);
+ e2 = find_edge (bb_sw, bb_deft);
+ gcc_assert (e1 && e2 && e1 != e2);
+ gcc_assert ((e1->flags & EDGE_FALSE_VALUE) == 0);
+ gcc_assert ((e2->flags & EDGE_TRUE_VALUE) == 0);
+ redirect_edge_succ (e1, bb_new);
+ e2->flags |= EDGE_FALSE_VALUE;
+ e3 = unchecked_make_edge (bb_new, bb_case, EDGE_TRUE_VALUE);
+ e3->flags = e1->flags | EDGE_TRUE_VALUE;;
+ e4 = unchecked_make_edge (bb_new, bb_deft, EDGE_FALSE_VALUE);
+ e4->flags = e2->flags;
+ e1->flags = EDGE_TRUE_VALUE;
+
+ /* Update edge and basic block counts */
+ e3->count = e1->count;
+ e4->count = e2->count / 2;
+ e2->count = e2->count - e4->count;
+ e1->count = e3->count + e4->count;
+ bb_new->count = e1->count;
+
+ /* Update edge probabilities */
+ e1_orig_prob = e1->probability;
+ e2_orig_prob = e2->probability;
+ e2->probability = e2_orig_prob / 2;
+ e1->probability = REG_BR_PROB_BASE - e2->probability;
+ e3->probability = (e1_orig_prob * REG_BR_PROB_BASE) / e1->probability;
+ e4->probability = REG_BR_PROB_BASE - e3->probability;
+
+ /* Update the basic block statement iterator */
+ *bsi = tmp_bsi;
+ }
+}
+
+/* Remove the ABS_EXPR pointed by NODE_PTR by inserting
+ explicit control flow.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted,
+ new basic blocks created...
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_abs (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree op;
+ tree label_decl_neg = create_artificial_label ();
+ tree label_decl_sel = create_artificial_label ();
+ tree label_neg, label_sel;
+ tree sel_var;
+ tree orig_stmt, cmp_stmt, asn_op_stmt, asn_neg_stmt;
+ basic_block bb_comp, bb_neg, bb_sel;
+ edge tmp_edge;
+ block_stmt_iterator tmp_bsi;
+ gcov_type count;
+
+ gcc_assert (TREE_CODE (node) == ABS_EXPR);
+
+ /* Insert a statement that copies the operand.
+ This is always done: it is always useful because it avoids
+ generating an extra basic block. */
+ op = TREE_OPERAND (node, 0);
+ sel_var = create_tmp_var (TREE_TYPE (op), "cilsimp");
+ asn_op_stmt = build2 (MODIFY_EXPR, TREE_TYPE (op), sel_var, op);
+ SET_EXPR_LOCATION (asn_op_stmt, locus);
+ bsi_insert_before (bsi, asn_op_stmt, BSI_SAME_STMT);
+
+ /* Insert the comparison statement */
+ cmp_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (GE_EXPR, boolean_type_node, sel_var,
+ build_int_cst (TREE_TYPE (op), 0)),
+ build1 (GOTO_EXPR, void_type_node, label_decl_sel),
+ build1 (GOTO_EXPR, void_type_node, label_decl_neg));
+ SET_EXPR_LOCATION (cmp_stmt, locus);
+ bsi_insert_before (bsi, cmp_stmt, BSI_SAME_STMT);
+
+ /* Update cfg */
+ orig_stmt = bsi_stmt (*bsi);
+ bb_comp = bb_for_stmt (orig_stmt);
+ count = bb_comp->count;
+ tmp_edge = split_block (bb_comp, cmp_stmt);
+ bb_sel = tmp_edge->dest;
+ bb_sel->count = count;
+ remove_edge (tmp_edge);
+ bb_neg = create_empty_bb (bb_comp);
+ bb_neg->count = count / 2;
+ unchecked_make_edge (bb_comp, bb_neg, EDGE_FALSE_VALUE);
+ make_single_succ_edge (bb_neg, bb_sel, EDGE_FALLTHRU);
+
+ /* Insert labels and statements into neg bb */
+ label_neg = build1 (LABEL_EXPR, void_type_node, label_decl_neg);
+ asn_neg_stmt = build2 (MODIFY_EXPR, TREE_TYPE (op),
+ sel_var,
+ build1 (NEGATE_EXPR, TREE_TYPE (op), sel_var));
+ SET_EXPR_LOCATION (asn_neg_stmt, locus);
+ tmp_bsi = bsi_start (bb_neg);
+ bsi_insert_after (&tmp_bsi, label_neg, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, asn_neg_stmt, BSI_SAME_STMT);
+
+ /* Insert a label into sel bb */
+ label_sel = build1 (LABEL_EXPR, void_type_node, label_decl_sel);
+ tmp_bsi = bsi_start (bb_sel);
+ bsi_insert_before (&tmp_bsi, label_sel, BSI_SAME_STMT);
+
+ /* Update current node in order to use the select variable */
+ *node_ptr = sel_var;
+
+ /* Update the basic block statement iterator */
+ gcc_assert (bsi_stmt (tmp_bsi) == orig_stmt);
+ *bsi = tmp_bsi;
+}
+
+/* Remove the MAX_EXPR or MIN_EXPR pointed by NODE_PTR by inserting
+ explicit control flow.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted,
+ new basic blocks created...
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_min_max (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ bool is_max;
+ tree op0, op1;
+ tree label_decl_op0 = create_artificial_label ();
+ tree label_decl_op1 = create_artificial_label ();
+ tree label_op0, label_op1;
+ tree sel_var;
+ tree orig_stmt, cmp_stmt, asn_op0_stmt, asn_op1_stmt;
+ basic_block bb_comp, bb_op0, bb_op1, bb_sel;
+ edge tmp_edge;
+ block_stmt_iterator tmp_bsi;
+ gcov_type count;
+
+ gcc_assert (TREE_CODE (node) == MAX_EXPR || TREE_CODE (node) == MIN_EXPR);
+ is_max = (TREE_CODE (node) == MAX_EXPR);
+
+ /* Make sure that the two operands have no side effects */
+ op0 = TREE_OPERAND (node, 0);
+ if (is_copy_required (op0))
+ {
+ tree var = create_tmp_var (TREE_TYPE (op0), "cilsimp");
+ tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (op0), var, op0);
+
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
+ TREE_OPERAND (node, 0) = var;
+ op0 = var;
+ }
+ op1 = TREE_OPERAND (node, 1);
+ if (is_copy_required (op1))
+ {
+ tree var = create_tmp_var (TREE_TYPE (op1), "cilsimp");
+ tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (op1), var, op1);
+
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
+ TREE_OPERAND (node, 1) = var;
+ op1 = var;
+ }
+
+ /* Insert the comparison statement */
+ cmp_stmt = build3 (COND_EXPR, void_type_node,
+ build2 (is_max ? GT_EXPR : LT_EXPR,
+ boolean_type_node, op0, op1),
+ build1 (GOTO_EXPR, void_type_node, label_decl_op0),
+ build1 (GOTO_EXPR, void_type_node, label_decl_op1));
+ SET_EXPR_LOCATION (cmp_stmt, locus);
+ bsi_insert_before (bsi, cmp_stmt, BSI_SAME_STMT);
+
+ /* Update cfg */
+ orig_stmt = bsi_stmt (*bsi);
+ bb_comp = bb_for_stmt (orig_stmt);
+ count = bb_comp->count;
+ tmp_edge = split_block (bb_comp, cmp_stmt);
+ bb_sel = tmp_edge->dest;
+ bb_sel->count = count;
+ remove_edge (tmp_edge);
+ bb_op0 = create_empty_bb (bb_comp);
+ bb_op1 = create_empty_bb (bb_op0);
+ bb_op0->count = count / 2;
+ bb_op1->count = count - bb_op0->count;
+ unchecked_make_edge (bb_comp, bb_op0, EDGE_TRUE_VALUE);
+ make_single_succ_edge (bb_op0, bb_sel, EDGE_FALLTHRU);
+ unchecked_make_edge (bb_comp, bb_op1, EDGE_FALSE_VALUE);
+ make_single_succ_edge (bb_op1, bb_sel, EDGE_FALLTHRU);
+
+ /* Insert labels and statements into op0 bb */
+ sel_var = create_tmp_var (TREE_TYPE (node), "cilsimp");
+ label_op0 = build1 (LABEL_EXPR, void_type_node, label_decl_op0);
+ asn_op0_stmt = build2 (MODIFY_EXPR, TREE_TYPE (op0), sel_var, op0);
+ SET_EXPR_LOCATION (asn_op0_stmt, locus);
+ tmp_bsi = bsi_start (bb_op0);
+ bsi_insert_after (&tmp_bsi, label_op0, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, asn_op0_stmt, BSI_SAME_STMT);
+
+ /* Insert labels and statements into op1 bb */
+ label_op1 = build1 (LABEL_EXPR, void_type_node, label_decl_op1);
+ asn_op1_stmt = build2 (MODIFY_EXPR, TREE_TYPE (op1), sel_var, op1);
+ SET_EXPR_LOCATION (asn_op1_stmt, locus);
+ tmp_bsi = bsi_start (bb_op1);
+ bsi_insert_after (&tmp_bsi, label_op1, BSI_NEW_STMT);
+ bsi_insert_after (&tmp_bsi, asn_op1_stmt, BSI_SAME_STMT);
+
+ /* Update current node in order to use the select variable */
+ *node_ptr = sel_var;
+
+ /* Update the basic block statement iterator */
+ gcc_assert (bsi_stmt (bsi_start (bb_sel)) == orig_stmt);
+ *bsi = bsi_start (bb_sel);
+}
+
+/* Remove the LROTATE_EXPR or RROTATE_EXPR pointed by NODE_PTR
+ by inserting shifts and bit operations.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted,
+ new basic blocks created...
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_rotate (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ bool left = (TREE_CODE (node) == LROTATE_EXPR);
+ tree op0_uns_type;
+ tree op0, op1;
+ tree t1, t2;
+
+ gcc_assert (TREE_CODE (node) == LROTATE_EXPR
+ || TREE_CODE (node) == RROTATE_EXPR);
+
+ /* Rotation is replaced by shifts on unsigned values:
+ generate the unsigned version of first operand type. */
+ op0 = TREE_OPERAND (node, 0);
+ op0_uns_type = build_distinct_type_copy (TREE_TYPE (op0));
+ TYPE_UNSIGNED (op0_uns_type) = 1;
+ op0 = fold_convert (op0_uns_type, op0);
+
+ /* Convert the second operand to 32-bit */
+ op1 = fold_convert (uint32_type, TREE_OPERAND (node, 1));
+
+ /* Make sure that the two operands have no side effects */
+ if (is_copy_required (op0))
+ {
+ tree var = create_tmp_var (TREE_TYPE (op0), "cilsimp");
+ tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (op0), var, op0);
+
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
+ TREE_OPERAND (node, 0) = var;
+ op0 = var;
+ }
+ if (is_copy_required (op1))
+ {
+ tree var = create_tmp_var (TREE_TYPE (op1), "cilsimp");
+ tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (op1), var, op1);
+
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
+ TREE_OPERAND (node, 1) = var;
+ op1 = var;
+ }
+
+ /* Build first shift */
+ t1 = build2 (left ? LSHIFT_EXPR : RSHIFT_EXPR, op0_uns_type,
+ op0,
+ op1);
+
+ /* Build second shift */
+ t2 = fold_build2 (left ? RSHIFT_EXPR : LSHIFT_EXPR, op0_uns_type,
+ op0,
+ build2 (MINUS_EXPR, uint32_type,
+ fold_convert (uint32_type,
+ TYPE_SIZE (TREE_TYPE (op0))),
+ op1));
+
+ /* Gimplify the two shifts */
+ t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL);
+ t2 = force_gimple_operand_bsi (bsi, t2, TRUE, NULL);
+
+ /* Build the rotate result and gimplify it */
+ t1 = build2 (BIT_IOR_EXPR, op0_uns_type, t1, t2);
+ t1 = fold_convert (TREE_TYPE (TREE_OPERAND (node, 0)), t1);
+ t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL);
+
+ /* Update the current node */
+ *node_ptr = t1;
+}
+
+/* Given the LSHIFT_EXPR or RSHIFT_EXPR
+ in NODE with the second operand of an integer type bigger than
+ 32 bits, convert such operand to a 32-bit type.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted. */
+
+static void
+simp_shift (block_stmt_iterator *bsi, tree node)
+{
+ tree t;
+
+ gcc_assert (TREE_CODE (node) == LSHIFT_EXPR
+ || TREE_CODE (node) == RSHIFT_EXPR);
+
+ /* Generate the type conversion */
+ t = fold_convert (uint32_type, TREE_OPERAND (node, 1));
+
+ /* Gimplify the equivalent expression and update the current node */
+ TREE_OPERAND (node, 1) = force_gimple_operand_bsi (bsi, t, FALSE, NULL);
+}
+
+/* Expand the TARGET_MEM_REF pointed by NODE_PTR by inserting
+ the equivalent sums and multiplication.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted.
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_target_mem_ref (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ tree t1, t2;
+
+ gcc_assert (TREE_CODE (node) == TARGET_MEM_REF);
+
+ /* Generate the equivalent expression */
+
+ if (TMR_BASE (node))
+ {
+ if (TMR_SYMBOL (node))
+ t1 = build2 (PLUS_EXPR, TREE_TYPE (TMR_BASE (node)),
+ TMR_BASE (node),
+ TMR_SYMBOL (node));
+ else
+ t1 = TMR_BASE (node);
+ }
+ else
+ t1 = TMR_SYMBOL (node);
+
+ if (TMR_INDEX (node))
+ {
+ if (TMR_STEP (node))
+ t2 = build2 (MULT_EXPR, TREE_TYPE (TMR_INDEX (node)),
+ TMR_INDEX (node),
+ TMR_STEP (node));
+ else
+ t2 = TMR_INDEX (node);
+
+ gcc_assert (t2);
+ if (TMR_OFFSET (node))
+ t2 = build2 (PLUS_EXPR, TREE_TYPE (t2),
+ TMR_OFFSET (node),
+ t2);
+ }
+ else
+ {
+ gcc_assert (! TMR_STEP (node));
+ t2 = TMR_OFFSET (node);
+ }
+
+ if (t1)
+ {
+ if (t2)
+ t1 = build2 (PLUS_EXPR, TREE_TYPE (t1), t1, t2);
+ }
+ else
+ t1 = t2;
+
+ gcc_assert (t1 && t1 != error_mark_node);
+ t1 = build1 (INDIRECT_REF, TREE_TYPE (node), t1);
+
+ /* Gimplify the equivalent expression and update the current node */
+ *node_ptr = force_gimple_operand_bsi (bsi, t1, FALSE, NULL);
+}
+
+/* Expand the ARRAY_REF pointed by NODE_PTR by inserting
+ the equivalent sums and multiplication.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted.
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_array_ref (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree base, index;
+ tree base_type;
+ tree t1, t2;
+ tree tmp_var, tmp_stmt;
+
+ gcc_assert (TREE_CODE (node) == ARRAY_REF);
+
+ base = TREE_OPERAND (node, 0);
+ index = TREE_OPERAND (node, 1);
+
+ /* The type of base is a pointer, no longer an array! */
+ base_type = build0 (POINTER_TYPE, TREE_TYPE (TREE_TYPE (base)));
+ layout_type (base_type);
+
+ /* Generate the equivalent gimplified expression */
+
+ t1 = fold_convert (long_integer_type_node, index);
+ t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL);
+ gcc_assert (t1 && t1 != error_mark_node);
+
+ t2 = fold_convert (long_integer_type_node, array_ref_element_size (node));
+ t2 = force_gimple_operand_bsi (bsi, t2, TRUE, NULL);
+ gcc_assert (t2 && t2 != error_mark_node);
+
+ if (TREE_CODE (t1) == INTEGER_CST
+ && (double_int_zero_p (TREE_INT_CST (t1))
+ || double_int_one_p (TREE_INT_CST (t1))))
+ {
+ if (double_int_one_p (TREE_INT_CST (t1)))
+ t1 = t2;
+ }
+ else if (TREE_CODE (t2) == INTEGER_CST
+ && (double_int_zero_p (TREE_INT_CST (t2))
+ || double_int_one_p (TREE_INT_CST (t2))))
+ {
+ if (double_int_zero_p (TREE_INT_CST (t2)))
+ t1 = t2;
+ }
+ else
+ {
+ tmp_var = create_tmp_var (long_integer_type_node, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, long_integer_type_node,
+ tmp_var,
+ fold_build2 (MULT_EXPR, long_integer_type_node,
+ t1,
+ t2));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t1 = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+ gcc_assert (t1 && t1 != error_mark_node);
+
+ tmp_var = create_tmp_var (base_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, base_type,
+ tmp_var,
+ build1 (ADDR_EXPR, base_type, base));
+ gcc_assert (TREE_CODE (base) != CALL_EXPR);
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t2 = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ if (TREE_CODE (t1) == INTEGER_CST
+ && double_int_zero_p (TREE_INT_CST (t1)))
+ {
+ t1 = t2;
+ }
+ else
+ {
+ tmp_var = create_tmp_var (base_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, base_type,
+ tmp_var,
+ build2 (PLUS_EXPR, base_type,
+ t2,
+ t1));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t1 = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+ gcc_assert (t1 && t1 != error_mark_node);
+
+ /* Update the current node */
+ *node_ptr = build1 (INDIRECT_REF, TREE_TYPE (node), t1);
+}
+
+/* Expand the COMPONENT_REF (pointed by NODE_PTR) accessing
+ a BIT_FIELD_DECL and being on a right-hand side by transforming it
+ into an INDIRECT_REF and applying the necessary bit mask operations.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted.
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_rhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree obj = TREE_OPERAND (node, 0);
+ tree fld = TREE_OPERAND (node, 1);
+ tree fld_type, fld_off ;
+ unsigned int cont_size, bfld_size, bfld_off;
+ tree new_type, obj_ptr_type;
+ tree tmp_var, tmp_stmt;
+ tree t;
+ HOST_WIDEST_INT off;
+
+ gcc_assert (TREE_CODE (node) == COMPONENT_REF);
+ gcc_assert (DECL_BIT_FIELD (fld));
+
+ /* Extract bit field layout */
+ fld_type = DECL_BIT_FIELD_TYPE (fld);
+ fld_off = DECL_FIELD_OFFSET (fld);
+ cont_size = TREE_INT_CST_LOW (TYPE_SIZE (fld_type));
+ bfld_size = TYPE_PRECISION (TREE_TYPE (fld));
+ bfld_off = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld)) & (cont_size - 1);
+ gcc_assert (cont_size >= TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))));
+
+ /* Build the type corresponding of a pointer to the object */
+ obj_ptr_type = build0 (POINTER_TYPE, TREE_TYPE (obj));
+ layout_type (obj_ptr_type);
+
+ /* Build the new type for the equivalent access */
+ new_type = get_unsigned_integer_type (cont_size);
+
+ /* Build the (gimplified) equivalent expression */
+
+ tmp_var = create_tmp_var (obj_ptr_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, obj_ptr_type,
+ tmp_var,
+ build1 (ADDR_EXPR, obj_ptr_type, obj));
+ gcc_assert (TREE_CODE (obj) != CALL_EXPR);
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ off = TREE_INT_CST_LOW (fld_off)
+ + ((TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld))
+ & ~(cont_size - 1))
+ / 8);
+
+ gcc_assert (TREE_INT_CST_HIGH (fld_off) == 0);
+
+ if (off > 0)
+ {
+ tmp_var = create_tmp_var (obj_ptr_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, obj_ptr_type,
+ tmp_var,
+ build2 (PLUS_EXPR, obj_ptr_type,
+ t,
+ build_int_cst (long_integer_type_node, off)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build1 (INDIRECT_REF, new_type, t));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ if (cont_size > bfld_size + bfld_off)
+ {
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (LSHIFT_EXPR, new_type,
+ t,
+ build_int_cstu (uint32_type,
+ cont_size
+ - bfld_size - bfld_off)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+
+ if (cont_size > bfld_size)
+ {
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (RSHIFT_EXPR, new_type,
+ t,
+ build_int_cstu (uint32_type,
+ cont_size - bfld_size)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+
+ gcc_assert (t && t != error_mark_node);
+
+ /* Update the current node */
+ *node_ptr = fold_convert (TREE_TYPE (node), t);
+}
+
+/* Expand the COMPONENT_REF (pointed by NODE_PTR) accessing
+ a BIT_FIELD_DECL and being on a left-hand side by transforming it
+ into an INDIRECT_REF and applying the necessary bit mask operations.
+ BSI points to the iterator of the statement that contains *NODE_PTR
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted.
+ NODE is passed by reference because simplification requires
+ replacing the node. */
+
+static void
+simp_lhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree obj = TREE_OPERAND (node, 0);
+ tree fld = TREE_OPERAND (node, 1);
+ tree fld_type, fld_off ;
+ unsigned int cont_size, bfld_size, bfld_off;
+ tree stmt = bsi_stmt (*bsi), rhs, addr;
+ tree new_type, obj_ptr_type;
+ tree tmp_var, tmp_stmt;
+ tree t;
+ HOST_WIDEST_INT off;
+ unsigned HOST_WIDEST_INT mask = 0;
+
+ gcc_assert (TREE_CODE (node) == COMPONENT_REF);
+ gcc_assert (DECL_BIT_FIELD (fld));
+ gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR
+ && TREE_OPERAND (stmt, 0) == node);
+
+ /* Extract bit field layout */
+ fld_type = DECL_BIT_FIELD_TYPE (fld);
+ fld_off = DECL_FIELD_OFFSET (fld);
+ cont_size = TREE_INT_CST_LOW (TYPE_SIZE (fld_type));
+ bfld_size = TYPE_PRECISION (TREE_TYPE (fld));
+ bfld_off = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld)) & (cont_size - 1);
+ gcc_assert (cont_size >= TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))));
+
+ /* Build the new type for the equivalent access */
+ new_type = get_unsigned_integer_type (cont_size);
+
+ /* Build the type corresponding of a pointer to the object */
+ obj_ptr_type = build0 (POINTER_TYPE, TREE_TYPE (obj));
+ layout_type (obj_ptr_type);
+
+ /* Convert the original rhs into the new type */
+ gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 1)) == VAR_DECL);
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build1 (NOP_EXPR, new_type, TREE_OPERAND (stmt, 1)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ rhs = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ /* Shift the rhs in order that it is in the right bit position */
+ if (cont_size > bfld_size)
+ {
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (LSHIFT_EXPR, new_type,
+ rhs,
+ build_int_cstu (uint32_type,
+ cont_size - bfld_size)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ rhs = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+ if (cont_size > bfld_size + bfld_off)
+ {
+ /* Remark: new_type is unsigned by construction:
+ therefore, the right shift doesn't introduce any 1 */
+
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (RSHIFT_EXPR, new_type,
+ rhs,
+ build_int_cstu (uint32_type,
+ cont_size
+ - bfld_size - bfld_off)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ rhs = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+
+ /* Build expression to compute the address to be accessed */
+ tmp_var = create_tmp_var (obj_ptr_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, obj_ptr_type,
+ tmp_var,
+ build1 (ADDR_EXPR, obj_ptr_type, obj));
+ gcc_assert (TREE_CODE (obj) != CALL_EXPR);
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ off = TREE_INT_CST_LOW (fld_off)
+ + ((TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld))
+ & ~(cont_size - 1))
+ / 8);
+
+ gcc_assert (TREE_INT_CST_HIGH (fld_off) == 0);
+
+ if (off > 0)
+ {
+ tmp_var = create_tmp_var (obj_ptr_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, obj_ptr_type,
+ tmp_var,
+ build2 (PLUS_EXPR, obj_ptr_type,
+ t,
+ build_int_cst (long_integer_type_node, off)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+ }
+ addr = t;
+
+ /* Read existing value at the address just computed */
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build1 (INDIRECT_REF, new_type, t));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ /* Compute the mask to be applied to the existing value */
+ gcc_assert (HOST_BITS_PER_WIDEST_INT >= 64);
+ mask |= (1 << (cont_size - bfld_size - bfld_off)) - 1;
+ mask <<= bfld_off + bfld_size;
+ mask |= (1 << bfld_off) - 1;
+
+ /* Apply the mask to the existing value */
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (BIT_AND_EXPR, new_type,
+ t,
+ build_int_cstu (new_type, mask)));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ t = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ /* Compute the new value for the rhs of the current statement */
+ tmp_var = create_tmp_var (new_type, "cilsimp");
+ tmp_stmt = build2 (MODIFY_EXPR, new_type,
+ tmp_var,
+ build2 (BIT_IOR_EXPR, new_type,
+ rhs,
+ t));
+ SET_EXPR_LOCATION (tmp_stmt, locus);
+ rhs = tmp_var;
+ bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
+
+ /* Update the current statement (and the current node) */
+ *node_ptr = build1 (INDIRECT_REF, new_type, addr);
+ TREE_OPERAND (stmt, 1) = rhs;
+}
+
+/* Expand the INIT_EXPR (or MODIFY_EXPR) in NODE having
+ a CONSTRUCTOR or STRING_CST on the right side into a sequence
+ of simpler (here, it means "not involving CONSTRUCTOR or
+ STRING_CST nodes) initializer statements.
+ Beware that, differently from most simplification functions,
+ this expansion leaves GIMPLE nodes that need further simplifications;
+ hence, this function should only be called during
+ the pre-simplification.
+ BSI points to the iterator of the statement that contains NODE
+ (in order to allow insertion of new statements).
+ BSI is passed by reference because instructions are inserted. */
+
+static void
+pre_simp_init (block_stmt_iterator *bsi, tree node)
+{
+ location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
+ tree lhs = TREE_OPERAND (node, 0);
+ tree rhs = TREE_OPERAND (node, 1);
+ tree stmt_list = 0;
+ block_stmt_iterator tmp_bsi;
+ tree_stmt_iterator i;
+
+ gcc_assert (bsi_stmt (*bsi) == node);
+ gcc_assert (TREE_CODE (node) == INIT_EXPR
+ || TREE_CODE (node) == MODIFY_EXPR);
+ gcc_assert (TREE_CODE (rhs) == CONSTRUCTOR || TREE_CODE (rhs) == STRING_CST);
+
+ /* Expand the constructor into a separate statement list */
+ expand_init_to_stmt_list (lhs, rhs, &stmt_list, FALSE);
+ gcc_assert (TREE_CODE (stmt_list) == STATEMENT_LIST);
+
+ /* Gimplify the new statements and insert them */
+ tmp_bsi = *bsi;
+ for (i = tsi_start (stmt_list); !tsi_end_p (i); tsi_next (&i))
+ {
+ tree stmt;
+
+ /* Gimplify the new statement */
+ gimplify_stmt (tsi_stmt_ptr (i));
+
+ /* Insert the new statements before the old */
+ stmt = tsi_stmt (i);
+ if (TREE_CODE (stmt) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator j;
+
+ for (j = tsi_start (stmt); !tsi_end_p (j); tsi_next (&j))
+ {
+ tree t = tsi_stmt (j);
+
+ SET_EXPR_LOCATION (t, locus);
+ bsi_insert_after (&tmp_bsi, t, BSI_NEW_STMT);
+ }
+ }
+ else if (stmt != NULL)
+ {
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_after (&tmp_bsi, stmt, BSI_NEW_STMT);
+ }
+ }
+
+ /* Remove the old statement */
+ bsi_remove (bsi, false);
+
+ /* Update the basic block statement iterator */
+ *bsi = tmp_bsi;
+}
+
+/* Make sure that the tree pointed by NODE_PTR is a VAR_DECL.
+ In case, split the statement containing NODE_PTR into two
+ by creating a new local variable.
+ BSI points to the iterator of the statement that contains NODE_PTR
+ (in order to allow insertion of new statements). */
+
+static void
+split_use (block_stmt_iterator bsi, tree *node_ptr)
+{
+ tree node = *node_ptr;
+ location_t locus = EXPR_LOCATION (bsi_stmt (bsi));
+ tree type = TREE_TYPE (node);
+ tree var, stmt;
+
+ if (TREE_CODE (node) == VAR_DECL)
+ return;
+
+ /* Split the current statement by creating a new local variable */
+ var = create_tmp_var (type, "cilsimp");
+ stmt = build2 (MODIFY_EXPR, type, var, node);
+ SET_EXPR_LOCATION (stmt, locus);
+ bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
+ *node_ptr = var;
+}
+
+/* Return TRUE if EXP contains mostly (3/4) zeros. */
+static bool
+mostly_zeros_p (tree exp)
+{
+ HOST_WIDE_INT nz_elts, count, elts;
+ bool must_clear;
+
+ gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+
+ categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+
+ if (must_clear)
+ return TRUE;
+
+ elts = count_type_elements (TREE_TYPE (exp), false);
+
+ return (nz_elts < elts / 4);
+}
+
+/* Return TRUE if EXP contains all zeros. */
+static bool
+all_zeros_p (tree exp)
+{
+ HOST_WIDE_INT nz_elts, count;
+ bool must_clear;
+
+ gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
+
+ categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+
+ return (nz_elts == 0);
+}
+
+/* Expand the initialization of tree DECL to tree INIT
+ into the statement list pointed by STMT_LIST.
+ Beware that statements inserted into the list cannot be assumed
+ to be in GIMPLE form and/or simplified for CIL.
+ If GIMPLE CIL-simplified statements are required, explicit
+ gimplification and CIL simplification have to be performed on them.
+ CLEARED tells whether unmentioned fields in the initializer
+ statement may be considered already initialized to zero or not.
+ The expansion is especially meant to expand a CONSTRUCTOR into
+ an equivalent statement sequence; anyway, any initialization
+ is properly handled: in case of no expansion, a simple MODIFY_EXPR
+ is appended to STMT_LIST.
+ STMT_LIST may be NULL; in this case a statement list is allocated.
+*/
+
+void
+expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared)
+{
+ tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+ unsigned int size = TREE_INT_CST_LOW (decl_size);
+ bool need_to_clear = FALSE;
+
+ if (! *stmt_list)
+ {
+ *stmt_list = alloc_stmt_list ();
+ }
+
+ gcc_assert (TREE_CODE (*stmt_list) == STATEMENT_LIST);
+
+ if (TREE_CODE (init) == CONST_DECL)
+ {
+ init = DECL_INITIAL (init);
+ gcc_assert (init && init != error_mark_node);
+ }
+
+ if (! cleared && TREE_CODE (init) == CONSTRUCTOR && all_zeros_p (init))
+ {
+ tree args, t, decl_ptr;
+
+ args = tree_cons (NULL, decl_size, NULL);
+ args = tree_cons (NULL, integer_zero_node, args);
+ decl_ptr = build_fold_addr_expr (decl);
+ args = tree_cons (NULL, decl_ptr, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMSET];
+ t = build_function_call_expr (t, args);
+
+ append_to_statement_list (t, stmt_list);
+
+ return;
+ }
+
+ switch (TREE_CODE (init))
+ {
+ case STRING_CST:
+ {
+ tree args, t, to_ptr, from_ptr;
+
+ gcc_assert (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
+
+ args = tree_cons (NULL, decl_size, NULL);
+
+ from_ptr = build_fold_addr_expr (init);
+ args = tree_cons (NULL, from_ptr, args);
+
+ to_ptr = build_fold_addr_expr (decl);
+ args = tree_cons (NULL, to_ptr, args);
+
+ /* We know they do not overlap */
+ t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ t = build_function_call_expr (t, args);
+
+ append_to_statement_list (t, stmt_list);
+ }
+ break;
+
+ case CONSTRUCTOR:
+ switch (TREE_CODE (TREE_TYPE (init)))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ unsigned HOST_WIDE_INT idx;
+ tree init_type = TREE_TYPE (init);
+ tree field, value;
+
+ /* If size is zero or the target is already cleared, do nothing */
+ if (size == 0 || cleared)
+ {
+ need_to_clear = FALSE;
+ cleared = TRUE;
+ }
+
+ /* We either clear the aggregate or indicate the value is dead. */
+ else if ((TREE_CODE (init_type) == UNION_TYPE
+ || TREE_CODE (init_type) == QUAL_UNION_TYPE)
+ && ! CONSTRUCTOR_ELTS (init))
+ /* If the constructor is empty, clear the union. */
+ need_to_clear = TRUE;
+
+ /* If the constructor has fewer fields than the structure or
+ if we are initializing the structure to mostly zeros, clear
+ the whole structure first. */
+ else if (size > 0
+ && (((int)VEC_length (constructor_elt,
+ CONSTRUCTOR_ELTS (init))
+ != fields_length (init_type))
+ || mostly_zeros_p (init)))
+ need_to_clear = TRUE;
+
+ if (need_to_clear && size > 0)
+ {
+ tree args, t, decl_ptr;
+
+ args = tree_cons (NULL, decl_size, NULL);
+ args = tree_cons (NULL, integer_zero_node, args);
+ decl_ptr = build_fold_addr_expr (decl);
+ args = tree_cons (NULL, decl_ptr, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMSET];
+ t = build_function_call_expr (t, args);
+
+ append_to_statement_list (t, stmt_list);
+
+ cleared = TRUE;
+ }
+
+ /* Store each element of the constructor into the
+ corresponding field of TARGET. */
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx,
+ field, value)
+ {
+ tree ltarget;
+
+ /* Just ignore missing fields. We cleared the whole
+ structure, above, if any fields are missing. */
+ if (field == 0)
+ continue;
+
+ if (cleared && initializer_zerop (value))
+ continue;
+
+ ltarget = build3 (COMPONENT_REF, TREE_TYPE (field), decl,
+ field, NULL);
+
+ expand_init_to_stmt_list (ltarget, value, stmt_list, cleared);
+ }
+ }
+ break;
+
+ case ARRAY_TYPE:
+ {
+ tree value, index;
+ unsigned HOST_WIDE_INT i;
+ tree domain;
+ tree elttype = TREE_TYPE (TREE_TYPE (init));
+ int const_bounds_p;
+ HOST_WIDE_INT minelt = 0;
+ HOST_WIDE_INT maxelt = 0;
+
+ domain = TYPE_DOMAIN (TREE_TYPE (init));
+ const_bounds_p = (TYPE_MIN_VALUE (domain)
+ && TYPE_MAX_VALUE (domain)
+ && host_integerp (TYPE_MIN_VALUE (domain), 0)
+ && host_integerp (TYPE_MAX_VALUE (domain), 0));
+
+ /* If we have constant bounds for the range
+ of the type, get them. */
+ if (const_bounds_p)
+ {
+ minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
+ maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
+ }
+
+ /* If the constructor has fewer elements than the array, clear
+ the whole array first. */
+ if (cleared)
+ need_to_clear = FALSE;
+ else
+ {
+ unsigned HOST_WIDE_INT idx;
+ tree index, value;
+ HOST_WIDE_INT count = 0;
+ HOST_WIDE_INT zero_count = 0;
+ need_to_clear = ! const_bounds_p;
+
+ /* This loop is a more accurate version of the loop in
+ mostly_zeros_p (it handles RANGE_EXPR in an index). It
+ is also needed to check for missing elements. */
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx,
+ index, value)
+ {
+ HOST_WIDE_INT this_node_count;
+
+ if (need_to_clear)
+ break;
+
+ if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
+ {
+ tree lo_index = TREE_OPERAND (index, 0);
+ tree hi_index = TREE_OPERAND (index, 1);
+
+ if (! host_integerp (lo_index, 1)
+ || ! host_integerp (hi_index, 1))
+ {
+ need_to_clear = TRUE;
+ break;
+ }
+
+ this_node_count = tree_low_cst (hi_index, 1)
+ - tree_low_cst (lo_index, 1) + 1;
+ }
+ else
+ this_node_count = 1;
+
+ count += this_node_count;
+ if (TREE_CODE (value) == CONSTRUCTOR
+ && mostly_zeros_p (value))
+ zero_count += this_node_count;
+ }
+
+ /* Clear the entire array first if there are any missing
+ elements, or if the incidence of zero elements is >=
+ 75%. */
+ if (! need_to_clear
+ && (count < maxelt - minelt + 1
+ || 4 * zero_count >= 3 * count))
+ need_to_clear = TRUE;
+ }
+
+ if (need_to_clear && size > 0)
+ {
+ tree args, t, decl_ptr;
+
+ args = tree_cons (NULL, decl_size, NULL);
+ args = tree_cons (NULL, integer_zero_node, args);
+ decl_ptr = build_fold_addr_expr (decl);
+ args = tree_cons (NULL, decl_ptr, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMSET];
+ t = build_function_call_expr (t, args);
+
+ append_to_statement_list (t, stmt_list);
+
+ cleared = TRUE;
+ }
+
+ /* Store each element of the constructor into the
+ corresponding element of TARGET, determined by counting the
+ elements. */
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, index, value)
+ {
+ enum machine_mode mode;
+ HOST_WIDE_INT bitsize;
+ int unsignedp;
+ tree t;
+
+ if (initializer_zerop (value))
+ continue;
+
+ unsignedp = TYPE_UNSIGNED (elttype);
+ mode = TYPE_MODE (elttype);
+
+ if (mode == BLKmode)
+ bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
+ ? tree_low_cst (TYPE_SIZE (elttype), 1)
+ : -1);
+ else
+ bitsize = GET_MODE_BITSIZE (mode);
+
+ gcc_assert (index == NULL_TREE
+ || TREE_CODE (index) != RANGE_EXPR);
+
+ if (minelt)
+ index = fold_convert (ssizetype,
+ fold_build2 (MINUS_EXPR,
+ TREE_TYPE (index),
+ index,
+ TYPE_MIN_VALUE (domain)));
+
+ t = build4 (ARRAY_REF, elttype, decl, index, NULL, NULL);
+ expand_init_to_stmt_list (t, value, stmt_list, cleared);
+ }
+ }
+ break;
+
+ case VECTOR_TYPE:
+ fprintf (stderr, "CIL: Cannot handle rhs: ");
+ debug_generic_expr (init);
+ gcc_assert (0);
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ break;
+
+ default:
+ append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (decl),
+ decl, init),
+ stmt_list);
+ break;
+ }
+}
+
+/* Rename a single variable using the specified suffix */
+
+static void
+rename_var (tree var, const char* suffix)
+{
+ const char *orig_name = IDENTIFIER_POINTER (DECL_NAME (var));
+ char *newsym = alloca (strlen (orig_name) + strlen (suffix) + 10 + 1);
+ DECL_NAME (var) = get_identifier_with_length (newsym,
+ sprintf (newsym,
+ "%s%s%lu",
+ orig_name,
+ suffix,
+ (unsigned long)var));
+}
+
+/* Simplify variables: rename inlined variables
+ rename and globalize function static variables
+ inline init for local variables. */
+
+static void
+simp_vars (void)
+{
+ block_stmt_iterator bsi = bsi_start (ENTRY_BLOCK_PTR);
+ tree *p = &cfun->unexpanded_var_list;
+
+ for (; *p; )
+ {
+ tree var = TREE_VALUE (*p);
+ tree init = DECL_INITIAL (var);
+
+ if (TREE_STATIC (var) && DECL_CONTEXT (var) != 0)
+ {
+ rename_var (var, "?fs");
+ DECL_CONTEXT (var) = 0;
+ }
+
+ if (DECL_FROM_INLINE (var) && DECL_NAME (var) != NULL)
+ rename_var (var, "?in");
+
+ if (!TREE_STATIC (var) && init && init != error_mark_node)
+ {
+ /* DECL_INITIAL (var) = NULL_TREE; */
+ bsi_insert_after (&bsi,
+ build2 (INIT_EXPR, TREE_TYPE (var), var, init),
+ BSI_NEW_STMT);
+ }
+
+ p = &TREE_CHAIN (*p);
+ }
+}
+
+/* Simplify pass that makes CIL emission easier. */
+
+static unsigned int
+simp_cil (void)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+
+ res_var = NULL_TREE;
+ uint32_type = get_unsigned_integer_type (32);
+
+ simp_vars ();
+
+ /* Some pre-simplification is needed for INIT_EXPR and MODIFY_EXPR:
+ *) in their expansion, it's sometimes convenient to generate ARRAY_REF
+ nodes, which require further simplification.
+ *) if the lhs is a bitfield COMPONENT_REF, then the rhs must be
+ a VAR_DECL because the following simplification pass expects
+ that. */
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+
+ if (TREE_CODE (stmt) == INIT_EXPR || TREE_CODE (stmt) == MODIFY_EXPR)
+ {
+ tree lhs = TREE_OPERAND (stmt, 0);
+ tree rhs = TREE_OPERAND (stmt, 1);
+
+ if (TREE_CODE (rhs) == CONSTRUCTOR
+ || TREE_CODE (rhs) == STRING_CST)
+ pre_simp_init (&bsi, stmt);
+ else if (TREE_CODE (lhs) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (lhs, 1)))
+ split_use (bsi, &TREE_OPERAND (stmt, 1));
+ }
+ }
+ }
+
+ /* Statement simplification loop.
+ At this point, the code is still in proper GIMPLE form,
+ but with no constructors nor string initializers. */
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree *stmt_ptr = bsi_stmt_ptr (bsi);
+ simp_cil_node (&bsi, stmt_ptr);
+ bb = bb_for_stmt (*stmt_ptr);
+ }
+ }
+
+#if 0
+ FOR_EACH_BB (bb)
+ {
+ dump_generic_bb (stdout, bb, 4, 0);
+ }
+#endif
+
+ return 0;
+}
+
+/* Gate function of CIL simplify pass. */
+
+static bool
+simp_cil_gate (void)
+{
+ return current_function_decl != NULL;
+}
+
+/* Define the parameters of the tree-simp-CIL pass. */
+
+struct tree_opt_pass pass_simp_cil =
+{
+ "simpcil", /* name */
+ simp_cil_gate, /* gate */
+ simp_cil, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REST_OF_COMPILATION, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ /* ??? If TER is enabled, we also kill gimple. */
+ 0, /* properties_destroyed */
+ 0,
+ 0,
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/tree-simp-cil.h b/gcc/config/cil32/tree-simp-cil.h
new file mode 100644
index 00000000000..51f0970a707
--- /dev/null
+++ b/gcc/config/cil32/tree-simp-cil.h
@@ -0,0 +1,39 @@
+/* CIL simplification definitions for GNU compiler.
+
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+Authors:
+ Andrea Bona
+ Andrea Ornstein
+ Erven Rohou
+ Roberto Costa
+
+Contact information at STMicroelectronics:
+Roberto Costa <roberto.costa@st.com> */
+
+#ifndef TREE_SIMP_CIL_H
+#define TREE_SIMP_CIL_H
+
+#include "tree.h"
+
+void
+expand_init_to_stmt_list (tree, tree, tree *, bool);
+
+#endif /* TREE_SIMP_CIL_H */
diff --git a/gcc/opts.c b/gcc/opts.c
index 01ec30d6ceb..c4cc2f436dd 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1123,9 +1123,10 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg)
write_symbols = DBX_DEBUG;
#endif
}
-
+#ifndef DISABLE_RTL_PASSES
if (write_symbols == NO_DEBUG)
warning (0, "target system does not support debug output");
+#endif
}
}
else
diff --git a/gcc/passes.c b/gcc/passes.c
index fe6f637e868..e037f8169d4 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -214,6 +214,7 @@ finish_optimization_passes (void)
char *name;
timevar_push (TV_DUMP);
+#if !defined(DISABLE_RTL_PASSES)
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
dump_file = dump_begin (pass_profile.static_pass_number, NULL);
@@ -231,6 +232,7 @@ finish_optimization_passes (void)
dump_end (pass_combine.static_pass_number, dump_file);
}
}
+#endif
/* Do whatever is necessary to finish printing the graphs. */
if (graph_dump_format != no_graph)
@@ -478,11 +480,18 @@ init_optimization_passes (void)
NEXT_PASS (pass_all_optimizations);
NEXT_PASS (pass_warn_function_noreturn);
NEXT_PASS (pass_mudflap_2);
+#if defined(DISABLE_RTL_PASSES)
+ NEXT_PASS (pass_simp_cil);
+ NEXT_PASS (pass_gen_cil); /* <--- CIL */
+ NEXT_PASS (pass_free_datastructures);
+ NEXT_PASS (pass_free_cfg_annotations);
+#else
NEXT_PASS (pass_free_datastructures);
NEXT_PASS (pass_free_cfg_annotations);
NEXT_PASS (pass_expand);
NEXT_PASS (pass_rest_of_compilation);
NEXT_PASS (pass_clean_state);
+#endif
*p = NULL;
p = &pass_all_optimizations.sub;
diff --git a/gcc/pointer-set.c b/gcc/pointer-set.c
index 5daf88bd0bc..cd23d32ded8 100644
--- a/gcc/pointer-set.c
+++ b/gcc/pointer-set.c
@@ -171,3 +171,30 @@ pointer_set_insert (struct pointer_set_t *pset, void *p)
return 0;
}
+
+struct pointer_set_iter_t
+pointer_set_begin (struct pointer_set_t *pset)
+{
+ struct pointer_set_iter_t iter = { 0, -1 };
+
+ return pointer_set_next (pset, iter);
+}
+
+struct pointer_set_iter_t
+pointer_set_next (struct pointer_set_t *pset, struct pointer_set_iter_t it)
+{
+ struct pointer_set_iter_t res = { 0, -1 };
+ size_t pos = (size_t)(it.slot + 1);
+
+ for (; pos < pset->n_slots; ++pos)
+ {
+ if (pset->slots[pos])
+ {
+ res.elem = pset->slots[pos];
+ res.slot = pos;
+ break;
+ }
+ }
+
+ return res;
+}
diff --git a/gcc/pointer-set.h b/gcc/pointer-set.h
index 7b2e6bc3d2c..9ae22c9f307 100644
--- a/gcc/pointer-set.h
+++ b/gcc/pointer-set.h
@@ -23,10 +23,22 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
struct pointer_set_t;
+struct pointer_set_iter_t {
+ void* elem;
+ int slot;
+};
+
+#define POINTER_SET_ITER_ELEM(it) ((it).elem)
+#define POINTER_SET_ITER_IS_END(it) ((it).slot < 0)
+
struct pointer_set_t *pointer_set_create (void);
void pointer_set_destroy (struct pointer_set_t *pset);
int pointer_set_contains (struct pointer_set_t *pset, void *p);
int pointer_set_insert (struct pointer_set_t *pset, void *p);
+struct pointer_set_iter_t pointer_set_begin (struct pointer_set_t *pset);
+struct pointer_set_iter_t pointer_set_next (struct pointer_set_t *pset,
+ struct pointer_set_iter_t it);
+
#endif /* POINTER_SET_H */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 9837e0de147..22e21b15ea8 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -1826,6 +1826,11 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
&& (sect->common.flags & SECTION_COMMON) == 0)
globalize_decl (decl);
+#ifdef TARGET_DECLARE_VARIABLE
+ TARGET_DECLARE_VARIABLE(asm_out_file,decl);
+ return;
+#endif
+
/* Output any data that we will need to use the address of. */
if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
output_addressed_constants (DECL_INITIAL (decl));