aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Ornstein <andrea.ornstein@st.com>2008-07-22 12:52:53 +0000
committerAndrea Ornstein <andrea.ornstein@st.com>2008-07-22 12:52:53 +0000
commit9c2921a9653dbb5afe44e60c5997c7434a380ef2 (patch)
treeddf1fed4b97683627f13a8f069f9e651c5e8391e
parentcda9cea359acbd1009467f45d178b5cb238e9e22 (diff)
New Snapshot from ST 2008-07-22 (rev 1260)
Changes from Erven Rohou, Gabriele Svelto and Andrea Ornstein CIL BE: A new stack based intermediate representation was added and the compilation flow was altered to lower GIMPLE code into it after the tree-ssa optimizations passes. The new IR is modelled against the CIL bytecode so that each instruction will match exactly one CIL instruction. This simplifies manipulating the code before emission compared to GIMPLE as it makes the stack explicit and limits the passes working on it to constructs and types which are native to the common language infrastructure (CLI). It thus allowed us to introduce CIL-specific optimizations and clean-up passes yielding an improved output and much more robust processing of the input. Nine new passes added: - bb_layout reorders basic blocks to maximize the number of adjacent blocks directly connected by an execution path thus minimizing the number of branches needed to link them together both conditional and unconditional - gimple_to_cil takes GIMPLE/generic code as its input and turns it into the CIL stack-based IR - missing_protos fixes functions which have been declared with K&R conventions - cil_peephole contains some simple peep-hole optimizations which clean up the input code from naive sequences which are known to be generated by the gimple_to_cil pass - remove_temps tries to remove useless temporary variables in order to reduce the code size. This is done by trying to promote variables which are written once but read many times on the stack, moving expressions around to maximize stack usage and propagating copies if possible, this pass is applied twice coupled with the remove_convs pass - remove_convs tries to remove redundant conversions both on the stack and preceding stores to memory or to local variables, like the remove_temps pass it is applied twice - simp_cond looks for conditional branches with one execution path falling through to the next basic block. If one of the conditionals is found and the conditional branch is followed by a non-conditional branch skipping over the next basic block the condition is reversed and the branch made to fall through thus removing the unconditional branch - emit_cil_vcg emits the VCG for the code - emit_cil emits the CIL assembly including type declarations, global initializers, etc... This pass also executes a few metadata-oriented optimizations like reordering the local variables to maximize the use of shorter CIL enconding for common instructions git-svn-id: https://gcc.gnu.org/svn/gcc/branches/st/cli@138054 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/config.gcc4
-rw-r--r--gcc/config/cil32/bb-layout.c11
-rw-r--r--gcc/config/cil32/cil-builtins.c355
-rw-r--r--gcc/config/cil32/cil-builtins.def317
-rw-r--r--gcc/config/cil32/cil-builtins.h4
-rw-r--r--gcc/config/cil32/cil-refs.c205
-rw-r--r--gcc/config/cil32/cil-refs.h5
-rw-r--r--gcc/config/cil32/cil-stack.c754
-rw-r--r--gcc/config/cil32/cil-stack.h123
-rw-r--r--gcc/config/cil32/cil-stmt-inline.h634
-rw-r--r--gcc/config/cil32/cil-stmt.c1317
-rw-r--r--gcc/config/cil32/cil-stmt.h186
-rw-r--r--gcc/config/cil32/cil-types.h280
-rw-r--r--gcc/config/cil32/cil32.c40
-rw-r--r--gcc/config/cil32/cil32.h16
-rw-r--r--gcc/config/cil32/cil32.opt8
-rw-r--r--gcc/config/cil32/emit-cil.c2571
-rw-r--r--gcc/config/cil32/emit-cil.h (renamed from gcc/config/cil32/tree-simp-cil.h)29
-rw-r--r--gcc/config/cil32/emit-hints.c18
-rw-r--r--gcc/config/cil32/emit-hints.h17
-rw-r--r--gcc/config/cil32/gen-cil.c4120
-rw-r--r--gcc/config/cil32/gen-cil.h55
-rw-r--r--gcc/config/cil32/gimple-to-cil.c3395
-rw-r--r--gcc/config/cil32/missing-protos.c224
-rw-r--r--gcc/config/cil32/peephole.c149
-rw-r--r--gcc/config/cil32/remove-convs.c329
-rw-r--r--gcc/config/cil32/remove-temps.c841
-rw-r--r--gcc/config/cil32/rm-ldloc.c484
-rw-r--r--gcc/config/cil32/simp-cond.c197
-rw-r--r--gcc/config/cil32/t-cil3290
-rw-r--r--gcc/config/cil32/tree-simp-cil-early.c169
-rw-r--r--gcc/config/cil32/tree-simp-cil.c2286
-rw-r--r--gcc/passes.c13
-rw-r--r--gcc/timevar.def8
-rw-r--r--gcc/varasm.c2
-rw-r--r--libgcc4net/gcc4net.cs87
-rw-r--r--libstd/Makefile.in1
-rwxr-xr-xlibstd/configure97
-rw-r--r--libstd/configure.ac5
-rw-r--r--libstd/include/Makefile.am1
-rw-r--r--libstd/include/Makefile.in2
-rw-r--r--libstd/include/__OPT_MSCorlibWrapper.h32
-rw-r--r--libstd/src/Makefile.in1
-rw-r--r--libstd/src/math.c12
-rw-r--r--libstd/src_opt/MSCorelibWrapper.c137
-rw-r--r--libstd/src_opt/MSCorelibWrapper.cs282
-rw-r--r--libstd/src_opt/MSCorelibWrapper_support.c10
-rw-r--r--libstd/src_opt/Makefile.am4
-rw-r--r--libstd/src_opt/Makefile.in5
49 files changed, 12318 insertions, 7614 deletions
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 6344ddc0fb9..510d578a21e 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -856,9 +856,9 @@ c4x-* | tic4x-*)
cil32-*-*)
gas=no
use_collect2=no
- extra_objs="tree-simp-cil.o tree-simp-cil-early.o bit-stream.o emit-hints.o gen-cil.o bb-layout.o rm-ldloc.o cil-refs.o cil-builtins.o"
+ extra_objs="bb-layout.o bit-stream.o cil-refs.o cil-stack.o cil-stmt.o emit-cil.o emit-hints.o gimple-to-cil.o missing-protos.o peephole.o remove-convs.o remove-temps.o simp-cond.o tree-simp-cil-early.o cil-builtins.o"
tm_file="${tm_file} cil32/cil-types.h"
- target_gtfiles="\$(srcdir)/config/cil32/cil-refs.c"
+ target_gtfiles="\$(srcdir)/config/cil32/cil-builtins.c \$(srcdir)/config/cil32/cil-refs.c \$(srcdir)/config/cil32/cil-stmt.c"
;;
cris-*-aout)
tm_file="dbxelf.h ${tm_file} cris/aout.h"
diff --git a/gcc/config/cil32/bb-layout.c b/gcc/config/cil32/bb-layout.c
index ce3afcc18a3..cf2e531da2b 100644
--- a/gcc/config/cil32/bb-layout.c
+++ b/gcc/config/cil32/bb-layout.c
@@ -1,6 +1,6 @@
/* Layout of basic blocks.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2008 Free Software Foundation, Inc.
This file is part of GCC.
@@ -24,6 +24,7 @@ Authors:
Andrea Ornstein
Erven Rohou
Roberto Costa
+ Gabriele Svelto
Contact information at STMicroelectronics:
Andrea C. Ornstein <andrea.ornstein@st.com>
@@ -34,15 +35,17 @@ Erven Rohou <erven.rohou@st.com>
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "timevar.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-pass.h"
-#include "timevar.h"
+
+static int marker = 0;
static inline void
visit_block (basic_block bb)
{
- bb->aux = (void*)1;
+ bb->aux = (void *) &marker;
}
static inline bool
@@ -143,7 +146,7 @@ bblayout (void)
basic_block* bb_order = NULL;
mark_dfs_back_edges ();
- bb_order = (basic_block*) alloca (n_basic_blocks * sizeof (basic_block));
+ bb_order = (basic_block *) alloca (n_basic_blocks * sizeof (basic_block));
current_bb_at_pos = ENTRY_BLOCK_PTR;
compute_layout (ENTRY_BLOCK_PTR, bb_order, &bb_num, &layout_changed);
bb_order[bb_num++] = EXIT_BLOCK_PTR;
diff --git a/gcc/config/cil32/cil-builtins.c b/gcc/config/cil32/cil-builtins.c
index a99680e6f83..8bac564ca06 100644
--- a/gcc/config/cil32/cil-builtins.c
+++ b/gcc/config/cil32/cil-builtins.c
@@ -36,66 +36,61 @@ Erven Rohou <erven.rohou@st.com>
#include "langhooks.h"
#include "cil-builtins.h"
+#include "cil-refs.h"
tree cil32_builtins[CIL32_MAX_BUILT_IN] = {NULL_TREE};
tree cil32_va_list_type = NULL_TREE;
tree cil32_arg_iterator_type;
-static void
-cil_build_builtin_types (void)
-{
- if (cil32_va_list_type == NULL_TREE) {
- tree f_dummy, record, type_decl;
+static GTY(()) tree cil32_complex_char_type = NULL_TREE;
+static GTY(()) tree cil32_complex_uchar_type = NULL_TREE;
+static GTY(()) tree cil32_complex_short_type = NULL_TREE;
+static GTY(()) tree cil32_complex_ushort_type = NULL_TREE;
+static GTY(()) tree cil32_complex_int_type = NULL_TREE;
+static GTY(()) tree cil32_complex_uint_type = NULL_TREE;
+static GTY(()) tree cil32_complex_long_type = NULL_TREE;
+static GTY(()) tree cil32_complex_ulong_type = NULL_TREE;
+static GTY(()) tree cil32_complex_float_type = NULL_TREE;
+static GTY(()) tree cil32_complex_double_type = NULL_TREE;
- record = (*lang_hooks.types.make_type) (RECORD_TYPE);
- type_decl = build_decl (TYPE_DECL, get_identifier ("__arg_iterator"), record);
+static GTY((param_is (union tree_node))) htab_t builtin_types = NULL;
- f_dummy = build_decl (FIELD_DECL, get_identifier ("__dummy"), ptr_type_node);
+static void cil_add_builtin (enum cil32_builtin, const char *, tree, int, ...);
+static void cil_build_builtin_types (void);
+static void cil_build_complex_types (void);
- DECL_FIELD_CONTEXT (f_dummy) = record;
+static void
+cil_add_builtin (enum cil32_builtin bi, const char *name,
+ tree ret_type, int n, ...)
+{
+ tree arglist;
+ va_list va;
- TREE_CHAIN (record) = type_decl;
- TYPE_NAME (record) = type_decl;
- TYPE_FIELDS (record) = f_dummy;
+ va_start (va, n);
+ arglist = NULL_TREE;
- layout_type (record);
+ while (n-- > 0)
+ arglist = tree_cons (NULL_TREE, va_arg(va, tree), arglist);
- cil32_arg_iterator_type = record;
+ va_end (va);
- cil32_va_list_type = build_pointer_type (cil32_arg_iterator_type);
- }
-}
+ arglist = tree_cons (NULL_TREE, void_type_node, arglist);
+ arglist = nreverse (arglist);
-static void
-cil_add_builtin(enum cil32_builtin bi, const char *name, tree ret_type, int n, ...)
-{
- tree arglist;
- va_list va;
-
- va_start (va, n);
- arglist = NULL_TREE;
- while (n-->0)
- arglist = tree_cons (NULL_TREE, va_arg(va, tree), arglist);
- va_end (va);
-
- arglist = tree_cons (NULL_TREE, void_type_node, arglist);
-
- arglist = nreverse (arglist);
-
- cil32_builtins[bi] = add_builtin_function (name,
- build_function_type (ret_type,
- arglist),
- bi,
- BUILT_IN_MD,
- NULL,
- NULL_TREE);
+ cil32_builtins[bi] = add_builtin_function (name,
+ build_function_type (ret_type,
+ arglist),
+ bi,
+ BUILT_IN_MD,
+ NULL,
+ NULL_TREE);
}
void
cil_init_builtins (void)
{
- /* Types */
+ /* Vector types */
tree float2_type_node = build_vector_type (float_type_node, 2);
tree float4_type_node = build_vector_type (float_type_node, 4);
tree intQI4_type_node = build_vector_type (intQI_type_node, 4);
@@ -107,6 +102,15 @@ cil_init_builtins (void)
tree intHI8_type_node = build_vector_type (intHI_type_node, 8);
tree intQI16_type_node = build_vector_type (intQI_type_node, 16);
+ /* Complex types */
+ tree complex_char_type_node = build_complex_type (char_type_node);
+ tree complex_short_integer_type_node = build_complex_type (short_integer_type_node);
+ tree complex_long_integer_type_node = build_complex_type (long_long_integer_type_node);
+ tree complex_unsigned_char_type_node = build_complex_type (unsigned_char_type_node);
+ tree complex_short_unsigned_type_node = build_complex_type (short_unsigned_type_node);
+ tree complex_unsigned_type_node = build_complex_type (unsigned_type_node);
+ tree complex_long_unsigned_type_node = build_complex_type (long_long_unsigned_type_node);
+
cil_build_builtin_types ();
#define DEF_CILBUILTIN(bid, name, ret_type, num_par, ...) \
@@ -115,9 +119,276 @@ cil_init_builtins (void)
#undef DEF_CILBUILTIN
}
+/* Records a builtin type generated by the CIL back end. */
+
+void
+cil_record_builtin_type (tree type)
+{
+ void **slot;
+
+ if (builtin_types == NULL)
+ builtin_types = htab_create_ggc (16, htab_hash_pointer, htab_eq_pointer,
+ NULL);
+
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* If the type was already recorded, nothing else to do */
+ slot = htab_find_slot (builtin_types, type, INSERT);
+
+ if (*slot == NULL)
+ *slot = type;
+}
+
+/* Returns true if TYPE is a builtin type of the CIL back end. */
+
+bool
+cil_builtin_type_p (tree type)
+{
+ void **slot;
+
+ type = TYPE_MAIN_VARIANT (type);
+ slot = htab_find_slot (builtin_types, type, NO_INSERT);
+
+ if (slot != NULL)
+ return true;
+ else
+ return false;
+}
+
+static void
+cil_build_builtin_types (void)
+{
+ cil_build_builtin_va_list ();
+ cil_build_complex_types ();
+}
+
tree
cil_build_builtin_va_list (void)
{
- cil_build_builtin_types ();
+ tree f_dummy, record, type_decl;
+
+ if (cil32_va_list_type == NULL_TREE)
+ {
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ type_decl = build_decl (TYPE_DECL, get_identifier ("__arg_iterator"),
+ 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);
+
+ cil32_arg_iterator_type = record;
+
+ cil32_va_list_type = build_pointer_type (cil32_arg_iterator_type);
+ cil_record_builtin_type (cil32_va_list_type);
+ }
+
return cil32_va_list_type;
}
+
+static void
+cil_build_complex_types (void)
+{
+ tree real, imag, real_id, imag_id;
+
+ if (cil32_complex_char_type == NULL)
+ {
+ real_id = get_identifier ("re");
+ imag_id = get_identifier ("im");
+
+ cil32_complex_char_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, char_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, char_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_char_type, "complex_char",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_char_type);
+
+ cil32_complex_uchar_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, unsigned_char_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, unsigned_char_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_uchar_type, "complex_uchar",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_uchar_type);
+
+ cil32_complex_short_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, short_integer_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, short_integer_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_short_type, "complex_short",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_short_type);
+
+ cil32_complex_ushort_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, short_unsigned_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, short_unsigned_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_ushort_type, "complex_ushort",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_ushort_type);
+
+ cil32_complex_int_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, integer_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, integer_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_int_type, "complex_int",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_int_type);
+
+ cil32_complex_uint_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, unsigned_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, unsigned_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_uint_type, "complex_uint",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_uint_type);
+
+ cil32_complex_long_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, long_long_integer_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, long_long_integer_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_long_type, "complex_long",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_long_type);
+
+ cil32_complex_ulong_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, long_long_unsigned_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, long_long_unsigned_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_ulong_type, "complex_ulong",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_ulong_type);
+
+ cil32_complex_float_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, float_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, float_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_float_type, "complex_float",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_float_type);
+
+ cil32_complex_double_type = lang_hooks.types.make_type (RECORD_TYPE);
+ real = build_decl (FIELD_DECL, real_id, double_type_node);
+ imag = build_decl (FIELD_DECL, imag_id, double_type_node);
+ TREE_CHAIN (imag) = real;
+ finish_builtin_struct (cil32_complex_double_type, "complex_double",
+ imag, NULL_TREE);
+ cil_record_builtin_type (cil32_complex_double_type);
+ }
+}
+
+tree
+cil_get_builtin_complex_real_fld (tree type)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ bool unsignedp;
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ unsignedp = TYPE_UNSIGNED (type);
+
+ switch (size)
+ {
+ case 8:
+ if (unsignedp)
+ return TYPE_FIELDS (cil32_complex_uchar_type);
+ else
+ return TYPE_FIELDS (cil32_complex_char_type);
+ break;
+
+ case 16:
+ if (unsignedp)
+ return TYPE_FIELDS (cil32_complex_ushort_type);
+ else
+ return TYPE_FIELDS (cil32_complex_short_type);
+ break;
+
+ case 32:
+ if (unsignedp)
+ return TYPE_FIELDS (cil32_complex_uint_type);
+ else
+ return TYPE_FIELDS (cil32_complex_int_type);
+ break;
+
+ case 64:
+ if (unsignedp)
+ return TYPE_FIELDS (cil32_complex_ulong_type);
+ else
+ return TYPE_FIELDS (cil32_complex_long_type);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ if (size == 32)
+ return TYPE_FIELDS (cil32_complex_float_type);
+ else
+ return TYPE_FIELDS (cil32_complex_double_type);
+ }
+}
+
+tree
+cil_get_builtin_complex_imag_fld (tree type)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ bool unsignedp;
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ unsignedp = TYPE_UNSIGNED (type);
+
+ switch (size)
+ {
+ case 8:
+ if (unsignedp)
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_uchar_type));
+ else
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_char_type));
+ break;
+
+ case 16:
+ if (unsignedp)
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_ushort_type));
+ else
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_short_type));
+ break;
+
+ case 32:
+ if (unsignedp)
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_uint_type));
+ else
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_int_type));
+ break;
+
+ case 64:
+ if (unsignedp)
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_ulong_type));
+ else
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_long_type));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ if (size == 32)
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_float_type));
+ else
+ return TREE_CHAIN (TYPE_FIELDS (cil32_complex_double_type));
+ }
+}
+
+#include "gt-cil-builtins.h"
diff --git a/gcc/config/cil32/cil-builtins.def b/gcc/config/cil32/cil-builtins.def
index d9887febb72..e8216d4b44f 100644
--- a/gcc/config/cil32/cil-builtins.def
+++ b/gcc/config/cil32/cil-builtins.def
@@ -41,52 +41,307 @@ DEF_CILBUILTIN(BUILT_IN_VA_END, "__builtin_cil_va_end", void_type_node, \
DEF_CILBUILTIN(BUILT_IN_VA_COPY, "__builtin_cil_va_copy", void_type_node, \
2, cil32_va_list_type, cil32_va_list_type)
+DEF_CILBUILTIN(BUILT_IN_VA_INIT, "__builtin_cil_va_init", void_type_node, \
+ 1, cil32_va_list_type)
+
DEF_CILBUILTIN(BUILT_IN_CPBLK, "__builtin_cil_cpblk", void_type_node, \
3, ptr_type_node, ptr_type_node, integer_type_node)
DEF_CILBUILTIN(BUILT_IN_INITBLK, "__builtin_cil_initblk", void_type_node, \
3, ptr_type_node, integer_type_node, integer_type_node)
-DEF_CILBUILTIN(BUILT_IN_IS_LITTLE_ENDIAN, "__builtin_isLittleEndian", integer_type_node, \
- 0)
+DEF_CILBUILTIN(BUILT_IN_IS_LITTLE_ENDIAN, \
+ "[gcc4net]gcc4net.Crt::__isLittleEndian", integer_type_node, \
+ 0)
-DEF_CILBUILTIN(BUILT_IN_ENDIAN_SELECT, "__builtin_EndianSelect", ptr_type_node, \
- 2, ptr_type_node, ptr_type_node)
+DEF_CILBUILTIN(BUILT_IN_ENDIAN_SELECT, \
+ "[gcc4net]gcc4net.Crt::__EndianSelect", ptr_type_node, \
+ 2, ptr_type_node, ptr_type_node)
-DEF_CILBUILTIN(V2SF_CTOR, "V2SF_ctor1", float2_type_node, \
+DEF_CILBUILTIN(V2SF_CTOR, "[gcc4net]gcc4net.V2SF::V2SF_ctor1", float2_type_node, \
2, float_type_node, float_type_node)
-DEF_CILBUILTIN(V4SF_CTOR, "V4SF_ctor1", float4_type_node, \
- 4, float_type_node, float_type_node, float_type_node, float_type_node)
+DEF_CILBUILTIN(V2SF_TO_DI, "[gcc4net]gcc4net.V2SF::V2SF_to_di", intDI_type_node, \
+ 1, float2_type_node)
+
+DEF_CILBUILTIN(V4SF_CTOR, "[gcc4net]gcc4net.V4SF::V4SF_ctor1", float4_type_node, \
+ 4, \
+ float_type_node, float_type_node, \
+ float_type_node, float_type_node)
+
+DEF_CILBUILTIN(V4QI_CTOR, "[gcc4net]gcc4net.V4QI::V4QI_ctor1",
+ intQI4_type_node, \
+ 4, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node)
+
+DEF_CILBUILTIN(V4QI_CTOR2, "[gcc4net]gcc4net.V4QI::V4QI_ctor2", \
+ intQI4_type_node, \
+ 1, unsigned_type_node)
+
+DEF_CILBUILTIN(V4QI_TO_USI, "[gcc4net]gcc4net.V4QI::V4QI_to_usi", \
+ unsigned_type_node, \
+ 1, intQI4_type_node)
+
+DEF_CILBUILTIN(V4QI_TO_SI, "[gcc4net]gcc4net.V4QI::V4QI_to_si", \
+ integer_type_node, \
+ 1, intQI4_type_node)
+
+DEF_CILBUILTIN(V2HI_CTOR, "[gcc4net]gcc4net.V2HI::V2HI_ctor1", \
+ intHI2_type_node, \
+ 2, unsigned_intHI_type_node, unsigned_intHI_type_node)
+
+DEF_CILBUILTIN(V2HI_CTOR2, "[gcc4net]gcc4net.V2HI::V2HI_ctor2", \
+ intHI2_type_node, \
+ 1, unsigned_type_node)
+
+DEF_CILBUILTIN(V2HI_TO_USI, "[gcc4net]gcc4net.V2HI::V2HI_to_usi", \
+ unsigned_type_node, \
+ 1, intHI2_type_node)
+
+DEF_CILBUILTIN(V2HI_TO_SI, "[gcc4net]gcc4net.V2HI::V2HI_to_si", \
+ integer_type_node, \
+ 1, intHI2_type_node)
+
+DEF_CILBUILTIN(V8QI_CTOR, "[gcc4net]gcc4net.V8QI::V8QI_ctor1", \
+ intQI8_type_node, \
+ 8, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node)
+
+DEF_CILBUILTIN(V8QI_CTOR2, "[gcc4net]gcc4net.V8QI::V8QI_ctor2", \
+ intQI8_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(V8QI_TO_UDI, "[gcc4net]gcc4net.V8QI::V8QI_to_udi", \
+ unsigned_intDI_type_node, \
+ 1, intQI8_type_node)
+
+DEF_CILBUILTIN(V8QI_TO_DI, "[gcc4net]gcc4net.V8QI::V8QI_to_di", \
+ intDI_type_node, \
+ 1, intQI8_type_node)
+
+DEF_CILBUILTIN(V4HI_CTOR, "[gcc4net]gcc4net.V4HI::V4HI_ctor1", \
+ intHI4_type_node, \
+ 4, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node)
+
+DEF_CILBUILTIN(V4HI_CTOR2, "[gcc4net]gcc4net.V8QI::V4HI_ctor2",
+ intHI4_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(V4HI_TO_UDI, "[gcc4net]gcc4net.V4HI::V4HI_to_udi", \
+ unsigned_intDI_type_node, \
+ 1, intHI4_type_node)
+
+DEF_CILBUILTIN(V4HI_TO_DI, "[gcc4net]gcc4net.V4HI::V4HI_to_di", \
+ intDI_type_node, \
+ 1, intHI4_type_node)
+
+DEF_CILBUILTIN(V2SI_CTOR, "[gcc4net]gcc4net.V2SI::V2SI_ctor1", \
+ intSI2_type_node, \
+ 2, \
+ unsigned_intSI_type_node, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(V2SI_CTOR2, "[gcc4net]gcc4net.V2SI::V2SI_ctor2", \
+ intSI2_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(V2SI_TO_UDI, "[gcc4net]gcc4net.V2SI::V2SI_to_udi", \
+ unsigned_intDI_type_node, \
+ 1, intSI2_type_node)
+
+DEF_CILBUILTIN(V2SI_TO_DI, "[gcc4net]gcc4net.V2SI::V2SI_to_di", \
+ intDI_type_node, \
+ 1, intSI2_type_node)
+
+DEF_CILBUILTIN(V4SI_CTOR, "[gcc4net]gcc4net.V4SI::V4SI_ctor1", \
+ intSI4_type_node, \
+ 4, \
+ unsigned_intSI_type_node, unsigned_intSI_type_node, \
+ unsigned_intSI_type_node, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(V4SI_TO_V4SF, "[gcc4net]gcc4net.V4SI::V4SI_to_V4SF", \
+ float4_type_node, \
+ 1, intSI4_type_node)
+
+DEF_CILBUILTIN(V8HI_CTOR, "[gcc4net]gcc4net.V8HI::V8HI_ctor1", \
+ intHI8_type_node, \
+ 8, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node, \
+ unsigned_intHI_type_node, unsigned_intHI_type_node)
+
+DEF_CILBUILTIN(V16QI_CTOR, "[gcc4net]gcc4net.V16QI::V16QI_ctor1", \
+ intQI16_type_node, \
+ 16, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node, \
+ unsigned_intQI_type_node, unsigned_intQI_type_node)
+
+DEF_CILBUILTIN(MINSI3, "[gcc4net]gcc4net.Crt::__minsi3", intSI_type_node, \
+ 2, intSI_type_node, intSI_type_node)
+
+DEF_CILBUILTIN(MINDI3, "[gcc4net]gcc4net.Crt::__mindi3", intDI_type_node, \
+ 2, intDI_type_node, intDI_type_node)
+
+DEF_CILBUILTIN(UMINSI3, "[gcc4net]gcc4net.Crt::__uminsi3", \
+ unsigned_intSI_type_node, \
+ 2, unsigned_intSI_type_node, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(UMINDI3, "[gcc4net]gcc4net.Crt::__umindi3", \
+ unsigned_intDI_type_node, \
+ 2, unsigned_intDI_type_node, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(MINSF3, "[gcc4net]gcc4net.Crt::__minsf3", float_type_node, \
+ 2, float_type_node, float_type_node)
+
+DEF_CILBUILTIN(MINDF3, "[gcc4net]gcc4net.Crt::__mindf3", double_type_node, \
+ 2, double_type_node, double_type_node)
+
+DEF_CILBUILTIN(MAXSI3, "[gcc4net]gcc4net.Crt::__maxsi3", intSI_type_node, \
+ 2, intSI_type_node, intSI_type_node)
+
+DEF_CILBUILTIN(MAXDI3, "[gcc4net]gcc4net.Crt::__maxdi3", intDI_type_node, \
+ 2, intDI_type_node, intDI_type_node)
+
+DEF_CILBUILTIN(UMAXSI3, "[gcc4net]gcc4net.Crt::__umaxsi3", \
+ unsigned_intSI_type_node, \
+ 2, unsigned_intSI_type_node, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(UMAXDI3, "[gcc4net]gcc4net.Crt::__umaxdi3", \
+ unsigned_intDI_type_node, \
+ 2, unsigned_intDI_type_node, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(MAXSF3, "[gcc4net]gcc4net.Crt::__maxsf3", float_type_node, \
+ 2, float_type_node, float_type_node)
+
+DEF_CILBUILTIN(MAXDF3, "[gcc4net]gcc4net.Crt::__maxdf3", double_type_node, \
+ 2, double_type_node, double_type_node)
+
+DEF_CILBUILTIN(ABSSI2, "[gcc4net]gcc4net.Crt::__abssi2", intSI_type_node, \
+ 1, intSI_type_node)
+
+DEF_CILBUILTIN(ABSDI2, "[gcc4net]gcc4net.Crt::__absdi2", intDI_type_node, \
+ 1, intDI_type_node)
+
+DEF_CILBUILTIN(ABSSF2, "[gcc4net]gcc4net.Crt::__abssf2", float_type_node, \
+ 1, float_type_node)
+
+DEF_CILBUILTIN(ABSDF2, "[gcc4net]gcc4net.Crt::__absdf2", double_type_node, \
+ 1, double_type_node)
+
+DEF_CILBUILTIN(SELECTSI4, "[gcc4net]gcc4net.Crt::__selectsi4", \
+ intSI_type_node, \
+ 3, intSI_type_node, intSI_type_node, intSI_type_node)
+
+DEF_CILBUILTIN(SELECTDI4, "[gcc4net]gcc4net.Crt::__selectdi4", \
+ intDI_type_node, \
+ 3, intSI_type_node, intDI_type_node, intDI_type_node)
+
+DEF_CILBUILTIN(SELECTSF4, "[gcc4net]gcc4net.Crt::__selectsf4", \
+ float_type_node, \
+ 3, intSI_type_node, float_type_node, float_type_node)
+
+DEF_CILBUILTIN(SELECTDF4, "[gcc4net]gcc4net.Crt::__selectdf4", \
+ double_type_node, \
+ 3, intSI_type_node, double_type_node, double_type_node)
+
+DEF_CILBUILTIN(CLZSI2, "[gcc4net]gcc4net.Crt::__clzsi2", \
+ intSI_type_node, \
+ 1, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(CLZDI2, "[gcc4net]gcc4net.Crt::__clzdi2", \
+ intSI_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(CTZSI2, "[gcc4net]gcc4net.Crt::__ctzsi2", \
+ intSI_type_node, \
+ 1, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(CTZDI2, "[gcc4net]gcc4net.Crt::__ctzdi2", \
+ intSI_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(FFSSI2, "[gcc4net]gcc4net.Crt::__ffssi2", \
+ intSI_type_node, \
+ 1, intSI_type_node)
+
+DEF_CILBUILTIN(FFSDI2, "[gcc4net]gcc4net.Crt::__ffsdi2", \
+ intSI_type_node, \
+ 1, intDI_type_node)
+
+DEF_CILBUILTIN(PARITYSI2, "[gcc4net]gcc4net.Crt::__paritysi2", \
+ intSI_type_node, \
+ 1, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(PARITYDI2, "[gcc4net]gcc4net.Crt::__paritydi2", \
+ intSI_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(POPCOUNTSI2, "[gcc4net]gcc4net.Crt::__popcountsi2", \
+ intSI_type_node, \
+ 1, unsigned_intSI_type_node)
+
+DEF_CILBUILTIN(POPCOUNTDI2, "[gcc4net]gcc4net.Crt::__popcountdi2", \
+ intSI_type_node, \
+ 1, unsigned_intDI_type_node)
+
+DEF_CILBUILTIN(CPLX_CHAR_CTOR, \
+ "[gcc4net]gcc4net.complex_char::complex_char_ctor", \
+ complex_char_type_node, \
+ 2, char_type_node, char_type_node)
+
+DEF_CILBUILTIN(CPLX_SHORT_CTOR, \
+ "[gcc4net]gcc4net.complex_short::complex_short_ctor", \
+ complex_short_integer_type_node, \
+ 2, short_integer_type_node, short_integer_type_node)
-DEF_CILBUILTIN(V4QI_CTOR, "V4QI_ctor1", intQI4_type_node, \
- 4, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node)
+DEF_CILBUILTIN(CPLX_INT_CTOR, \
+ "[gcc4net]gcc4net.complex_int::complex_int_ctor", \
+ complex_integer_type_node, \
+ 2, integer_type_node, integer_type_node)
-DEF_CILBUILTIN(V2HI_CTOR, "V2HI_ctor1", intHI2_type_node, \
- 2, intHI_type_node, unsigned_intHI_type_node)
+DEF_CILBUILTIN(CPLX_LONG_CTOR, \
+ "[gcc4net]gcc4net.complex_long::complex_long_ctor", \
+ complex_long_integer_type_node, \
+ 2, long_long_integer_type_node, long_long_integer_type_node)
-DEF_CILBUILTIN(V8QI_CTOR, "V8QI_ctor1", intQI8_type_node, \
- 8, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node)
+DEF_CILBUILTIN(CPLX_UCHAR_CTOR, \
+ "[gcc4net]gcc4net.complex_uchar::complex_uchar_ctor", \
+ complex_unsigned_char_type_node, \
+ 2, unsigned_char_type_node, unsigned_char_type_node)
-DEF_CILBUILTIN(V4HI_CTOR, "V4HI_ctor1", intHI4_type_node, \
- 4, unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node)
+DEF_CILBUILTIN(CPLX_USHORT_CTOR, \
+ "[gcc4net]gcc4net.complex_ushort::complex_ushort_ctor", \
+ complex_short_unsigned_type_node, \
+ 2, short_unsigned_type_node, short_unsigned_type_node)
-DEF_CILBUILTIN(V2SI_CTOR, "V2SI_ctor1", intSI2_type_node, \
- 2, unsigned_intSI_type_node, unsigned_intSI_type_node)
+DEF_CILBUILTIN(CPLX_UINT_CTOR, \
+ "[gcc4net]gcc4net.complex_uint::complex_uint_ctor", \
+ complex_unsigned_type_node, \
+ 2, unsigned_type_node, unsigned_type_node)
-DEF_CILBUILTIN(V4SI_CTOR, "V4SI_ctor1", intSI4_type_node, \
- 4, unsigned_intSI_type_node, unsigned_intSI_type_node, unsigned_intSI_type_node, unsigned_intSI_type_node)
+DEF_CILBUILTIN(CPLX_ULONG_CTOR, \
+ "[gcc4net]gcc4net.complex_ulong::complex_ulong_ctor", \
+ complex_long_unsigned_type_node, \
+ 2, long_long_unsigned_type_node, long_long_unsigned_type_node)
-DEF_CILBUILTIN(V8HI_CTOR, "V8HI_ctor1", intHI8_type_node, \
- 8, \
- unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node, \
- unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node, unsigned_intHI_type_node)
+DEF_CILBUILTIN(CPLX_FLOAT_CTOR, \
+ "[gcc4net]gcc4net.complex_float::complex_float_ctor", \
+ complex_float_type_node, \
+ 2, float_type_node, float_type_node)
-DEF_CILBUILTIN(V16QI_CTOR, "V16QI_ctor1", intQI16_type_node, \
- 16, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, \
- unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node, unsigned_intQI_type_node)
+DEF_CILBUILTIN(CPLX_DOUBLE_CTOR, \
+ "[gcc4net]gcc4net.complex_double::complex_double_ctor", \
+ complex_double_type_node, \
+ 2, double_type_node, double_type_node)
diff --git a/gcc/config/cil32/cil-builtins.h b/gcc/config/cil32/cil-builtins.h
index 506c5028a9a..44b62d7e5a9 100644
--- a/gcc/config/cil32/cil-builtins.h
+++ b/gcc/config/cil32/cil-builtins.h
@@ -49,5 +49,9 @@ extern GTY(()) tree cil32_arg_iterator_type;
extern void cil_init_builtins (void);
extern tree cil_build_builtin_va_list (void);
+extern tree cil_get_builtin_complex_real_fld (tree);
+extern tree cil_get_builtin_complex_imag_fld (tree);
+extern void cil_record_builtin_type (tree);
+extern bool cil_builtin_type_p (tree);
#endif /* !CIL_BUILTINS_H */
diff --git a/gcc/config/cil32/cil-refs.c b/gcc/config/cil32/cil-refs.c
index baa64b8c433..42461a6bd34 100644
--- a/gcc/config/cil32/cil-refs.c
+++ b/gcc/config/cil32/cil-refs.c
@@ -184,7 +184,6 @@ restartswitch:
size = tree_low_cst (TYPE_SIZE (type), 1);
snprintf (tmp_str + 1, 3, HOST_WIDE_INT_PRINT_UNSIGNED, size);
-
str = append_string (str, tmp_str, len, max_len);
}
break;
@@ -505,7 +504,7 @@ mark_referenced_type (tree t)
t = TYPE_MAIN_VARIANT (t);
- if (t == cil32_arg_iterator_type)
+ if (cil_builtin_type_p (t))
return;
/* If the type was already referenced, nothing else to do */
@@ -640,6 +639,108 @@ referenced_types_htab ( void )
return ref_types;
}
+/* Promote the type TYPE following the C conventions for variable argument
+ calls. */
+
+tree
+promote_type_for_vararg (tree type)
+{
+ unsigned HOST_WIDE_INT size;
+
+ if (type == NULL_TREE || type == error_mark_node)
+ return type;
+
+ switch (TREE_CODE (type))
+ {
+ /* Incomplete and variable-length arrays are pointers and
+ they must be dealt with as such. */
+ case ARRAY_TYPE:
+ if (! TYPE_DOMAIN (type) || ARRAY_TYPE_VARLENGTH (type))
+ goto pointer;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ return TYPE_MAIN_VARIANT (type);
+
+ case COMPLEX_TYPE:
+ return type;
+
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ size = tree_low_cst (TYPE_SIZE (type), 1);
+ gcc_assert (size <= 64);
+ return (size <= 32) ? unsigned_intSI_type_node : unsigned_intDI_type_node;
+
+ case REAL_TYPE:
+ return double_type_node;
+
+pointer:
+ case POINTER_TYPE:
+ /* FIXME: cil32 is a 32bit machine, in case we support 64bit model
+ changes are needed. */
+ return unsigned_intSI_type_node;
+
+ default:
+ internal_error ("%s: %s\n", __func__, tree_code_name[TREE_CODE (type)]);
+ }
+}
+
+/* Return the promoted type of the local variable represented by VAR. In most
+ cases this will be simply the variable type, however some temporaries may
+ have been declared with integral types which do not exist in CIL
+ (e.g. 3-bit integers). The types of those variables are automatically
+ promoted to a larger stack type since those variables will end up
+ only on the stack. */
+
+tree
+promote_local_var_type (tree var)
+{
+ unsigned int precision;
+ unsigned int unsignedp;
+ tree type = TREE_TYPE (var);
+
+ if (INTEGRAL_TYPE_P (type) && DECL_ARTIFICIAL (var))
+ {
+ gcc_assert (!DECL_FILE_SCOPE_P (var) && !TREE_STATIC (var));
+
+ precision = TYPE_PRECISION (type);
+ unsignedp = TYPE_UNSIGNED (type);
+
+ switch (precision)
+ {
+ case 8: /* FALLTHROUGH */
+ case 16: /* FALLTHROUGH */
+ case 32: /* FALLTHROUGH */
+ case 64: return type;
+ default:
+ if (precision < 32)
+ return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+ else
+ return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+ }
+ }
+ else
+ return type;
+}
+
+/* Return true if we treat the type TYPE as a pointer, false otherwise. */
+
+bool
+cil_pointer_type_p (tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (! TYPE_DOMAIN (type) || ARRAY_TYPE_VARLENGTH (type))
+ return true;
+ }
+ else if (POINTER_TYPE_P (type))
+ return true;
+
+ return false;
+}
+
/******************************************************************************
* Strings *
******************************************************************************/
@@ -760,7 +861,7 @@ pinvoke_eq (const void *ptr1, const void *ptr2)
T must be a FUNCTION_DECL node. */
void
-cil_add_pinvoke (tree t)
+add_pinvoke (tree t)
{
void **slot;
@@ -816,8 +917,7 @@ record_addr_taken_label (tree label)
label_addr addr = GGC_NEW (struct label_addr_d);
addr->label = label;
- addr->id = build_int_cst (intSI_type_node, machine->label_id);
- machine->label_id++;
+ addr->id = build_int_cst (intSI_type_node, machine->label_id++);
gcc_assert (htab_find (labels_map, addr) == NULL);
slot = htab_find_slot (labels_map, addr, INSERT);
@@ -864,19 +964,23 @@ tree
get_label_addrs ( void )
{
struct machine_function *machine = cfun->machine;
+ tree default_label;
if (machine->label_addrs == NULL_TREE)
{
- tree label_addrs;
/* TODO: CIL switches cannot be larger than 8192 entries. Handling larger
ranges could make the code for replacing computed GOTOs significnaly
more complex. */
gcc_assert (machine->label_id < 8192);
- label_addrs = make_tree_vec (machine->label_id);
- htab_traverse (labels_map, fill_label_addrs, label_addrs);
+ machine->label_addrs = make_tree_vec (machine->label_id + 1);
+ htab_traverse (labels_map, fill_label_addrs, machine->label_addrs);
- machine->label_addrs = label_addrs;
+ /* Add a fake default label. */
+ default_label = build3 (CASE_LABEL_EXPR, void_type_node,
+ build_int_cst (NULL_TREE, machine->label_id),
+ NULL_TREE, create_artificial_label ());
+ TREE_VEC_ELT (machine->label_addrs, machine->label_id) = default_label;
}
return machine->label_addrs;
@@ -1306,14 +1410,16 @@ expand_init_to_stmt_list1 (tree decl, tree init,
tree fun, stmt;
tree args = NULL;
tree value;
- tree ctor_fun = NULL;
unsigned HOST_WIDE_INT idx;
tree vector_type = TREE_TYPE (init);
tree vector_elt_type = TREE_TYPE (vector_type);
- int vec_size = tree_low_cst (TYPE_SIZE (vector_type), 1);
- int elt_size = tree_low_cst (TYPE_SIZE (vector_elt_type), 1);
- int num_elt = vec_size / elt_size;
- int i, num_args = 0;
+ unsigned HOST_WIDE_INT elt_size;
+ unsigned HOST_WIDE_INT num_elt;
+ unsigned HOST_WIDE_INT i, num_args = 0;
+ enum cil32_builtin builtin;
+
+ elt_size = tree_low_cst (TYPE_SIZE (vector_elt_type), 1);
+ num_elt = TYPE_VECTOR_SUBPARTS (vector_type);
/* Build the list of args. */
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, value)
@@ -1321,6 +1427,7 @@ expand_init_to_stmt_list1 (tree decl, tree init,
args = tree_cons (NULL, value, args);
++num_args;
}
+
/* The constructor might not initialize all args. */
for (i = num_args; i < num_elt; i++)
args = tree_cons (NULL, integer_zero_node, args);
@@ -1331,48 +1438,72 @@ expand_init_to_stmt_list1 (tree decl, tree init,
switch (num_elt)
{
case 2:
- if (vec_size == 32)
- ctor_fun = cil32_builtins[CIL32_V2HI_CTOR];
- else if (vec_size == 64)
- ctor_fun = cil32_builtins[CIL32_V2SI_CTOR];
+ switch (elt_size)
+ {
+ case 16: builtin = CIL32_V2HI_CTOR; break;
+ case 32: builtin = CIL32_V2SI_CTOR; break;
+ default:
+ internal_error ("V2QI/DI vectors are not supported");
+ }
+
break;
case 4:
- if (vec_size == 32)
- ctor_fun = cil32_builtins[CIL32_V4QI_CTOR];
- else if (vec_size == 64)
- ctor_fun = cil32_builtins[CIL32_V4HI_CTOR];
- else if (vec_size == 128)
- ctor_fun = cil32_builtins[CIL32_V4SI_CTOR];
+ switch (elt_size)
+ {
+ case 8: builtin = CIL32_V4QI_CTOR; break;
+ case 16: builtin = CIL32_V4HI_CTOR; break;
+ case 32: builtin = CIL32_V4SI_CTOR; break;
+ default:
+ internal_error ("V4DI vectors are not supported");
+ }
+
break;
case 8:
- if (vec_size == 64)
- ctor_fun = cil32_builtins[CIL32_V8QI_CTOR];
- else if (vec_size == 128)
- ctor_fun = cil32_builtins[CIL32_V8HI_CTOR];
+ switch (elt_size)
+ {
+ case 8: builtin = CIL32_V8QI_CTOR; break;
+ case 16: builtin = CIL32_V8HI_CTOR; break;
+ default:
+ internal_error ("V8SI/DI vectors are not supported");
+ }
+
break;
case 16:
- if (vec_size == 128)
- ctor_fun = cil32_builtins[CIL32_V16QI_CTOR];
+ switch (elt_size)
+ {
+ case 8: builtin = CIL32_V16QI_CTOR; break;
+ default:
+ internal_error ("V16HI/SI/DI vectors are not supported");
+ }
+
break;
default:
- internal_error ("V%d int vectors not supported\n", num_elt);
+ internal_error (HOST_WIDE_INT_PRINT_UNSIGNED" bit wide "
+ "vectors are not supported",
+ num_elt * elt_size);
}
}
else if (TREE_CODE (vector_elt_type) == REAL_TYPE)
{
- if (num_elt != 2 && num_elt != 4)
- internal_error ("V%dSF vectors not supported\n", num_elt);
-
- ctor_fun = cil32_builtins[CIL32_V2SF_CTOR];
+ switch (num_elt)
+ {
+ case 2: builtin = CIL32_V2SF_CTOR; break;
+ case 4: builtin = CIL32_V4SF_CTOR; break;
+ default:
+ internal_error ("V"HOST_WIDE_INT_PRINT_UNSIGNED
+ "SF vectors not supported\n", num_elt);
+ }
}
- gcc_assert (ctor_fun);
+ else
+ gcc_unreachable ();
/* Note that the args list must be reversed. Can do better? */
- fun = build_function_call_expr (ctor_fun, nreverse (args));
+ fun = build_function_call_expr (cil32_builtins[builtin],
+ nreverse (args));
stmt = build_gimple_modify_stmt(decl, fun);
append_to_statement_list (stmt, stmt_list1);
append_to_statement_list (stmt, stmt_list2);
diff --git a/gcc/config/cil32/cil-refs.h b/gcc/config/cil32/cil-refs.h
index 2bd17e7a351..88c0863daf2 100644
--- a/gcc/config/cil32/cil-refs.h
+++ b/gcc/config/cil32/cil-refs.h
@@ -72,6 +72,9 @@ extern void refs_fini (void);
extern void mark_referenced_type (tree);
extern htab_t referenced_types_htab ( void );
+extern tree promote_type_for_vararg (tree);
+extern tree promote_local_var_type (tree);
+extern bool cil_pointer_type_p (tree);
/******************************************************************************
* Strings *
@@ -85,7 +88,7 @@ extern htab_t referenced_strings_htab ( void );
* Functions *
******************************************************************************/
-extern void cil_add_pinvoke (tree);
+extern void add_pinvoke (tree);
extern htab_t pinvokes_htab ( void );
/******************************************************************************
diff --git a/gcc/config/cil32/cil-stack.c b/gcc/config/cil32/cil-stack.c
new file mode 100644
index 00000000000..7888df4cc71
--- /dev/null
+++ b/gcc/config/cil32/cil-stack.c
@@ -0,0 +1,754 @@
+/* Implementation of the stack information functionality.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "errors.h"
+#include "ggc.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "cil-types.h"
+#include "cil-refs.h"
+#include "cil-stack.h"
+#include "cil-stmt.h"
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static bool value_type_p (tree);
+static cil_type_t cil_binary_op_type (enum cil_opcode, cil_type_t, cil_type_t);
+
+/******************************************************************************
+ * Stack information functionality *
+ ******************************************************************************/
+
+/* Create a new empty stack. */
+
+cil_stack
+cil_stack_create (void)
+{
+ cil_stack stack = XNEW (struct cil_stack_d);
+
+ stack->vec = VEC_alloc (cil_type_t, heap, 1);
+
+ return stack;
+}
+
+/* Create a new stack by copying the contents of stack SRC. */
+
+cil_stack
+cil_stack_copy(const_cil_stack src)
+{
+ cil_stack stack = XNEW (struct cil_stack_d);
+
+ if (VEC_length (cil_type_t, src->vec) != 0)
+ stack->vec = VEC_copy (cil_type_t, heap, src->vec);
+ else
+ stack->vec = VEC_alloc (cil_type_t, heap, 1);
+
+ return stack;
+}
+
+/* Release the stack object pointed by STACK. */
+
+void
+cil_stack_free (cil_stack stack)
+{
+ VEC_free (cil_type_t, heap, stack->vec);
+ XDELETE (stack);
+}
+
+/* Update the stack STACK as if its state was altered by executing the
+ statement STMT. */
+
+void
+cil_stack_after_stmt (cil_stack stack, cil_stmt stmt)
+{
+ VEC (cil_type_t, heap) *vstack = stack->vec;
+ enum cil_opcode opcode = cil_opcode (stmt);
+ cil_type_t op1, op2, res;
+ tree type;
+ size_t i;
+
+ switch (opcode)
+ {
+ case CIL_CPBLK:
+ case CIL_INITBLK:
+ VEC_pop (cil_type_t, vstack);
+ VEC_pop (cil_type_t, vstack);
+ VEC_pop (cil_type_t, vstack);
+ break;
+
+ case CIL_BEQ:
+ case CIL_BGE:
+ case CIL_BGE_UN:
+ case CIL_BGT:
+ case CIL_BGT_UN:
+ case CIL_BLE:
+ case CIL_BLE_UN:
+ case CIL_BLT:
+ case CIL_BLT_UN:
+ case CIL_BNE_UN:
+ case CIL_STFLD:
+ case CIL_STIND_I1:
+ case CIL_STIND_I2:
+ case CIL_STIND_I4:
+ case CIL_STIND_I8:
+ case CIL_STIND_R4:
+ case CIL_STIND_R8:
+ case CIL_STIND_I:
+ case CIL_STOBJ:
+ VEC_pop (cil_type_t, vstack);
+ VEC_pop (cil_type_t, vstack);
+ break;
+
+ case CIL_ADD:
+ case CIL_AND:
+ case CIL_CEQ:
+ case CIL_CGT:
+ case CIL_CGT_UN:
+ case CIL_CLT:
+ case CIL_CLT_UN:
+ case CIL_DIV:
+ case CIL_DIV_UN:
+ case CIL_MUL:
+ case CIL_OR:
+ case CIL_REM:
+ case CIL_REM_UN:
+ case CIL_SHL:
+ case CIL_SHR:
+ case CIL_SHR_UN:
+ case CIL_SUB:
+ case CIL_XOR:
+ op2 = VEC_pop (cil_type_t, vstack);
+ op1 = VEC_pop (cil_type_t, vstack);
+ res = cil_binary_op_type (opcode, op1, op2);
+ VEC_quick_push (cil_type_t, vstack, res);
+ break;
+
+ case CIL_BRFALSE:
+ case CIL_BRTRUE:
+ case CIL_INITOBJ:
+ case CIL_POP:
+ case CIL_STARG:
+ case CIL_STLOC:
+ case CIL_STSFLD:
+ case CIL_SWITCH:
+ VEC_pop (cil_type_t, vstack);
+ break;
+
+ case CIL_CONV_I1:
+ case CIL_CONV_I2:
+ case CIL_CONV_I4:
+ case CIL_CONV_I8:
+ case CIL_CONV_R4:
+ case CIL_CONV_R8:
+ case CIL_CONV_U1:
+ case CIL_CONV_U2:
+ case CIL_CONV_U4:
+ case CIL_CONV_U8:
+ case CIL_CONV_I:
+ case CIL_CONV_U:
+ case CIL_CONV_R_UN:
+ VEC_pop (cil_type_t, vstack);
+
+ switch (opcode)
+ {
+ case CIL_CONV_I1: res = CIL_INT8; break;
+ case CIL_CONV_I2: res = CIL_INT16; break;
+ case CIL_CONV_I4: res = CIL_INT32; break;
+ case CIL_CONV_I8: res = CIL_INT64; break;
+ case CIL_CONV_R4: res = CIL_FLOAT32; break;
+ case CIL_CONV_R8: res = CIL_FLOAT64; break;
+ case CIL_CONV_U1: res = CIL_UNSIGNED_INT8; break;
+ case CIL_CONV_U2: res = CIL_UNSIGNED_INT16; break;
+ case CIL_CONV_U4: res = CIL_UNSIGNED_INT32; break;
+ case CIL_CONV_U8: res = CIL_UNSIGNED_INT64; break;
+ case CIL_CONV_I: res = CIL_NATIVE_INT; break;
+ case CIL_CONV_U: res = CIL_NATIVE_UNSIGNED_INT; break;
+ case CIL_CONV_R_UN: res = CIL_FLOAT; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ VEC_quick_push (cil_type_t, vstack, res);
+ break;
+
+ case CIL_BR:
+ case CIL_BREAK:
+ case CIL_CKFINITE:
+ break;
+
+ case CIL_LDFLD:
+ case CIL_LDSFLD:
+ type = TREE_TYPE (cil_field (stmt));
+
+ if (opcode == CIL_LDFLD)
+ VEC_pop (cil_type_t, vstack);
+
+ if (value_type_p (type))
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_VALUE_TYPE);
+ else
+ VEC_safe_push (cil_type_t, heap, vstack, scalar_to_cil (type));
+
+ break;
+
+ case CIL_LDIND_I1:
+ case CIL_LDIND_I2:
+ case CIL_LDIND_I4:
+ case CIL_LDIND_I8:
+ case CIL_LDIND_U1:
+ case CIL_LDIND_U2:
+ case CIL_LDIND_U4:
+ case CIL_LDIND_U8:
+ case CIL_LDIND_R4:
+ case CIL_LDIND_R8:
+ case CIL_LDIND_I:
+ VEC_pop (cil_type_t, vstack);
+
+ switch (opcode)
+ {
+ case CIL_LDIND_I1: res = CIL_INT8; break;
+ case CIL_LDIND_I2: res = CIL_INT16; break;
+ case CIL_LDIND_I4: res = CIL_INT32; break;
+ case CIL_LDIND_I8: res = CIL_INT64; break;
+ case CIL_LDIND_U1: res = CIL_UNSIGNED_INT8; break;
+ case CIL_LDIND_U2: res = CIL_UNSIGNED_INT16; break;
+ case CIL_LDIND_U4: res = CIL_UNSIGNED_INT32; break;
+ case CIL_LDIND_U8: res = CIL_UNSIGNED_INT64; break;
+ case CIL_LDIND_R4: res = CIL_FLOAT; break;
+ case CIL_LDIND_R8: res = CIL_FLOAT; break;
+ case CIL_LDIND_I: res = CIL_NATIVE_INT; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ VEC_quick_push (cil_type_t, vstack, res);
+ break;
+
+ case CIL_LDOBJ:
+ case CIL_ARGLIST:
+ VEC_pop (cil_type_t, vstack);
+ VEC_quick_push (cil_type_t, vstack, CIL_VALUE_TYPE);
+ break;
+
+ case CIL_LDFLDA:
+ case CIL_LOCALLOC:
+ VEC_pop (cil_type_t, vstack);
+ VEC_quick_push (cil_type_t, vstack, CIL_POINTER);
+ break;
+
+ case CIL_NEG:
+ case CIL_NOT:
+ op1 = VEC_pop (cil_type_t, vstack);
+
+ if (cil_int_or_smaller_p (op1))
+ res = CIL_INT32;
+ else if (cil_long_p (op1))
+ res = CIL_INT64;
+ else if (cil_float_p (op1))
+ res = CIL_FLOAT;
+ else if (cil_native_integer_p (op1))
+ res = CIL_NATIVE_INT;
+ else
+ gcc_unreachable ();
+
+ VEC_quick_push (cil_type_t, vstack, res);
+ break;
+
+ case CIL_DUP:
+ op1 = VEC_last (cil_type_t, vstack);
+ VEC_safe_push (cil_type_t, heap, vstack, op1);
+ break;
+
+ case CIL_LDARG:
+ case CIL_LDLOC:
+ if (opcode == CIL_LDARG)
+ type = DECL_ARG_TYPE (cil_var (stmt));
+ else
+ type = TREE_TYPE (cil_var (stmt));
+
+ if (value_type_p (type))
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_VALUE_TYPE);
+ else
+ VEC_safe_push (cil_type_t, heap, vstack, scalar_to_cil (type));
+
+ break;
+
+ case CIL_LDARGA:
+ case CIL_LDLOCA:
+ case CIL_LDSFLDA:
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_POINTER);
+ break;
+
+ case CIL_LDC_I4:
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_INT32);
+ break;
+
+ case CIL_LDC_I8:
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_INT64);
+ break;
+
+ case CIL_LDC_R4:
+ case CIL_LDC_R8:
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_FLOAT);
+ break;
+
+ case CIL_LDFTN:
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_NATIVE_INT);
+ break;
+
+ case CIL_RET:
+ if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ VEC_pop (cil_type_t, vstack);
+
+ break;
+
+ case CIL_CALL:
+ case CIL_JMP:
+ i = cil_call_nargs (stmt) + (cil_call_static_chain (stmt) ? 1 : 0);
+
+ while (i-- != 0)
+ VEC_pop (cil_type_t, vstack);
+
+ type = TREE_TYPE (cil_call_ftype (stmt));
+
+ if (!VOID_TYPE_P (type))
+ {
+ if (value_type_p (type))
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_VALUE_TYPE);
+ else
+ VEC_safe_push (cil_type_t, heap, vstack, scalar_to_cil (type));
+ }
+
+ break;
+
+ case CIL_CALLI:
+ i = cil_call_nargs (stmt) + 1 + (cil_call_static_chain (stmt) ? 1 : 0);
+
+ while (i-- != 0)
+ VEC_pop (cil_type_t, vstack);
+
+ type = TREE_TYPE (cil_call_ftype (stmt));
+
+ if (!VOID_TYPE_P (type))
+ {
+ if (value_type_p (type))
+ VEC_safe_push (cil_type_t, heap, vstack, CIL_VALUE_TYPE);
+ else
+ VEC_safe_push (cil_type_t, heap, vstack, scalar_to_cil (type));
+ }
+
+ break;
+
+ case CIL_ASM:
+ /* TODO: Specify a way for asm statements to tell the compiler how
+ many stack slots they need. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Update the STACK field as VEC_* operations may alter the source. */
+ stack->vec = vstack;
+}
+
+/* Return the depth of the stack STACK. */
+
+size_t
+cil_stack_depth (const_cil_stack stack)
+{
+ return VEC_length (cil_type_t, stack->vec);
+}
+
+/* Return the type of the element on top of the stack. */
+
+cil_type_t
+cil_stack_top (const_cil_stack stack)
+{
+ return VEC_last (cil_type_t, stack->vec);
+}
+
+/* Peek the value I-th location of the stack STACK. The location is considered
+ in reverse order, i.e. location 0 is the top of the stack, 1 the location
+ just below it and so on. */
+
+cil_type_t
+cil_stack_peek (const_cil_stack stack, size_t i)
+{
+ size_t depth = VEC_length (cil_type_t, stack->vec);
+
+ return VEC_index (cil_type_t, stack->vec, depth - 1 - i);
+}
+
+/******************************************************************************
+ * CIL types functions *
+ ******************************************************************************/
+
+/* Return TRUE if the type TYPE is a non-native integer type, FALSE
+ otherwise. */
+
+bool
+cil_integer_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_INT8:
+ case CIL_INT16:
+ case CIL_INT32:
+ case CIL_INT64:
+ case CIL_UNSIGNED_INT8:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ case CIL_UNSIGNED_INT64:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the type TYPE is a native integer type, FALSE otherwise. */
+
+bool
+cil_native_integer_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_NATIVE_INT:
+ case CIL_NATIVE_UNSIGNED_INT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the type TYPE is a floating-point type, FALSE otherwise. */
+
+bool
+cil_float_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_FLOAT:
+ case CIL_FLOAT32:
+ case CIL_FLOAT64:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the type TYPE is a pointer type (or native integer),
+ FALSE otherwise. */
+
+bool
+cil_pointer_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_NATIVE_INT:
+ case CIL_NATIVE_UNSIGNED_INT:
+ case CIL_POINTER:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the type TYPE is a 32-bit or smaller integer, FALSE
+ otherwise. */
+
+bool
+cil_int_or_smaller_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_INT8:
+ case CIL_INT16:
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT8:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the type TYPE is a 64-bit integer, FALSE otherwise. */
+
+bool
+cil_long_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_INT64:
+ case CIL_UNSIGNED_INT64:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns TRUE if the type TYPE is unsigned, FALSE otherwise. */
+
+bool
+cil_unsigned_int_p (cil_type_t type)
+{
+ switch (type)
+ {
+ case CIL_UNSIGNED_INT8:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ case CIL_UNSIGNED_INT64:
+ case CIL_NATIVE_UNSIGNED_INT:
+ return true;
+
+ default:
+ return true;
+ }
+}
+
+/* Return the CIL stack representation for scalar type TYPE. */
+
+cil_type_t
+scalar_to_cil (tree type)
+{
+ unsigned HOST_WIDE_INT size;
+
+ switch (TREE_CODE (type))
+ {
+ case ENUMERAL_TYPE:
+ return CIL_INT32;
+
+ case INTEGER_TYPE:
+ size = tree_low_cst (TYPE_SIZE (type), 1);
+
+ switch (size)
+ {
+ case 8: return TYPE_UNSIGNED (type) ? CIL_UNSIGNED_INT8 : CIL_INT8;
+ case 16: return TYPE_UNSIGNED (type) ? CIL_UNSIGNED_INT16 : CIL_INT16;
+ case 32: return TYPE_UNSIGNED (type) ? CIL_UNSIGNED_INT32 : CIL_INT32;
+ case 64: return TYPE_UNSIGNED (type) ? CIL_UNSIGNED_INT64 : CIL_INT64;
+ default:
+ internal_error ("Unsupported integer size "
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+
+ case REAL_TYPE:
+ return CIL_FLOAT;
+
+ case BOOLEAN_TYPE:
+ return CIL_INT8;
+
+ case ARRAY_TYPE:
+ gcc_assert (!TYPE_DOMAIN (type) || ARRAY_TYPE_VARLENGTH (type));
+ /* FALLTHROUGH */
+
+ case POINTER_TYPE:
+ return CIL_POINTER;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return TRUE if the type specified by TYPE is loaded on the stack as a
+ value type, FALSE otherwise. */
+
+static bool
+value_type_p (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case ARRAY_TYPE:
+ if (!TYPE_DOMAIN (type) || ARRAY_TYPE_VARLENGTH (type))
+ return false; /* Incomplete array types are treated life pointers. */
+
+ /* FALLTHROUGH */
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case VECTOR_TYPE:
+ case COMPLEX_TYPE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return the result type of a binary operation OP with operands of types
+ TYPE1 and TYPE2. This function doesn't do any validation of the passed
+ operation as it assumes that it is fed valid CIL code. */
+
+static cil_type_t
+cil_binary_op_type (enum cil_opcode op, cil_type_t type1, cil_type_t type2)
+{
+ /* TODO: When pointers will be specialized this function should be
+ altered to deal with them properly. */
+
+ switch (op)
+ {
+ case CIL_ADD:
+ case CIL_AND: /* TODO: Could be improved */
+ case CIL_DIV:
+ case CIL_DIV_UN:
+ case CIL_MUL:
+ case CIL_OR: /* TODO: Could be improved */
+ case CIL_REM:
+ case CIL_REM_UN:
+ case CIL_SUB:
+ case CIL_XOR: /* TODO: Could be improved */
+ if (cil_int_or_smaller_p (type1))
+ {
+ if (cil_int_or_smaller_p (type2))
+ return CIL_INT32;
+ else if (cil_native_integer_p (type2))
+ return CIL_NATIVE_INT;
+ else /* CIL_POINTER */
+ return type2;
+ }
+ else if (cil_long_p (type1))
+ return CIL_INT64;
+ else if (cil_native_integer_p (type1))
+ {
+ if (type2 == CIL_POINTER)
+ return type2;
+ else
+ return CIL_NATIVE_INT;
+ }
+ else if (cil_float_p (type1))
+ return CIL_FLOAT;
+ else if (type1 == CIL_POINTER)
+ {
+ if (type2 == CIL_POINTER)
+ return CIL_NATIVE_INT;
+ else
+ return type1;
+ }
+ else
+ gcc_unreachable ();
+
+ break;
+
+ case CIL_CEQ:
+ case CIL_CGT:
+ case CIL_CGT_UN:
+ case CIL_CLT:
+ case CIL_CLT_UN:
+ return CIL_INT32;
+
+ case CIL_SHL:
+ case CIL_SHR:
+ case CIL_SHR_UN:
+ if (cil_int_or_smaller_p (type1))
+ return CIL_INT32;
+ else if (cil_long_p (type1))
+ return CIL_INT64;
+ else
+ return CIL_NATIVE_INT;
+
+ break;
+
+ default:
+ internal_error ("Unsupported operation for cil_binary_op_type()");
+ }
+}
+
+/* Create a new stacks-to-basic-blocks mapping structure. */
+
+cil_bb_stacks
+cil_bb_stacks_create (void)
+{
+ cil_bb_stacks bbs = XNEW (struct cil_bb_stacks_d);
+
+ bbs->stacks = XCNEWVEC (cil_stack, last_basic_block);
+
+ return bbs;
+}
+
+/* Destroy a stacks-to-basic-blocks mapping structure, also free all the stacks
+ it holds. */
+
+void
+cil_bb_stacks_destroy (cil_bb_stacks bbs)
+{
+ size_t i;
+
+ for (i = 0; i < (size_t) last_basic_block; i++)
+ {
+ if (bbs->stacks[i] != NULL)
+ cil_stack_free (bbs->stacks[i]);
+ }
+
+ XDELETEVEC (bbs->stacks);
+ XDELETE (bbs);
+}
+
+/* Returns the stack associated with the basic block BB if present, otherwise
+ a new empty stack will be associated with the basic block BB and
+ returned. */
+
+cil_stack
+cil_stack_for_bb (const_cil_bb_stacks bbs, basic_block bb)
+{
+ if (bbs->stacks[bb->index] == NULL)
+ bbs->stacks[bb->index] = cil_stack_create ();
+
+ return bbs->stacks[bb->index];
+}
+
+/* Sets to STACK the stack associated with the basic block BB. The stack is
+ copied so that the copy can be manipulated later without impacting the
+ original. If a stack was already associated with the basic block then
+ it is fred and replaced. */
+
+void
+cil_set_stack_for_bb (cil_bb_stacks bbs, basic_block bb, cil_stack stack)
+{
+ if (bbs->stacks[bb->index] == stack)
+ return;
+ else if (bbs->stacks[bb->index] != NULL)
+ cil_stack_free (bbs->stacks[bb->index]);
+
+ bbs->stacks[bb->index] = cil_stack_copy (stack);
+}
diff --git a/gcc/config/cil32/cil-stack.h b/gcc/config/cil32/cil-stack.h
new file mode 100644
index 00000000000..93e471860c8
--- /dev/null
+++ b/gcc/config/cil32/cil-stack.h
@@ -0,0 +1,123 @@
+/* Prototypes for the stack information functionality.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#ifndef CIL_STACK_H
+#define CIL_STACK_H
+
+#include "tree.h"
+#include "tree-flow.h"
+#include "cil-types.h"
+#include "cil-stmt.h"
+
+/******************************************************************************
+ * CIL stack types *
+ ******************************************************************************/
+
+/* Represents CIL types on the stack including types which wouldn't be on a
+ real CIL evaluation stack. The extra types are useful for optimizations
+ which rely on precise stack typization. */
+
+enum cil_type
+{
+ CIL_INT8, /* Signed 8-bit integer */
+ CIL_INT16, /* Signed 16-bit integer */
+ CIL_INT32, /* Signed 32-bit integer */
+ CIL_INT64, /* Signed 64-bit integer */
+ CIL_NATIVE_INT, /* Signed native integer */
+ CIL_UNSIGNED_INT8, /* Unsigned 8-bit integer */
+ CIL_UNSIGNED_INT16, /* Unsigned 16-bit integer */
+ CIL_UNSIGNED_INT32, /* Unsigned 32-bit integer */
+ CIL_UNSIGNED_INT64, /* Unsigned 64-bit integer */
+ CIL_NATIVE_UNSIGNED_INT, /* Unsigned native integer */
+ CIL_FLOAT, /* On-stack floating-point type*/
+ CIL_FLOAT32, /* Single precision floating-point */
+ CIL_FLOAT64, /* Double precision floating-point */
+ CIL_POINTER, /* Generic pointer */
+ CIL_VALUE_TYPE, /* Generic value type */
+};
+
+typedef enum cil_type cil_type_t;
+
+/* Represents the CIL stack. */
+
+DEF_VEC_I(cil_type_t);
+DEF_VEC_ALLOC_I(cil_type_t, heap);
+
+struct cil_stack_d
+{
+ VEC(cil_type_t, heap) *vec;
+};
+
+typedef struct cil_stack_d *cil_stack;
+typedef const struct cil_stack_d *const_cil_stack;
+
+/* Container used for holding a stack for each basic block in the current
+ function. */
+
+struct cil_bb_stacks_d
+{
+ cil_stack *stacks;
+};
+
+typedef struct cil_bb_stacks_d *cil_bb_stacks;
+typedef const struct cil_bb_stacks_d *const_cil_bb_stacks;
+
+/******************************************************************************
+ * Stack information interface *
+ ******************************************************************************/
+
+extern cil_stack cil_stack_create (void);
+extern cil_stack cil_stack_copy (const_cil_stack);
+extern void cil_stack_free (cil_stack);
+extern void cil_stack_after_stmt (cil_stack, cil_stmt);
+extern size_t cil_stack_depth (const_cil_stack);
+extern cil_type_t cil_stack_top (const_cil_stack);
+extern cil_type_t cil_stack_peek (const_cil_stack, size_t);
+
+extern cil_bb_stacks cil_bb_stacks_create (void);
+extern void cil_bb_stacks_destroy (cil_bb_stacks);
+extern cil_stack cil_stack_for_bb (const_cil_bb_stacks, basic_block);
+extern void cil_set_stack_for_bb (cil_bb_stacks, basic_block, cil_stack);
+
+/******************************************************************************
+ * CIL type interface *
+ ******************************************************************************/
+
+extern bool cil_integer_p (cil_type_t);
+extern bool cil_native_integer_p (cil_type_t);
+extern bool cil_float_p (cil_type_t);
+extern bool cil_pointer_p (cil_type_t);
+extern bool cil_int_or_smaller_p (cil_type_t);
+extern bool cil_long_p (cil_type_t);
+extern bool cil_unsigned_int_p (cil_type_t);
+extern cil_type_t scalar_to_cil (tree);
+
+#endif /* CIL_STACK_H */
diff --git a/gcc/config/cil32/cil-stmt-inline.h b/gcc/config/cil32/cil-stmt-inline.h
new file mode 100644
index 00000000000..0bd42c01e69
--- /dev/null
+++ b/gcc/config/cil32/cil-stmt-inline.h
@@ -0,0 +1,634 @@
+/* Inlined functions for manipulating CIL statements.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#ifndef CIL_STMT_INLINE_H
+#define CIL_STMT_INLINE_H
+
+/******************************************************************************
+ * CIL statement inlined functions *
+ ******************************************************************************/
+
+/* Return the code for CIL statement STMT. */
+
+static inline enum cil_opcode
+cil_opcode (const_cil_stmt stmt)
+{
+ return stmt->opcode;
+}
+
+/* Return the basic block holding the statement STMT. */
+
+static inline basic_block
+cil_bb (const_cil_stmt stmt)
+{
+ return stmt->bb;
+}
+
+/* Set the basic block holding the statement STMT to BB. */
+
+static inline void
+cil_set_bb (cil_stmt stmt, basic_block bb)
+{
+ stmt->bb = bb;
+}
+
+/* Return locus information for statement STMT. */
+
+static inline source_locus
+cil_locus (const_cil_stmt stmt)
+{
+ return stmt->locus;
+}
+
+/* Set locus information for statement STMT. */
+
+static inline void
+cil_set_locus (cil_stmt stmt, source_locus locus)
+{
+ stmt->locus = locus;
+}
+
+/* Return the variable declaration (VAR_DECL) held by a CIL statement. */
+
+static inline tree
+cil_var (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_VAR);
+
+ return stmt->arg.var;
+}
+
+/* Return the type definition (TYPE_DECL) held by a CIL statement. */
+
+static inline tree
+cil_type (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_TYPE);
+
+ return stmt->arg.type;
+}
+
+/* Return the field declaration (FIELD_DECL) held by a CIL statement. */
+
+static inline tree
+cil_field (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_FIELD);
+
+ return stmt->arg.field;
+}
+
+/* Return the label declaration (LABEL_DECL) held by a CIL statement. */
+
+static inline tree
+cil_label (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_LABEL);
+
+ return stmt->arg.label;
+}
+
+/* Return the number of cases of a CIL switch statment. */
+
+static inline size_t
+cil_switch_ncases (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+
+ return stmt->arg.labels->ncases;
+}
+
+/* Return the I-th case of a CIL switch statement. The last entry is the
+ default case. */
+
+static inline tree
+cil_switch_case (const_cil_stmt stmt, size_t i)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+ gcc_assert (i < stmt->arg.labels->ncases);
+
+ return stmt->arg.labels->cases[i];
+}
+
+/* Return the default case of a CIL switch statement. */
+
+static inline tree
+cil_switch_default (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+
+ return stmt->arg.labels->cases[stmt->arg.labels->ncases - 1];
+}
+
+/* Return the I-th case label of CIL switch statement. */
+
+static inline tree
+cil_switch_case_label (const_cil_stmt stmt, size_t i)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+ gcc_assert (i < stmt->arg.labels->ncases);
+
+ return CASE_LABEL (stmt->arg.labels->cases[i]);
+}
+
+/* Return the low value of the I-th case of CIL switch statement as an
+ HOST_WIDE_INT instead of a tree. */
+
+static inline HOST_WIDE_INT
+cil_switch_case_low (const_cil_stmt stmt, size_t i)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+ gcc_assert (i < stmt->arg.labels->ncases);
+
+ return tree_low_cst (CASE_LOW (stmt->arg.labels->cases[i]), 0);
+}
+
+/* Return the high value of the I-th case of CIL switch statement as an
+ HOST_WIDE_INT instead of a tree. If the case doesn't represent a range then
+ this function will return the case value (i.e. the low value). */
+
+static inline HOST_WIDE_INT
+cil_switch_case_high (const_cil_stmt stmt, size_t i)
+{
+ gcc_assert (stmt->opcode == CIL_SWITCH);
+ gcc_assert (i < stmt->arg.labels->ncases);
+
+ if (CASE_HIGH (stmt->arg.labels->cases[i]))
+ return tree_low_cst (CASE_HIGH (stmt->arg.labels->cases[i]), 0);
+ else
+ return tree_low_cst (CASE_LOW (stmt->arg.labels->cases[i]), 0);
+}
+
+/* Return the function declaration of a CIL LDFTN statement. */
+
+static inline
+tree cil_func (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_LDFTN);
+
+ return stmt->arg.func;
+}
+
+/* Builds a CIL CALL statement. The FDECL field holds the callee
+ declaration. */
+
+static inline cil_stmt
+cil_build_call (tree fdecl)
+{
+ return cil_build_call_generic (CIL_CALL, fdecl);
+}
+
+/* Builds a CIL CALLI statement. The FTYPE field holds the callee type. */
+
+static inline cil_stmt
+cil_build_calli (tree ftype)
+{
+ return cil_build_call_generic (CIL_CALLI, ftype);
+}
+
+/* Builds a CIL JMP statement. The FDECL field holds the callee declaration. */
+
+static inline cil_stmt
+cil_build_jmp (tree fdecl)
+{
+ return cil_build_call_generic (CIL_JMP, fdecl);
+}
+
+/* Builds a CIL CALL statement. The FDECL field holds the callee declaration.
+ The ARGLIST must be a pointer to a VEC (tree, heap) holding the types of the
+ arguments passed to the callee after the ellipsis. */
+
+static inline cil_stmt
+cil_build_call_va (tree fdecl, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_CALL, true, fdecl, arglist);
+}
+
+/* Builds a CIL CALLI statement. The FTYPE field holds the callee type. The
+ ARGLIST must be a pointer to a VEC (tree, heap) holding the types of the
+ arguments passed to the callee after the ellipsis. */
+
+static inline cil_stmt
+cil_build_calli_va (tree ftype, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_CALLI, true, ftype, arglist);
+}
+
+/* Builds a CIL JMP statement. The FDECL field holds the callee declaration.
+ The ARGLIST must be a pointer to a VEC (tree, heap) holding the types of the
+ arguments passed to the callee after the ellipsis. */
+
+static inline cil_stmt
+cil_build_jmp_va (tree fdecl, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_JMP, true, fdecl, arglist);
+}
+
+/* Builds a CIL CALL statement for a function without a prototype. The FDECL
+ field holds the callee declaration. The ARGLIST must be a pointer to a
+ VEC (tree, heap) holding the types of all the arguments passed to the
+ callee. */
+
+static inline cil_stmt
+cil_build_call_mp (tree fdecl, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_CALL, false, fdecl, arglist);
+}
+
+/* Builds a CIL CALL statement for a function without a prototype. The FTYPE
+ field holds the callee type. The ARGLIST must be a pointer to a
+ VEC (tree, heap) holding the types of all the arguments passed to the
+ callee. */
+
+static inline cil_stmt
+cil_build_calli_mp (tree ftype, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_CALLI, false, ftype, arglist);
+}
+
+/* Builds a CIL CALL statement for a function without a prototype. The FDECL
+ field holds the callee declaration. The ARGLIST must be a pointer to a
+ VEC (tree, heap) holding the types of all the arguments passed to the
+ callee. */
+
+static inline cil_stmt
+cil_build_jmp_mp (tree fdecl, VEC (tree, heap) *arglist)
+{
+ return cil_build_call_generic_list (CIL_JMP, false, fdecl, arglist);
+}
+
+/* Return the type of the callee of a CIL CALL, CALLI or JMP statement. */
+
+static inline tree
+cil_call_ftype (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ return stmt->arg.fcall->ftype;
+}
+
+/* Return the function declaration of the callee of a CIL CALL or JMP
+ statement. */
+
+static inline tree
+cil_call_fdecl (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL || stmt->opcode == CIL_JMP);
+
+ return stmt->arg.fcall->fdecl;
+}
+
+/* Return the number of arguments passed to the callee of a CIL CALL, CALLI or
+ JMP statement. */
+
+static inline size_t
+cil_call_nargs (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL || stmt->opcode == CIL_CALLI);
+
+ return stmt->arg.fcall->nargs;
+}
+
+/* Return the I-th argument passed to the callee of a CIL CALL, CALLI or JMP
+ statement. */
+
+static inline tree
+cil_call_arg_type (const_cil_stmt stmt, size_t i)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+ gcc_assert (i < stmt->arg.fcall->nargs);
+
+ return stmt->arg.fcall->arguments[i];
+}
+
+/* Set the type SC_TYPE of the static chain for the call STMT. */
+
+static inline void
+cil_call_set_static_chain (cil_stmt stmt, tree sc_type)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ stmt->arg.fcall->static_chain_p = true;
+ stmt->arg.fcall->static_chain = sc_type;
+}
+
+/* Return the type of the static chain for the call STMT if present. */
+
+static inline tree
+cil_call_static_chain (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ if (stmt->arg.fcall->static_chain_p)
+ return stmt->arg.fcall->static_chain;
+ else
+ return NULL_TREE;
+}
+
+/* Sets the type DUMMY_TYPE of a dummy argument passed to the call. This is
+ currently used for passing the type of a va_arg() call. */
+
+static inline void
+cil_call_set_dummy_arg (cil_stmt stmt, tree dummy_type)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ stmt->arg.fcall->static_chain = dummy_type;
+}
+
+/* Returns the type of the dummy argument passed to a call. This is currently
+ used for passing the type of a va_arg() call. */
+
+static inline tree
+cil_call_dummy_arg (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+ gcc_assert (!stmt->arg.fcall->static_chain_p);
+
+ return stmt->arg.fcall->static_chain;
+}
+
+/* Return true if the callee accepts a variable number of arguments. */
+
+static inline bool
+cil_call_vararg_p (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ return stmt->arg.fcall->vararg_p;
+}
+
+/* Return true if the callee doesn't have a prototype. */
+
+static inline bool
+cil_call_missing_proto_p (const_cil_stmt stmt)
+{
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ return stmt->arg.fcall->missing_proto_p;
+}
+
+/* Return a constant held by a CIL statement. */
+
+static inline tree
+cil_cst (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_CST);
+
+ return stmt->arg.cst;
+}
+
+/* Return a string held by a CIL statement. */
+
+static inline tree
+cil_string (const_cil_stmt stmt)
+{
+ gcc_assert (opcode_arg_type (stmt->opcode) == CIL_STRING);
+
+ return stmt->arg.str;
+}
+
+/******************************************************************************
+ * CIL sequence inlined functions *
+ ******************************************************************************/
+
+/* Return the first node in CIL sequence S. */
+
+static inline cil_seq_node
+cil_seq_first (const_cil_seq s)
+{
+ return s ? s->first : NULL;
+}
+
+/* Return the first statement in CIL sequence S. */
+
+static inline cil_stmt
+cil_seq_first_stmt (const_cil_seq s)
+{
+ cil_seq_node n = cil_seq_first (s);
+ return (n) ? n->stmt : NULL;
+}
+
+/* Return the last node in CIL sequence S. */
+
+static inline cil_seq_node
+cil_seq_last (const_cil_seq s)
+{
+ return s ? s->last : NULL;
+}
+
+/* Return the last statement in CIL sequence S. */
+
+static inline cil_stmt
+cil_seq_last_stmt (const_cil_seq s)
+{
+ cil_seq_node n = cil_seq_last (s);
+ return (n) ? n->stmt : NULL;
+}
+
+/* Set the last node in CIL sequence S to LAST. */
+
+static inline void
+cil_seq_set_last (cil_seq s, cil_seq_node last)
+{
+ s->last = last;
+}
+
+/* Set the first node in CIL sequence S to FIRST. */
+
+static inline void
+cil_seq_set_first (cil_seq s, cil_seq_node first)
+{
+ s->first = first;
+}
+
+/* Return true if CIL sequence S is empty. */
+
+static inline bool
+cil_seq_empty_p (const_cil_seq s)
+{
+ return s == NULL || s->first == NULL;
+}
+
+/******************************************************************************
+ * CIL statement iterator inlined functions *
+ ******************************************************************************/
+
+/* Return a new iterator pointing to SEQ's first statement. */
+
+static inline cil_stmt_iterator
+csi_start (cil_seq seq)
+{
+ cil_stmt_iterator i;
+
+ i.ptr = cil_seq_first (seq);
+ i.seq = seq;
+ i.bb = (i.ptr && i.ptr->stmt) ? cil_bb (i.ptr->stmt) : NULL;
+
+ return i;
+}
+
+/* Return a new iterator pointing to the first statement in basic block BB. */
+
+static inline cil_stmt_iterator
+csi_start_bb (basic_block bb)
+{
+ cil_stmt_iterator i;
+ cil_seq seq;
+
+ seq = cil_bb_seq (bb);
+ i.ptr = cil_seq_first (seq);
+ i.seq = seq;
+ i.bb = bb;
+
+ return i;
+}
+
+/* Return a new iterator initially pointing to SEQ's last statement. */
+
+static inline cil_stmt_iterator
+csi_last (cil_seq seq)
+{
+ cil_stmt_iterator i;
+
+ i.ptr = cil_seq_last (seq);
+ i.seq = seq;
+ i.bb = (i.ptr && i.ptr->stmt) ? cil_bb (i.ptr->stmt) : NULL;
+
+ return i;
+}
+
+
+/* Return a new iterator pointing to the last statement in basic block BB. */
+
+static inline cil_stmt_iterator
+csi_last_bb (basic_block bb)
+{
+ cil_stmt_iterator i;
+ cil_seq seq;
+
+ seq = cil_bb_seq (bb);
+ i.ptr = cil_seq_last (seq);
+ i.seq = seq;
+ i.bb = bb;
+
+ return i;
+}
+
+/* Return true if I is at the end of its sequence. */
+
+static inline bool
+csi_end_p (cil_stmt_iterator i)
+{
+ return i.ptr == NULL;
+}
+
+/* Return true if I is one statement before the end of its sequence. */
+
+static inline bool
+csi_one_before_end_p (cil_stmt_iterator i)
+{
+ return i.ptr != NULL && i.ptr->next == NULL;
+}
+
+/* Return true if I points to the first statement of its sequence. */
+
+static inline bool
+csi_first_p (cil_stmt_iterator i)
+{
+ return i.ptr == cil_seq_first (i.seq);
+}
+
+/* Advance the iterator to the next CIL statement. */
+
+static inline void
+csi_next (cil_stmt_iterator *i)
+{
+ i->ptr = i->ptr->next;
+}
+
+/* Advance the iterator to the previous CIL statement. */
+
+static inline void
+csi_prev (cil_stmt_iterator *i)
+{
+ i->ptr = i->ptr->prev;
+}
+
+/* Return the current stmt. */
+
+static inline cil_stmt
+csi_stmt (cil_stmt_iterator i)
+{
+ return i.ptr->stmt;
+}
+
+/* Return a pointer to the current stmt. */
+
+static inline cil_stmt *
+csi_stmt_ptr (cil_stmt_iterator *i)
+{
+ return &i->ptr->stmt;
+}
+
+/* Return the basic block associated with this iterator. */
+
+static inline basic_block
+csi_bb (cil_stmt_iterator i)
+{
+ return i.bb;
+}
+
+/* Return the sequence associated with this iterator. */
+
+static inline cil_seq
+csi_seq (cil_stmt_iterator i)
+{
+ return i.seq;
+}
+
+#endif /* !CIL_STMT_INLINE_H */
diff --git a/gcc/config/cil32/cil-stmt.c b/gcc/config/cil32/cil-stmt.c
new file mode 100644
index 00000000000..0480ce38d53
--- /dev/null
+++ b/gcc/config/cil32/cil-stmt.c
@@ -0,0 +1,1317 @@
+/* CIL statements, sequences and iterators implementation.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "ggc.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "cil-types.h"
+#include "cil-refs.h"
+#include "cil-stmt.h"
+
+/******************************************************************************
+ * Globals *
+ ******************************************************************************/
+
+/* A cache of cil_seq objects. Sequences are created and destroyed fairly
+ often so it's better to keep the fred ones around. */
+static GTY ((deletable)) struct cil_seq_d *cil_seq_cache = NULL;
+
+/******************************************************************************
+ * Local function prototypes *
+ ******************************************************************************/
+
+static void update_bb_for_cil_stmts (cil_seq_node, basic_block);
+static void csi_insert_seq_nodes_before (cil_stmt_iterator *, cil_seq_node,
+ cil_seq_node,
+ enum csi_iterator_update);
+static void csi_insert_seq_nodes_after (cil_stmt_iterator *, cil_seq_node,
+ cil_seq_node, enum csi_iterator_update);
+
+/******************************************************************************
+ * CIL statement functions *
+ ******************************************************************************/
+
+/* Create a new CIL statement with no arguments. */
+
+cil_stmt
+cil_build_stmt (enum cil_opcode opcode)
+{
+ cil_stmt stmt;
+
+ gcc_assert (opcode_arg_type (opcode) == CIL_NONE);
+
+ stmt = GGC_CNEW (struct cil_stmt_d);
+ stmt->opcode = opcode;
+
+ return stmt;
+}
+
+/* Create a new CIL statement with one argument. CIL SWITCH, CALL, CALLI and
+ JMP statements cannot be built with this function and must be built with the
+ appropriate functions. */
+
+cil_stmt
+cil_build_stmt_arg (enum cil_opcode opcode, tree arg)
+{
+ cil_stmt stmt;
+
+ gcc_assert (opcode_arg_type (opcode) != CIL_NONE);
+
+ stmt = GGC_CNEW (struct cil_stmt_d);
+ stmt->opcode = opcode;
+
+ switch (opcode_arg_type (opcode))
+ {
+ case CIL_VAR: stmt->arg.var = arg; break;
+ case CIL_TYPE: stmt->arg.type = arg; break;
+ case CIL_FIELD: stmt->arg.field = arg; break;
+ case CIL_LABEL: stmt->arg.label = arg; break;
+ case CIL_FUNC: stmt->arg.func = arg; break;
+ case CIL_CST: stmt->arg.cst = arg; break;
+ case CIL_STRING: stmt->arg.str = arg; break;
+ default: gcc_unreachable ();
+ }
+
+ return stmt;
+}
+
+/* Create a new CIL switch statement with the case / label couples taken from
+ a TREE_VEC of CASE_LABELs as used in a GIMPLE SWITCH_EXPR. */
+
+cil_stmt
+cil_build_switch (tree labels)
+{
+ cil_stmt stmt = GGC_CNEW (struct cil_stmt_d);
+ cil_switch_arg arg = GGC_NEW (struct cil_switch_arg_d);
+ unsigned int i, length = TREE_VEC_LENGTH (labels);
+
+ gcc_assert (length != 0);
+ arg->ncases = length;
+ arg->cases = GGC_NEWVEC (tree, length);
+
+ /* This sets the default case correctly as it is the last element in both the
+ TREE_VEC and in the cases array. */
+ for (i = 0; i < length; i++)
+ arg->cases[i] = TREE_VEC_ELT (labels, i);
+
+ stmt->opcode = CIL_SWITCH;
+ stmt->arg.labels = arg;
+
+ return stmt;
+}
+
+/* Build a generic CIL call statement. The OPCODE parameter specifies the type
+ of jump. The TYPE_OR_DECL parameter holds the function declaration or the
+ function type depending if the call is direct or not. */
+
+cil_stmt
+cil_build_call_generic (enum cil_opcode opcode, tree type_or_decl)
+{
+ cil_stmt stmt = GGC_CNEW (struct cil_stmt_d);
+ cil_call_arg arg = GGC_CNEW (struct cil_call_arg_d);
+ tree arg_types;
+ size_t i;
+
+ gcc_assert (opcode == CIL_CALL || opcode == CIL_CALLI || opcode == CIL_JMP);
+
+ if (opcode != CIL_CALLI)
+ {
+ arg->ftype = TREE_TYPE (type_or_decl);
+ arg->fdecl = type_or_decl;
+ }
+ else
+ arg->ftype = type_or_decl;
+
+ arg_types = TYPE_ARG_TYPES (arg->ftype);
+
+ if (arg_types == NULL)
+ {
+ arg->nargs = 0;
+ arg->arguments = NULL;
+ }
+ else
+ {
+ arg->nargs = list_length (arg_types) - 1;
+ arg->arguments = GGC_NEWVEC (tree, arg->nargs);
+
+ for (i = 0; i < arg->nargs; i++)
+ {
+ arg->arguments[i] = TREE_VALUE (arg_types);
+ arg_types = TREE_CHAIN (arg_types);
+ }
+ }
+
+ stmt->opcode = opcode;
+ stmt->arg.fcall = arg;
+ return stmt;
+}
+
+/* Build a generic CIL call statement taking extra arguments not specified in
+ the signature. OPCODE specifies the type of jump. VA requires the call to
+ be flagged as taking a variable number of arguments. TYPE_OR_DECL holds the
+ function declaration or the function type depending if the call is direct or
+ not. The ARGLIST must be a TREE_VEC holding the arguments passed after the
+ ellipsis for a vararg call and all the arguments for a call lacking the
+ prototype. This function is used both for creating vararg calls and calls to
+ regular functions whose prototype is missing. */
+
+cil_stmt
+cil_build_call_generic_list (enum cil_opcode opcode, bool va,
+ tree type_or_decl, VEC (tree, heap) *arglist)
+{
+ cil_stmt stmt = GGC_CNEW (struct cil_stmt_d);
+ cil_call_arg arg = GGC_CNEW (struct cil_call_arg_d);
+ tree arg_types;
+ size_t nargs_base;
+ size_t i;
+
+ gcc_assert (opcode == CIL_CALL || opcode == CIL_CALLI || opcode == CIL_JMP);
+
+ if (opcode != CIL_CALLI)
+ {
+ arg->ftype = TREE_TYPE (type_or_decl);
+ arg->fdecl = type_or_decl;
+ }
+ else
+ arg->ftype = type_or_decl;
+
+ arg_types = TYPE_ARG_TYPES (arg->ftype);
+
+ if (arg_types == NULL)
+ nargs_base = 0;
+ else
+ nargs_base = list_length (arg_types);
+
+ arg->nargs = nargs_base + VEC_length (tree, arglist);
+
+ if (arg->nargs == 0)
+ arg->arguments = NULL;
+ else
+ arg->arguments = GGC_NEWVEC (tree, arg->nargs);
+
+ for (i = 0; i < nargs_base; i++)
+ {
+ arg->arguments[i] = TREE_VALUE (arg_types);
+ arg_types = TREE_CHAIN (arg_types);
+ }
+
+ for ( ; i < arg->nargs; i++)
+ arg->arguments[i] = VEC_index (tree, arglist, i - nargs_base);
+
+ if (va)
+ arg->vararg_p = true;
+ else
+ arg->missing_proto_p = true;
+
+ stmt->opcode = opcode;
+ stmt->arg.fcall = arg;
+ return stmt;
+}
+
+/* Return the number of arguments accepted by the callee of a CIL CALL or CALLI
+ statement. This does not include the arguments after the ellipsis in a
+ variable argument call. */
+
+size_t
+cil_call_nargs_base (const_cil_stmt stmt)
+{
+ tree arg_types;
+
+ gcc_assert (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP);
+
+ arg_types = TYPE_ARG_TYPES (stmt->arg.fcall->ftype);
+
+ if (arg_types == NULL)
+ return 0;
+ else
+ {
+ if (cil_call_vararg_p (stmt))
+ return list_length (arg_types);
+ else
+ return list_length (arg_types) - 1;
+ }
+}
+
+/* Create a deep copy of the CIL statement pointed by STMT and return it. */
+
+cil_stmt
+cil_copy_stmt (const_cil_stmt stmt)
+{
+ cil_stmt new_stmt;
+
+ new_stmt = GGC_NEW (struct cil_stmt_d);
+ memcpy (new_stmt, stmt, sizeof (struct cil_stmt_d));
+
+ if (stmt->opcode == CIL_SWITCH)
+ {
+ cil_switch_arg arg = GGC_NEW (struct cil_switch_arg_d);
+ unsigned int ncases = stmt->arg.labels->ncases;
+
+ arg->ncases = ncases;
+ arg->cases = GGC_NEWVEC (tree, ncases);
+ memcpy (arg->cases, stmt->arg.labels->cases, sizeof (tree) * ncases);
+ new_stmt->arg.labels = arg;
+ }
+ else if (stmt->opcode == CIL_CALL
+ || stmt->opcode == CIL_CALLI
+ || stmt->opcode == CIL_JMP)
+ {
+ cil_call_arg arg = GGC_NEW (struct cil_call_arg_d);
+ unsigned int nargs = stmt->arg.fcall->nargs;
+
+ memcpy (arg, &stmt->arg.fcall, sizeof (struct cil_call_arg_d));
+
+ if (nargs != 0)
+ {
+ arg->arguments = GGC_NEWVEC (tree, nargs);
+ memcpy (arg->arguments, stmt->arg.fcall->arguments,
+ sizeof (tree) * nargs);
+ }
+ }
+
+ return new_stmt;
+}
+
+/* Returns the tail. prefix to the CIL statement pointed by STMT. */
+
+bool
+cil_prefix_tail (const_cil_stmt stmt)
+{
+ gcc_assert ((stmt->opcode == CIL_CALL) || (stmt->opcode == CIL_CALLI));
+
+ return stmt->prefix_tail;
+}
+
+/* Sets the tail. prefix to STATUS in the CIL statment pointed by STMT. */
+
+void
+cil_set_prefix_tail (cil_stmt stmt, bool status)
+{
+ gcc_assert ((stmt->opcode == CIL_CALL) || (stmt->opcode == CIL_CALLI));
+
+ stmt->prefix_tail = status ? 1 : 0;
+}
+
+/* Returns the value of the unaligned. prefix of the CIL statement pointed by
+ STMT. If the prefix is not specified the returned value will be 0,
+ otherwise the alignment (either 1, 2 or 4) will be returned. */
+
+int
+cil_prefix_unaligned (const_cil_stmt stmt)
+{
+ gcc_assert ((stmt->opcode == CIL_CPBLK) || (stmt->opcode == CIL_INITBLK)
+ || (stmt->opcode == CIL_LDOBJ) || (stmt->opcode == CIL_STOBJ)
+ || ((stmt->opcode >= CIL_LDIND_I1) && (stmt->opcode <= CIL_LDIND_I))
+ || ((stmt->opcode >= CIL_STIND_I1) && (stmt->opcode <= CIL_STIND_I))
+ || (stmt->opcode == CIL_LDFLD) || (stmt->opcode == CIL_STFLD));
+
+ return stmt->prefix_unaligned ? stmt->alignment : 0;
+}
+
+/* Sets the unaligned. prefix in the CIL statement pointed by STMT. The actual
+ alignment is taken from ALIGNMENT and must be either 1, 2 or 4. */
+
+void
+cil_set_prefix_unaligned (cil_stmt stmt, int alignment)
+{
+ gcc_assert ((stmt->opcode == CIL_CPBLK) || (stmt->opcode == CIL_INITBLK)
+ || (stmt->opcode == CIL_LDOBJ) || (stmt->opcode == CIL_STOBJ)
+ || ((stmt->opcode >= CIL_LDIND_I1) && (stmt->opcode <= CIL_LDIND_I))
+ || ((stmt->opcode >= CIL_STIND_I1) && (stmt->opcode <= CIL_STIND_I))
+ || (stmt->opcode == CIL_LDFLD) || (stmt->opcode == CIL_STFLD));
+ gcc_assert ((alignment == 1) || (alignment == 2) || (alignment == 4));
+
+ stmt->prefix_unaligned = alignment ? 1 : 0;
+ stmt->alignment = alignment;
+}
+
+/* Sets the volatile. prefix to STATUS in the CIL statement pointed by STMT. */
+
+void
+cil_set_prefix_volatile (cil_stmt stmt, bool status)
+{
+ gcc_assert ((stmt->opcode == CIL_CPBLK) || (stmt->opcode == CIL_INITBLK)
+ || (stmt->opcode == CIL_LDOBJ) || (stmt->opcode == CIL_STOBJ)
+ || ((stmt->opcode >= CIL_LDIND_I1) && (stmt->opcode <= CIL_LDIND_I))
+ || ((stmt->opcode >= CIL_STIND_I1) && (stmt->opcode <= CIL_STIND_I))
+ || (stmt->opcode == CIL_LDFLD) || (stmt->opcode == CIL_STFLD)
+ || (stmt->opcode == CIL_LDSFLD) || (stmt->opcode == CIL_STSFLD));
+
+ stmt->prefix_volatile = status ? 1 : 0;
+}
+
+/* Returns the status of the volatile. prefix in the CIL statement pointed by
+ STMT. */
+
+bool
+cil_prefix_volatile (const_cil_stmt stmt)
+{
+ gcc_assert ((stmt->opcode == CIL_CPBLK) || (stmt->opcode == CIL_INITBLK)
+ || (stmt->opcode == CIL_LDOBJ) || (stmt->opcode == CIL_STOBJ)
+ || ((stmt->opcode >= CIL_LDIND_I1) && (stmt->opcode <= CIL_LDIND_I))
+ || ((stmt->opcode >= CIL_STIND_I1) && (stmt->opcode <= CIL_STIND_I))
+ || (stmt->opcode == CIL_LDFLD) || (stmt->opcode == CIL_STFLD)
+ || (stmt->opcode == CIL_LDSFLD) || (stmt->opcode == CIL_STSFLD));
+
+ return stmt->prefix_volatile;
+}
+
+/* Returns the type of argument of the opcode specified by the OPCODE
+ argument. */
+
+enum cil_arg_type
+opcode_arg_type (enum cil_opcode opcode)
+{
+ switch (opcode)
+ {
+ case CIL_LDARG:
+ case CIL_LDARGA:
+ case CIL_LDLOC:
+ case CIL_LDLOCA:
+ case CIL_STARG:
+ case CIL_STLOC:
+ return CIL_VAR;
+
+ case CIL_INITOBJ:
+ case CIL_LDOBJ:
+ case CIL_STOBJ:
+ return CIL_TYPE;
+
+ case CIL_LDFLD:
+ case CIL_LDFLDA:
+ case CIL_LDSFLD:
+ case CIL_LDSFLDA:
+ case CIL_STFLD:
+ case CIL_STSFLD:
+ return CIL_FIELD;
+
+ case CIL_BEQ:
+ case CIL_BGE:
+ case CIL_BGE_UN:
+ case CIL_BGT:
+ case CIL_BGT_UN:
+ case CIL_BLE:
+ case CIL_BLE_UN:
+ case CIL_BLT:
+ case CIL_BLT_UN:
+ case CIL_BNE_UN:
+ case CIL_BR:
+ case CIL_BRFALSE:
+ case CIL_BRTRUE:
+ return CIL_LABEL;
+
+ case CIL_SWITCH:
+ return CIL_LABELS;
+
+ case CIL_LDFTN:
+ return CIL_FUNC;
+
+ case CIL_CALL:
+ case CIL_CALLI:
+ case CIL_JMP:
+ return CIL_FCALL;
+
+ case CIL_LDC_I4:
+ case CIL_LDC_I8:
+ case CIL_LDC_R4:
+ case CIL_LDC_R8:
+ return CIL_CST;
+
+ case CIL_ASM:
+ return CIL_STRING;
+
+ default:
+ return CIL_NONE;
+ }
+}
+
+/* Returns TRUE if the CIL stsatement STMT represents a conversion, FALSE
+ otherwise. */
+
+bool
+cil_conversion_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_CONV_I1:
+ case CIL_CONV_I2:
+ case CIL_CONV_I4:
+ case CIL_CONV_I8:
+ case CIL_CONV_R4:
+ case CIL_CONV_R8:
+ case CIL_CONV_U1:
+ case CIL_CONV_U2:
+ case CIL_CONV_U4:
+ case CIL_CONV_U8:
+ case CIL_CONV_I:
+ case CIL_CONV_U:
+ case CIL_CONV_R_UN:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns TRUE if the CIL statement STMT is a conditional branch instruction,
+ FALSE otherwise. */
+
+bool
+cil_cond_branch_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_BEQ:
+ case CIL_BGE:
+ case CIL_BGE_UN:
+ case CIL_BGT:
+ case CIL_BGT_UN:
+ case CIL_BLE:
+ case CIL_BLE_UN:
+ case CIL_BLT:
+ case CIL_BLT_UN:
+ case CIL_BNE_UN:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns TRUE if the CIL statement STMT is an indirect load, FALSE
+ otherwise. */
+
+bool
+cil_ldind_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_LDIND_I1:
+ case CIL_LDIND_I2:
+ case CIL_LDIND_I4:
+ case CIL_LDIND_I8:
+ case CIL_LDIND_U1:
+ case CIL_LDIND_U2:
+ case CIL_LDIND_U4:
+ case CIL_LDIND_U8:
+ case CIL_LDIND_R4:
+ case CIL_LDIND_R8:
+ case CIL_LDIND_I:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns TRUE if the CIL statement STMT is an indirect store, FALSE
+ otherwise. */
+
+bool
+cil_stind_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_STIND_I1:
+ case CIL_STIND_I2:
+ case CIL_STIND_I4:
+ case CIL_STIND_I8:
+ case CIL_STIND_R4:
+ case CIL_STIND_R8:
+ case CIL_STIND_I:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns TRUE if the CIL stsatement STMT pushes a single slot on the stack
+ without side effects, false otherwise. */
+
+bool
+cil_push_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_DUP:
+ case CIL_LDARG:
+ case CIL_LDARGA:
+ case CIL_LDC_I4:
+ case CIL_LDC_I8:
+ case CIL_LDC_R4:
+ case CIL_LDC_R8:
+ case CIL_LDFTN:
+ case CIL_LDLOC:
+ case CIL_LDLOCA:
+ case CIL_LDSFLD:
+ case CIL_LDSFLDA:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/******************************************************************************
+ * CIL sequence functions *
+ ******************************************************************************/
+
+/* Allocate a new CIL sequence in GC memory and return it. If there are free
+ sequences in GIMPLE_SEQ_CACHE return one of those instead. */
+
+cil_seq
+cil_seq_alloc (void)
+{
+ cil_seq seq = cil_seq_cache;
+
+ if (seq)
+ {
+ cil_seq_cache = cil_seq_cache->next_free;
+ gcc_assert (cil_seq_cache != seq);
+ memset (seq, 0, sizeof (*seq));
+ }
+ else
+ seq = GGC_CNEW (struct cil_seq_d);
+
+ return seq;
+}
+
+/* Return SEQ to the free pool of CIL sequences. */
+
+void
+cil_seq_free (cil_seq seq)
+{
+ if (seq == NULL)
+ return;
+
+ gcc_assert (cil_seq_first (seq) == NULL);
+ gcc_assert (cil_seq_last (seq) == NULL);
+
+ /* If this triggers, it's a sign that the same list is being freed
+ twice. */
+ gcc_assert (seq != cil_seq_cache || cil_seq_cache == NULL);
+
+ /* Add SEQ to the pool of free sequences. */
+ seq->next_free = cil_seq_cache;
+ cil_seq_cache = seq;
+}
+
+/* Link CIL statement CS to the end of the sequence *SEQ_P. If
+ *SEQ_P is NULL, a new sequence is allocated. */
+
+void
+cil_seq_add_stmt (cil_seq *seq_p, cil_stmt cs)
+{
+ cil_stmt_iterator si;
+
+ if (cs == NULL)
+ return;
+
+ if (*seq_p == NULL)
+ *seq_p = cil_seq_alloc ();
+
+ si = csi_last (*seq_p);
+ csi_insert_after (&si, cs, CSI_NEW_STMT);
+}
+
+/* Append sequence SRC to the end of sequence *DST_P. If *DST_P is
+ NULL, a new sequence is allocated. */
+
+void
+cil_seq_add_seq (cil_seq *dst_p, cil_seq src)
+{
+ cil_stmt_iterator si;
+
+ if (src == NULL)
+ return;
+
+ if (*dst_p == NULL)
+ *dst_p = cil_seq_alloc ();
+
+ si = csi_last (*dst_p);
+ csi_insert_seq_after (&si, src, CSI_NEW_STMT);
+}
+
+/* Perform a deep copy of sequence SRC and return the result. */
+
+cil_seq
+cil_seq_deep_copy (cil_seq src)
+{
+ cil_stmt_iterator csi;
+ cil_seq new_seq = cil_seq_alloc ();
+ cil_stmt stmt;
+
+ for (csi = csi_start (src); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = cil_copy_stmt (csi_stmt (csi));
+ cil_seq_add_stmt (&new_seq, stmt);
+ }
+
+ return new_seq;
+}
+
+/* Returns the sequence of statements in BB. */
+
+cil_seq
+cil_bb_seq (const basic_block bb)
+{
+ struct machine_function *machine = cfun->machine;
+ struct cil_basic_block_d tmp;
+ void **slot;
+
+ tmp.bb = bb;
+ slot = htab_find_slot (machine->bb_seqs, &tmp, INSERT);
+
+ gcc_assert (*slot != NULL);
+ return ((cil_basic_block) *slot)->seq;
+}
+
+/* Sets the sequence of statements in BB to SEQ. */
+
+void
+cil_set_bb_seq (basic_block bb, cil_seq seq)
+{
+ struct machine_function *machine = cfun->machine;
+ struct cil_basic_block_d tmp;
+ void **slot;
+
+ tmp.bb = bb;
+ slot = htab_find_slot (machine->bb_seqs, &tmp, INSERT);
+
+ if (*slot == NULL)
+ {
+ cil_basic_block cbb = GGC_NEW (struct cil_basic_block_d);
+
+ cbb->bb = bb;
+ cbb->seq = seq;
+ *slot = cbb;
+ }
+ else
+ ((cil_basic_block) *slot)->seq = seq;
+}
+
+/* Computes the stack depth at the end of the sequence pointed by SEQ. INIT
+ specifies the initial stack depth of the sequence. If MAX is true then the
+ maximum stack depth is returned, otherwise the depth at the end of the
+ sequence is returned. */
+
+unsigned int
+cil_seq_stack_depth (cil_seq seq, unsigned int init, bool max)
+{
+ cil_stmt_iterator i;
+ unsigned int max_depth = init;
+ unsigned int depth = init;
+ unsigned int nargs;
+
+ if (cil_seq_empty_p (seq))
+ return max_depth;
+
+ for (i = csi_start (seq); !csi_end_p (i); csi_next (&i))
+ {
+ cil_stmt cs = csi_stmt (i);
+
+ switch (cil_opcode (cs))
+ {
+ case CIL_CPBLK:
+ case CIL_INITBLK:
+ gcc_assert (depth >= 3);
+ depth -= 3;
+ break;
+
+ case CIL_BEQ:
+ case CIL_BGE:
+ case CIL_BGE_UN:
+ case CIL_BGT:
+ case CIL_BGT_UN:
+ case CIL_BLE:
+ case CIL_BLE_UN:
+ case CIL_BLT:
+ case CIL_BLT_UN:
+ case CIL_BNE_UN:
+ case CIL_STFLD:
+ case CIL_STIND_I1:
+ case CIL_STIND_I2:
+ case CIL_STIND_I4:
+ case CIL_STIND_I8:
+ case CIL_STIND_R4:
+ case CIL_STIND_R8:
+ case CIL_STIND_I:
+ case CIL_STOBJ:
+ gcc_assert (depth >= 2);
+ depth -= 2;
+ break;
+
+ case CIL_ADD:
+ case CIL_AND:
+ case CIL_CEQ:
+ case CIL_CGT:
+ case CIL_CGT_UN:
+ case CIL_CLT:
+ case CIL_CLT_UN:
+ case CIL_DIV:
+ case CIL_DIV_UN:
+ case CIL_MUL:
+ case CIL_OR:
+ case CIL_REM:
+ case CIL_REM_UN:
+ case CIL_SHL:
+ case CIL_SHR:
+ case CIL_SHR_UN:
+ case CIL_SUB:
+ case CIL_XOR:
+ gcc_assert (depth >= 2);
+ depth--;
+ break;
+
+ case CIL_BRFALSE:
+ case CIL_BRTRUE:
+ case CIL_INITOBJ:
+ case CIL_POP:
+ case CIL_STARG:
+ case CIL_STLOC:
+ case CIL_STSFLD:
+ case CIL_SWITCH:
+ gcc_assert (depth >= 1);
+ depth--;
+ break;
+
+ case CIL_CKFINITE:
+ case CIL_CONV_I1:
+ case CIL_CONV_I2:
+ case CIL_CONV_I4:
+ case CIL_CONV_I8:
+ case CIL_CONV_R4:
+ case CIL_CONV_R8:
+ case CIL_CONV_U1:
+ case CIL_CONV_U2:
+ case CIL_CONV_U4:
+ case CIL_CONV_U8:
+ case CIL_CONV_I:
+ case CIL_CONV_U:
+ case CIL_CONV_R_UN:
+ case CIL_LDFLD:
+ case CIL_LDFLDA:
+ case CIL_LDIND_I1:
+ case CIL_LDIND_I2:
+ case CIL_LDIND_I4:
+ case CIL_LDIND_I8:
+ case CIL_LDIND_U1:
+ case CIL_LDIND_U2:
+ case CIL_LDIND_U4:
+ case CIL_LDIND_U8:
+ case CIL_LDIND_R4:
+ case CIL_LDIND_R8:
+ case CIL_LDIND_I:
+ case CIL_LDOBJ:
+ case CIL_LOCALLOC:
+ case CIL_NEG:
+ case CIL_NOT:
+ gcc_assert (depth >= 1);
+ break;
+
+ case CIL_BR:
+ case CIL_BREAK:
+ break;
+
+ case CIL_DUP:
+ gcc_assert (depth >= 1);
+ depth++;
+ max_depth = (depth > max_depth) ? depth : max_depth;
+ break;
+
+ case CIL_ARGLIST:
+ case CIL_LDARG:
+ case CIL_LDARGA:
+ case CIL_LDC_I4:
+ case CIL_LDC_I8:
+ case CIL_LDC_R4:
+ case CIL_LDC_R8:
+ case CIL_LDFTN:
+ case CIL_LDLOC:
+ case CIL_LDLOCA:
+ case CIL_LDSFLD:
+ case CIL_LDSFLDA:
+ depth++;
+ max_depth = (depth > max_depth) ? depth : max_depth;
+ break;
+
+ case CIL_RET:
+ if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ {
+ gcc_assert (depth == 1);
+ depth--;
+ }
+ else
+ gcc_assert (depth == 0);
+
+ break;
+
+ case CIL_CALL:
+ case CIL_JMP:
+ nargs = cil_call_nargs (cs) + (cil_call_static_chain (cs) ? 1 : 0);
+ gcc_assert (depth >= nargs);
+ depth -= nargs;
+
+ if (!VOID_TYPE_P (TREE_TYPE (cil_call_ftype (cs))))
+ {
+ depth++;
+ max_depth = (depth > max_depth) ? depth : max_depth;
+ }
+
+ break;
+
+ case CIL_CALLI:
+ nargs = cil_call_nargs (cs) + 1
+ + (cil_call_static_chain (cs) ? 1 : 0);
+ gcc_assert (depth >= nargs);
+ depth -= nargs;
+
+ if (!VOID_TYPE_P (TREE_TYPE (cil_call_ftype (cs))))
+ {
+ depth++;
+ max_depth = (depth > max_depth) ? depth : max_depth;
+ }
+
+ break;
+
+ case CIL_ASM:
+ /* TODO: Specify a way for asm statements to tell the compiler how
+ many stack slots they need. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return max ? max_depth : depth;
+}
+
+/******************************************************************************
+ * CIL statement iterator functions *
+ ******************************************************************************/
+
+/* Move all statements in the sequence after I to a new sequence.
+ Return this new sequence. */
+
+cil_seq
+csi_split_seq_after (cil_stmt_iterator i)
+{
+ cil_seq_node cur, next;
+ cil_seq old_seq, new_seq;
+
+ cur = i.ptr;
+
+ /* How can we possibly split after the end, or before the beginning? */
+ gcc_assert (cur && cur->next);
+ next = cur->next;
+
+ old_seq = i.seq;
+ new_seq = cil_seq_alloc ();
+
+ cil_seq_set_first (new_seq, next);
+ cil_seq_set_last (new_seq, cil_seq_last (old_seq));
+ cil_seq_set_last (old_seq, cur);
+ cur->next = NULL;
+ next->prev = NULL;
+
+ return new_seq;
+}
+
+/* Move all statements in the sequence before I to a new sequence.
+ Return this new sequence. I is set to the head of the new list. */
+
+cil_seq
+csi_split_seq_before (cil_stmt_iterator *i)
+{
+ cil_seq_node cur, prev;
+ cil_seq old_seq, new_seq;
+
+ cur = i->ptr;
+
+ /* How can we possibly split after the end? */
+ gcc_assert (cur);
+ prev = cur->prev;
+
+ old_seq = i->seq;
+ new_seq = cil_seq_alloc ();
+ i->seq = new_seq;
+
+ /* Set the limits on NEW_SEQ. */
+ cil_seq_set_first (new_seq, cur);
+ cil_seq_set_last (new_seq, cil_seq_last (old_seq));
+
+ /* Cut OLD_SEQ before I. */
+ cil_seq_set_last (old_seq, prev);
+ cur->prev = NULL;
+
+ if (prev)
+ prev->next = NULL;
+ else
+ cil_seq_set_first (old_seq, NULL);
+
+ return new_seq;
+}
+
+/* Replace the statement pointed-to by CSI to STMT. */
+
+void
+csi_replace (cil_stmt_iterator *csi, cil_stmt stmt)
+{
+ cil_stmt orig_stmt = csi_stmt (*csi);
+
+ if (stmt == orig_stmt)
+ return;
+
+ cil_set_locus (stmt, cil_locus (orig_stmt));
+ cil_set_bb (stmt, csi_bb (*csi));
+
+ *csi_stmt_ptr (csi) = stmt;
+}
+
+/* Insert statement STMT before the statement pointed-to by iterator
+ I, update STMT's basic block. M specifies how to update iterator
+ I after insertion (see enum csi_iterator_update). */
+
+void
+csi_insert_before (cil_stmt_iterator *i, cil_stmt stmt,
+ enum csi_iterator_update m)
+{
+ cil_seq_node n;
+
+ n = GGC_NEW (struct cil_seq_node_d);
+ n->prev = n->next = NULL;
+ n->stmt = stmt;
+ csi_insert_seq_nodes_before (i, n, n, m);
+}
+
+/* Inserts the sequence of statements SEQ before the statement pointed
+ by iterator I. M indicates what to do with the iterator after
+ insertion (see enum csi_iterator_update). */
+
+void
+csi_insert_seq_before (cil_stmt_iterator *i, cil_seq seq,
+ enum csi_iterator_update m)
+{
+ cil_seq_node first, last;
+
+ /* Don't allow inserting a sequence into itself. */
+ gcc_assert (seq != i->seq);
+
+ first = cil_seq_first (seq);
+ last = cil_seq_last (seq);
+
+ cil_seq_set_first (seq, NULL);
+ cil_seq_set_last (seq, NULL);
+ cil_seq_free (seq);
+
+ /* Empty sequences need no work. */
+ if (!first || !last)
+ {
+ gcc_assert (first == last);
+ return;
+ }
+
+ csi_insert_seq_nodes_before (i, first, last, m);
+}
+
+/* Insert statement STMT after the statement pointed-to by iterator I,
+ update STMT's basic block. M specifies how to update iterator I
+ after insertion (see enum csi_iterator_update). */
+
+void
+csi_insert_after (cil_stmt_iterator *i, cil_stmt stmt,
+ enum csi_iterator_update m)
+{
+ cil_seq_node n;
+
+ n = GGC_NEW (struct cil_seq_node_d);
+ n->prev = n->next = NULL;
+ n->stmt = stmt;
+ csi_insert_seq_nodes_after (i, n, n, m);
+}
+
+/* Links sequence SEQ after the statement pointed-to by iterator I.
+ M is as in csi_insert_after. */
+
+void
+csi_insert_seq_after (cil_stmt_iterator *i, cil_seq seq,
+ enum csi_iterator_update m)
+{
+ cil_seq_node first, last;
+
+ /* Don't allow inserting a sequence into itself. */
+ gcc_assert (seq != i->seq);
+
+ first = cil_seq_first (seq);
+ last = cil_seq_last (seq);
+
+ cil_seq_set_first (seq, NULL);
+ cil_seq_set_last (seq, NULL);
+ cil_seq_free (seq);
+
+ /* Empty sequences need no work. */
+ if (!first || !last)
+ {
+ gcc_assert (first == last);
+ return;
+ }
+
+ csi_insert_seq_nodes_after (i, first, last, m);
+}
+
+/* Remove the current stmt from the sequence. The iterator is updated
+ to point to the next statement. */
+
+void
+csi_remove (cil_stmt_iterator *i)
+{
+ cil_seq_node cur, next, prev;
+ cil_stmt stmt = csi_stmt (*i);
+
+ /* Free all the data flow information for STMT. */
+ cil_set_bb (stmt, NULL);
+
+ /* Update the iterator and re-wire the links in I->SEQ. */
+ cur = i->ptr;
+ next = cur->next;
+ prev = cur->prev;
+
+ if (prev)
+ prev->next = next;
+ else
+ cil_seq_set_first (i->seq, next);
+
+ if (next)
+ next->prev = prev;
+ else
+ cil_seq_set_last (i->seq, prev);
+
+ i->ptr = next;
+}
+
+/* Finds iterator for STMT. */
+
+cil_stmt_iterator
+csi_for_stmt (cil_stmt stmt)
+{
+ cil_stmt_iterator i;
+
+ for (i = csi_start_bb (cil_bb (stmt)); !csi_end_p (i); csi_next (&i))
+ if (csi_stmt (i) == stmt)
+ return i;
+
+ gcc_unreachable ();
+}
+
+/* Move the statement at FROM so it comes right after the statement at TO. */
+
+void
+csi_move_after (cil_stmt_iterator *from, cil_stmt_iterator *to)
+{
+ cil_stmt stmt = csi_stmt (*from);
+ csi_remove (from);
+
+ /* We must have CSI_NEW_STMT here, as csi_move_after is sometimes used to
+ move statements to an empty block. */
+ csi_insert_after (to, stmt, CSI_NEW_STMT);
+}
+
+/* Move the statement at FROM so it comes right before the statement
+ at TO. */
+
+void
+csi_move_before (cil_stmt_iterator *from, cil_stmt_iterator *to)
+{
+ cil_stmt stmt = csi_stmt (*from);
+ csi_remove (from);
+
+ /* For consistency with csi_move_after, it might be better to have
+ CSI_NEW_STMT here; however, that breaks several places that expect
+ that TO does not change. */
+ csi_insert_before (to, stmt, CSI_SAME_STMT);
+}
+
+/* Move the statement at FROM to the end of basic block BB. */
+
+void
+csi_move_to_bb_end (cil_stmt_iterator *from, basic_block bb)
+{
+ cil_stmt_iterator last = csi_last (cil_bb_seq (bb));
+
+ /* Have to check csi_end_p because it could be an empty block. */
+ if (!csi_end_p (last))
+ csi_move_before (from, &last);
+ else
+ csi_move_after (from, &last);
+}
+
+/******************************************************************************
+ * Helper functions *
+ ******************************************************************************/
+
+/* Set BB to be the basic block for all the statements in the list
+ starting at FIRST and LAST. */
+
+static void
+update_bb_for_cil_stmts (cil_seq_node first, basic_block bb)
+{
+ cil_seq_node n;
+
+ for (n = first; n != NULL; n = n->next)
+ cil_set_bb (n->stmt, bb);
+}
+
+/* Insert the sequence delimited by nodes FIRST and LAST before
+ iterator I. M specifies how to update iterator I after insertion
+ (see enum csi_iterator_update).
+
+ This routine assumes that there is a forward and backward path
+ between FIRST and LAST (i.e., they are linked in a doubly-linked
+ list). Additionally, if FIRST == LAST, this routine will properly
+ insert a single node. */
+
+static void
+csi_insert_seq_nodes_before (cil_stmt_iterator *i, cil_seq_node first,
+ cil_seq_node last, enum csi_iterator_update m)
+{
+ basic_block bb;
+ cil_seq_node cur = i->ptr;
+
+ if ((bb = csi_bb (*i)) != NULL)
+ update_bb_for_cil_stmts (first, bb);
+
+ /* Link SEQ before CUR in the sequence. */
+ if (cur)
+ {
+ first->prev = cur->prev;
+
+ if (first->prev)
+ first->prev->next = first;
+ else
+ cil_seq_set_first (i->seq, first);
+
+ last->next = cur;
+ cur->prev = last;
+ }
+ else
+ {
+ gcc_assert (!cil_seq_first (i->seq));
+ cil_seq_set_first (i->seq, first);
+ cil_seq_set_last (i->seq, last);
+ }
+
+ /* Update the iterator, if requested. */
+ switch (m)
+ {
+ case CSI_NEW_STMT:
+ case CSI_CONTINUE_LINKING:
+ i->ptr = first;
+ break;
+ case CSI_SAME_STMT:
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Insert the sequence delimited by nodes FIRST and LAST after
+ iterator I. M specifies how to update iterator I after insertion
+ (see enum csi_iterator_update).
+
+ This routine assumes that there is a forward and backward path
+ between FIRST and LAST (i.e., they are linked in a doubly-linked
+ list). Additionally, if FIRST == LAST, this routine will properly
+ insert a single node. */
+
+static void
+csi_insert_seq_nodes_after (cil_stmt_iterator *i, cil_seq_node first,
+ cil_seq_node last, enum csi_iterator_update m)
+{
+ basic_block bb;
+ cil_seq_node cur = i->ptr;
+
+ /* If the iterator is inside a basic block, we need to update the
+ basic block information for all the nodes between FIRST and LAST. */
+ if ((bb = csi_bb (*i)) != NULL)
+ update_bb_for_cil_stmts (first, bb);
+
+ /* Link SEQ after CUR. */
+ if (cur)
+ {
+ last->next = cur->next;
+
+ if (last->next)
+ last->next->prev = last;
+ else
+ cil_seq_set_last (i->seq, last);
+
+ first->prev = cur;
+ cur->next = first;
+ }
+ else
+ {
+ gcc_assert (!cil_seq_last (i->seq));
+ cil_seq_set_first (i->seq, first);
+ cil_seq_set_last (i->seq, last);
+ }
+
+ /* Update the iterator, if requested. */
+ switch (m)
+ {
+ case CSI_NEW_STMT:
+ i->ptr = first;
+ break;
+ case CSI_CONTINUE_LINKING:
+ i->ptr = last;
+ break;
+ case CSI_SAME_STMT:
+ gcc_assert (cur);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+#include "gt-cil-stmt.h"
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/cil-stmt.h b/gcc/config/cil32/cil-stmt.h
new file mode 100644
index 00000000000..df4ddbb05f2
--- /dev/null
+++ b/gcc/config/cil32/cil-stmt.h
@@ -0,0 +1,186 @@
+/* Type declarations and prototypes of the CIL statements.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#ifndef CIL_STMT_H
+#define CIL_STMT_H
+
+#include "input.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "cil-types.h"
+
+/******************************************************************************
+ * CIL statement interface *
+ ******************************************************************************/
+
+extern cil_stmt cil_build_stmt (enum cil_opcode);
+extern cil_stmt cil_build_stmt_arg (enum cil_opcode, tree);
+extern cil_stmt cil_build_switch (tree);
+extern cil_stmt cil_build_call_generic (enum cil_opcode, tree);
+extern cil_stmt cil_build_call_generic_list (enum cil_opcode, bool,
+ tree, VEC (tree, heap) *);
+extern cil_stmt cil_copy_stmt (const_cil_stmt);
+extern bool cil_prefix_tail (const_cil_stmt);
+extern void cil_set_prefix_tail (cil_stmt, bool);
+extern int cil_prefix_unaligned (const_cil_stmt);
+extern void cil_set_prefix_unaligned (cil_stmt, int);
+extern bool cil_prefix_volatile (const_cil_stmt);
+extern void cil_set_prefix_volatile (cil_stmt, bool);
+extern size_t cil_call_nargs_base (const_cil_stmt);
+
+static inline enum cil_opcode cil_opcode (const_cil_stmt);
+static inline basic_block cil_bb (const_cil_stmt);
+static inline void cil_set_bb (cil_stmt, basic_block);
+static inline source_locus cil_locus (const_cil_stmt);
+static inline void cil_set_locus (cil_stmt, source_locus);
+static inline tree cil_var (const_cil_stmt);
+static inline tree cil_type (const_cil_stmt);
+static inline tree cil_field (const_cil_stmt);
+static inline tree cil_label (const_cil_stmt);
+static inline size_t cil_switch_ncases (const_cil_stmt);
+static inline tree cil_switch_case (const_cil_stmt, size_t);
+static inline tree cil_switch_default (const_cil_stmt);
+static inline tree cil_switch_case_label (const_cil_stmt, size_t);
+static inline HOST_WIDE_INT cil_switch_case_low (const_cil_stmt, size_t);
+static inline HOST_WIDE_INT cil_switch_case_high (const_cil_stmt, size_t);
+static inline tree cil_func (const_cil_stmt);
+static inline cil_stmt cil_build_call (tree);
+static inline cil_stmt cil_build_calli (tree);
+static inline cil_stmt cil_build_jmp (tree);
+static inline cil_stmt cil_build_call_va (tree, VEC (tree, heap) *);
+static inline cil_stmt cil_build_calli_va (tree, VEC (tree, heap) *);
+static inline cil_stmt cil_build_jmp_va (tree, VEC (tree, heap) *);
+static inline cil_stmt cil_build_call_mp (tree, VEC (tree, heap) *);
+static inline cil_stmt cil_build_calli_mp (tree, VEC (tree, heap) *);
+static inline cil_stmt cil_build_jmp_mp (tree, VEC (tree, heap) *);
+static inline tree cil_call_ftype (const_cil_stmt);
+static inline tree cil_call_fdecl (const_cil_stmt);
+static inline size_t cil_call_nargs (const_cil_stmt);
+static inline tree cil_call_arg_type (const_cil_stmt, size_t);
+static inline void cil_call_set_static_chain (cil_stmt, tree);
+static inline tree cil_call_static_chain (const_cil_stmt);
+static inline void cil_call_set_dummy_arg (cil_stmt, tree);
+static inline tree cil_call_dummy_arg (const_cil_stmt);
+static inline bool cil_call_vararg_p (const_cil_stmt);
+static inline bool cil_call_missing_proto_p (const_cil_stmt);
+static inline tree cil_cst (const_cil_stmt);
+static inline tree cil_string (const_cil_stmt);
+
+extern bool cil_conversion_p (const_cil_stmt);
+extern bool cil_cond_branch_p (const_cil_stmt);
+extern bool cil_ldind_p (const_cil_stmt);
+extern bool cil_stind_p (const_cil_stmt);
+extern bool cil_push_p (const_cil_stmt);
+
+extern enum cil_arg_type opcode_arg_type (enum cil_opcode);
+
+/******************************************************************************
+ * CIL sequence interface *
+ ******************************************************************************/
+
+static inline cil_seq_node cil_seq_first (const_cil_seq);
+static inline cil_stmt cil_seq_first_stmt (const_cil_seq);
+static inline cil_seq_node cil_seq_last (const_cil_seq);
+static inline cil_stmt cil_seq_last_stmt (const_cil_seq);
+static inline void cil_seq_set_last (cil_seq, cil_seq_node);
+static inline void cil_seq_set_first (cil_seq, cil_seq_node);
+static inline bool cil_seq_empty_p (const_cil_seq);
+extern cil_seq cil_seq_alloc (void);
+extern void cil_seq_free (cil_seq);
+extern void cil_seq_add_stmt (cil_seq *, cil_stmt);
+extern void cil_seq_add_seq (cil_seq *, cil_seq);
+extern cil_seq cil_seq_deep_copy (cil_seq);
+extern cil_seq cil_bb_seq (basic_block);
+extern void cil_set_bb_seq (basic_block, cil_seq);
+extern unsigned int cil_seq_stack_depth (cil_seq, unsigned int, bool);
+
+/******************************************************************************
+ * CIL statement iterator declaration & interface *
+ ******************************************************************************/
+
+/* Iterator object for CIL statement sequences. */
+
+typedef struct
+{
+ /* Current node. */
+ cil_seq_node ptr;
+
+ /* Sequence and basic block associated with this iterator. */
+ cil_seq seq;
+ basic_block bb;
+} cil_stmt_iterator;
+
+/* CIL statement list iterator interface */
+static inline cil_stmt_iterator csi_start (cil_seq);
+static inline cil_stmt_iterator csi_start_bb (basic_block);
+static inline cil_stmt_iterator csi_last (cil_seq);
+static inline cil_stmt_iterator csi_last_bb (basic_block);
+static inline bool csi_end_p (cil_stmt_iterator);
+static inline bool csi_one_before_end_p (cil_stmt_iterator);
+static inline bool csi_first_p (cil_stmt_iterator);
+static inline void csi_next (cil_stmt_iterator *);
+static inline void csi_prev (cil_stmt_iterator *);
+static inline cil_stmt csi_stmt (cil_stmt_iterator);
+static inline cil_stmt *csi_stmt_ptr (cil_stmt_iterator *);
+static inline basic_block csi_bb (cil_stmt_iterator);
+static inline cil_seq csi_seq (cil_stmt_iterator);
+
+enum csi_iterator_update
+{
+ CSI_NEW_STMT, /* Only valid when single statement is added, move
+ iterator to it. */
+ CSI_SAME_STMT, /* Leave the iterator at the same statement. */
+ CSI_CONTINUE_LINKING /* Move iterator to whatever position is suitable
+ for linking other statements in the same
+ direction. */
+};
+
+extern cil_seq csi_split_seq_after (cil_stmt_iterator);
+extern cil_seq csi_split_seq_before (cil_stmt_iterator *);
+extern void csi_replace (cil_stmt_iterator *, cil_stmt);
+extern void csi_insert_before (cil_stmt_iterator *, cil_stmt,
+ enum csi_iterator_update);
+extern void csi_insert_seq_before (cil_stmt_iterator *, cil_seq,
+ enum csi_iterator_update);
+extern void csi_insert_after (cil_stmt_iterator *, cil_stmt,
+ enum csi_iterator_update);
+extern void csi_insert_seq_after (cil_stmt_iterator *, cil_seq,
+ enum csi_iterator_update);
+extern void csi_remove (cil_stmt_iterator *);
+extern cil_stmt_iterator csi_for_stmt (cil_stmt);
+extern void csi_move_after (cil_stmt_iterator *, cil_stmt_iterator *);
+extern void csi_move_before (cil_stmt_iterator *, cil_stmt_iterator *);
+extern void csi_move_to_bb_end (cil_stmt_iterator *, basic_block);
+
+/* Inlined functions */
+#include "cil-stmt-inline.h"
+
+#endif /* !CIL_STMT_H */
diff --git a/gcc/config/cil32/cil-types.h b/gcc/config/cil32/cil-types.h
index 45839ad8055..ef505db0b97 100644
--- a/gcc/config/cil32/cil-types.h
+++ b/gcc/config/cil32/cil-types.h
@@ -38,14 +38,6 @@ Erven Rohou <erven.rohou@st.com>
* Misc types *
******************************************************************************/
- /* Per-function machine data. */
-
-struct machine_function GTY(())
-{
- unsigned int label_id;
- tree label_addrs;
-};
-
/* Referenced string entry. */
struct str_ref_d GTY(())
@@ -72,4 +64,276 @@ struct label_addr_d GTY(())
typedef struct label_addr_d *label_addr;
+/******************************************************************************
+ * CIL statements *
+ ******************************************************************************/
+
+/* CIL opcodes, only the relevant opcodes are represented. Opcodes which have
+ no equivalent in GIMPLE or are not useful for emission are not present. */
+
+enum cil_opcode
+{
+ CIL_ADD, /* Add numeric values */
+ CIL_AND, /* Logical and */
+ CIL_ARGLIST, /* Get argument list */
+ CIL_BEQ, /* Branch on equal */
+ CIL_BGE, /* Branch on greater or equal */
+ CIL_BGE_UN, /* Branch on greater or equal, unsigned or unordered */
+ CIL_BGT, /* Branch on greater than */
+ CIL_BGT_UN, /* Branch on greater than, unsigned or unordered */
+ CIL_BLE, /* Branch on less or equal */
+ CIL_BLE_UN, /* Branch on less or equal, unsigned or unordered */
+ CIL_BLT, /* Branch on less than */
+ CIL_BLT_UN, /* Branch on less than, unsigned or unordered */
+ CIL_BNE_UN, /* Branch on not equal, unsigned or unordered */
+ CIL_BR, /* Branch unconditional */
+ CIL_BREAK, /* Breakpoint instruction */
+ CIL_BRFALSE, /* Branch on false, null or zero */
+ CIL_BRTRUE, /* Branch on non-false, non-null, or non-zero */
+ CIL_CALL, /* Method call */
+ CIL_CALLI, /* Indirect method call */
+ CIL_CEQ, /* Compare equal */
+ CIL_CGT, /* Compare greater than */
+ CIL_CGT_UN, /* Compare greater than, unsigned or unordered */
+ CIL_CKFINITE, /* Check for a finite real number */
+ CIL_CLT, /* Compare less than */
+ CIL_CLT_UN, /* Compare less than unordered */
+ CIL_CONV_I1, /* Convert to int8 */
+ CIL_CONV_I2, /* Convert to int16 */
+ CIL_CONV_I4, /* Convert to int32 */
+ CIL_CONV_I8, /* Convert to int64 */
+ CIL_CONV_R4, /* Convert to float32 */
+ CIL_CONV_R8, /* Convert to float64 */
+ CIL_CONV_U1, /* Convert to unsigned int8 */
+ CIL_CONV_U2, /* Convert to unsigned int16 */
+ CIL_CONV_U4, /* Convert to unsigned int32 */
+ CIL_CONV_U8, /* Convert to unsigned int64 */
+ CIL_CONV_I, /* Convert to native int */
+ CIL_CONV_U, /* Convert to unsigned native int */
+ CIL_CONV_R_UN, /* Convert unsigned integer to floating-point */
+ CIL_CPBLK, /* Copy data from memory to memory */
+ CIL_DIV, /* Divide values */
+ CIL_DIV_UN, /* Divide values, unsigned */
+ CIL_DUP, /* Duplicate the value on top of the stack */
+ CIL_INITBLK, /* Set all bytes in a block of memory to a given byte value */
+ CIL_INITOBJ, /* Initialize the value at an address */
+ CIL_JMP, /* Jump to method */
+ CIL_LDARG, /* Load an argument on the operand stack */
+ CIL_LDARGA, /* Load an argument's address */
+ CIL_LDC_I4, /* Load an int32 numeric constant on the stack */
+ CIL_LDC_I8, /* Load an int64 numeric constant on the stack */
+ CIL_LDC_R4, /* Load a float32 numeric constant on the stack */
+ CIL_LDC_R8, /* Load a float64 numeric constant on the stack */
+ CIL_LDFLD, /* Load field of an object */
+ CIL_LDFLDA, /* Load field address */
+ CIL_LDFTN, /* Load method pointer */
+ CIL_LDIND_I1, /* Indirect load value of type int8 */
+ CIL_LDIND_I2, /* Indirect load value of type int16 */
+ CIL_LDIND_I4, /* Indirect load value of type int32 */
+ CIL_LDIND_I8, /* Indirect load value of type int64 */
+ CIL_LDIND_U1, /* Indirect load value of type unsigned int8 */
+ CIL_LDIND_U2, /* Indirect load value of type unsigned int16 */
+ CIL_LDIND_U4, /* Indirect load value of type unsigned int32 */
+ CIL_LDIND_U8, /* Indirect load value of type unsigned int64 */
+ CIL_LDIND_R4, /* Indirect load value of type float32 */
+ CIL_LDIND_R8, /* Indirect load value of type float64 */
+ CIL_LDIND_I, /* Indirect load value of type native int */
+ CIL_LDLOC, /* Load local variable onto the stack */
+ CIL_LDLOCA, /* Load local variable address */
+ CIL_LDOBJ, /* Copy a value from an address to the stack */
+ CIL_LDSFLD, /* Load static field of a class */
+ CIL_LDSFLDA, /* Load static field address */
+ CIL_LOCALLOC, /* Allocate space from the local memory pool */
+ CIL_MUL, /* Multiply values */
+ CIL_NEG, /* Negate value */
+ CIL_NOT, /* Bitwise complement */
+ CIL_OR, /* Bitwise or */
+ CIL_POP, /* Remove the top element of the stack */
+ CIL_REM, /* Compute remainder */
+ CIL_REM_UN, /* Compute integer remainder, unsigned */
+ CIL_RET, /* Return from method */
+ CIL_SHL, /* Shift integer left */
+ CIL_SHR, /* Shift integer right */
+ CIL_SHR_UN, /* Shift integer right, unsigned */
+ CIL_STARG, /* Store a value in an argument slot */
+ CIL_STFLD, /* Store field of an object */
+ CIL_STIND_I1, /* Store int8 value indirect from stack */
+ CIL_STIND_I2, /* Store int16 value indirect from stack */
+ CIL_STIND_I4, /* Store int32 value indirect from stack */
+ CIL_STIND_I8, /* Store int64 value indirect from stack */
+ CIL_STIND_R4, /* Store float32 value indirect from stack */
+ CIL_STIND_R8, /* Store float64 value indirect from stack */
+ CIL_STIND_I, /* Store native int value indirect from stack */
+ CIL_STLOC, /* Pop value from stack to local variable */
+ CIL_STOBJ, /* Store a value at an address */
+ CIL_STSFLD, /* Store static field of a class */
+ CIL_SUB, /* Substract numeric value */
+ CIL_SWITCH, /* Table switch based on value */
+ CIL_XOR, /* Bitwise exclusive or */
+
+ /* Artificial opcodes */
+ CIL_ASM /* Artificial opcode representing ASM_EXPR statements */
+};
+
+/* CIL statement argument type, used by the garbage collector. */
+
+enum cil_arg_type
+{
+ CIL_VAR, /* Variable declaration */
+ CIL_TYPE, /* Type declaration */
+ CIL_FIELD, /* Field declaration */
+ CIL_LABEL, /* Label declaration */
+ CIL_LABELS, /* Switch case labels */
+ CIL_FUNC, /* Function declaration */
+ CIL_FCALL, /* Function call description */
+ CIL_CST, /* Integer or real constant */
+ CIL_STRING, /* A string (held in a tree, not a char *) */
+ CIL_NONE /* No argument */
+};
+
+/* Represents the information provided by a CALL_EXPR when converted to a CIL
+ CALL or CALLI instruction. The FTYPE fields points to the called function
+ type, the FDECL field to the function declaration (or NULL_TREE for a CALLI),
+ the ARGLIST holds the types of the arguments which were passed to the
+ function (including those after the ellipsis in a variable argument call
+ and the NARGS field holds their number. If the STATIC_CHAIN_P field is
+ set then the STATIC_CHAIN field holds the type of the static chain. If
+ STATIC_CHAIN is non-NULL and STATIC_CHAIN_P is not set then STATIC_CHAIN
+ holds the type of a dummy argument (like the type passed to a va_arg() call)
+ which shall be treated differently compared to the other arguments. The
+ VARARG field is set to true if the callee accepts a variable number of
+ arguments, false otherwise. */
+
+struct cil_call_arg_d GTY (())
+{
+ tree ftype;
+ tree fdecl;
+ tree * GTY ((length ("%h.nargs"))) arguments;
+ size_t nargs;
+ tree static_chain;
+ unsigned vararg_p : 1;
+ unsigned missing_proto_p : 1;
+ unsigned static_chain_p : 1;
+};
+
+typedef struct cil_call_arg_d *cil_call_arg;
+
+/* An array of CASE_LABEL_EXPRs used as the argument of CIL_SWITCH statements.
+ The entry 0 is the default label. Check tree.def for more information on
+ CASE_LABEL_EXPRs. */
+
+struct cil_switch_arg_d GTY (())
+{
+ size_t ncases;
+ tree * GTY ((length ("%h.ncases"))) cases;
+};
+
+typedef struct cil_switch_arg_d *cil_switch_arg;
+
+/* A CIL statement. The stack image pointed by the STACK field represents the
+ various types held in the stack slots. This image is taken *before* the
+ statement has executed. */
+
+struct cil_stmt_d GTY (())
+{
+ /* Opcode of this statement. */
+ ENUM_BITFIELD (cil_opcode) opcode : 8;
+
+ /* Instruction prefixes. Unaligned and alignment can be specified on the same
+ instruction depending on the opcode. For the alignment prefix the minimum
+ alignment (1, 2 or 4) is also specified. */
+ unsigned prefix_tail : 1;
+ unsigned prefix_unaligned : 1;
+ unsigned alignment : 3;
+ unsigned prefix_volatile : 1;
+
+ /* Statement argument if present. Can be a variable, type, field, label or
+ function declaration; a list of switch labels, a function type descriptor
+ or a constant (either integer or real). */
+ union
+ {
+ tree GTY ((tag ("CIL_VAR"))) var;
+ tree GTY ((tag ("CIL_TYPE"))) type;
+ tree GTY ((tag ("CIL_FIELD"))) field;
+ tree GTY ((tag ("CIL_LABEL"))) label;
+ cil_switch_arg GTY ((tag ("CIL_LABELS"))) labels;
+ tree GTY ((tag ("CIL_FUNC"))) func;
+ cil_call_arg GTY ((tag ("CIL_FCALL"))) fcall;
+ tree GTY ((tag ("CIL_CST"))) cst;
+ tree GTY ((tag ("CIL_STRING"))) str;
+ } GTY ((desc ("opcode_arg_type (%0.opcode)"))) arg;
+
+ /* Basic block holding this statement. */
+ struct basic_block_def *bb;
+
+ /* Original location in the source. */
+ struct location_s *locus;
+};
+
+typedef struct cil_stmt_d *cil_stmt;
+typedef const struct cil_stmt_d *const_cil_stmt;
+
+/******************************************************************************
+ * CIL sequence *
+ ******************************************************************************/
+
+/* A node in a cil_seq_d. */
+
+struct cil_seq_node_d GTY((chain_next ("%h.next"), chain_prev ("%h.prev")))
+{
+ cil_stmt stmt;
+ struct cil_seq_node_d *prev;
+ struct cil_seq_node_d *next;
+};
+
+typedef struct cil_seq_node_d *cil_seq_node;
+
+/* A double-linked sequence of CIL statements. */
+
+struct cil_seq_d GTY ((chain_next ("%h.next_free")))
+{
+ /* First and last statements in the sequence. */
+ cil_seq_node first;
+ cil_seq_node last;
+
+ /* Sequences are created/destroyed frequently. To minimize
+ allocation activity, deallocated sequences are kept in a pool of
+ available sequences. This is the pointer to the next free
+ sequence in the pool. */
+ struct cil_seq_d *next_free;
+};
+
+typedef struct cil_seq_d *cil_seq;
+typedef const struct cil_seq_d *const_cil_seq;
+
+/* Mapping for basic blocks and CIL sequences. */
+
+struct cil_basic_block_d GTY (())
+{
+ /* Basic block, defined as a generic pointer in order not to pull more
+ header files in there. */
+ void * GTY ((skip)) bb;
+
+ /* CIL sequence associated with the basic block. */
+ cil_seq seq;
+};
+
+typedef struct cil_basic_block_d *cil_basic_block;
+
+/******************************************************************************
+ * Per-function target specific global data *
+ ******************************************************************************/
+
+struct htab;
+
+/* Per-function machine data. */
+struct machine_function GTY(())
+{
+ unsigned int label_id;
+ tree label_addrs;
+
+ /* Hash table used for mapping CIL sequences to GCC's basic blocks. */
+ struct htab * GTY ((param_is (struct cil_basic_block_d))) bb_seqs;
+};
+
#endif /* !CIL_TYPES_H */
diff --git a/gcc/config/cil32/cil32.c b/gcc/config/cil32/cil32.c
index 0cb76be32df..abce0966f79 100644
--- a/gcc/config/cil32/cil32.c
+++ b/gcc/config/cil32/cil32.c
@@ -61,9 +61,12 @@ Erven Rohou <erven.rohou@st.com>
#include "cil-builtins.h"
#include "cil-types.h"
#include "cil-refs.h"
-#include "gen-cil.h"
+#include "emit-cil.h"
static struct machine_function *cil_init_machine_status (void);
+static hashval_t cil_basic_block_hash (const void *);
+static int cil_basic_block_eq (const void *, const void *);
+
static tree cil32_handle_function_attribute (tree *, tree, tree, int, bool *);
static void cil32_file_start (void);
static void cil32_file_end (void);
@@ -112,10 +115,12 @@ struct gcc_target targetm = TARGET_INITIALIZER;
static struct machine_function *
cil_init_machine_status (void)
{
- struct machine_function *machine = GGC_NEW(struct machine_function);
+ struct machine_function *machine = GGC_NEW (struct machine_function);
machine->label_id = 0;
machine->label_addrs = NULL_TREE;
+ machine->bb_seqs = htab_create_ggc (32, cil_basic_block_hash,
+ cil_basic_block_eq, NULL);
return machine;
}
@@ -126,6 +131,27 @@ cil_override_options (void)
init_machine_status = cil_init_machine_status;
}
+/* Hash value calculation function for CIL basic blocks. */
+
+static hashval_t
+cil_basic_block_hash (const void *ptr)
+{
+ cil_basic_block cbb = (cil_basic_block) ptr;
+
+ return (hashval_t) ((long) cbb->bb >> 3);
+}
+
+/* Equality function for CIL basic blocks. */
+
+static int
+cil_basic_block_eq (const void *ptr1, const void *ptr2)
+{
+ cil_basic_block cbb1 = (cil_basic_block) ptr1;
+ cil_basic_block cbb2 = (cil_basic_block) ptr2;
+
+ return cbb1->bb == cbb2->bb;
+}
+
static tree
cil32_handle_function_attribute (tree *node, tree name,
tree args ATTRIBUTE_UNUSED,
@@ -141,7 +167,7 @@ cil32_handle_function_attribute (tree *node, tree name,
}
if (strcmp (IDENTIFIER_POINTER (name), "pinvoke") == 0)
- cil_add_pinvoke(*node);
+ add_pinvoke (*node);
return NULL_TREE;
}
@@ -161,15 +187,15 @@ static void
cil32_file_start (void)
{
refs_init ();
- gen_cil_init ();
- cil_vcg_init ();
+ emit_vcg_init ();
+ emit_cil_init ();
}
static void
cil32_file_end (void)
{
- cil_vcg_fini ();
- gen_cil_fini ();
+ emit_cil_fini ();
+ emit_vcg_fini ();
refs_fini ();
}
diff --git a/gcc/config/cil32/cil32.h b/gcc/config/cil32/cil32.h
index ca83e6d0a1d..03516b5c3f6 100644
--- a/gcc/config/cil32/cil32.h
+++ b/gcc/config/cil32/cil32.h
@@ -39,7 +39,7 @@ Erven Rohou <erven.rohou@st.com>
#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)
+#define TARGET_DECLARE_VARIABLE(STREAM,DECL) emit_cil_decl(STREAM,DECL)
/* Node: Driver */
@@ -76,7 +76,6 @@ extern int target_flags;
#define TARGET_VERSION \
fprintf (stderr, " [cil32]")
-
#define OVERRIDE_OPTIONS cil_override_options ()
/* Node: Storage Layout */
@@ -525,11 +524,16 @@ struct cum_args {int regs;};
#define NO_IMPLICIT_EXTERN_C
-extern struct tree_opt_pass pass_bb_layout;
extern struct tree_opt_pass pass_simp_cil_early;
-extern struct tree_opt_pass pass_simp_cil_final;
-extern struct tree_opt_pass pass_gen_cil;
-extern struct tree_opt_pass pass_cil_vcg;
+extern struct tree_opt_pass pass_bb_layout;
+extern struct tree_opt_pass pass_gimple_to_cil;
+extern struct tree_opt_pass pass_missing_protos;
+extern struct tree_opt_pass pass_cil_peephole;
+extern struct tree_opt_pass pass_remove_convs;
+extern struct tree_opt_pass pass_remove_temps;
+extern struct tree_opt_pass pass_simp_cond;
+extern struct tree_opt_pass pass_emit_cil_vcg;
+extern struct tree_opt_pass pass_emit_cil;
/*
* Local variables:
diff --git a/gcc/config/cil32/cil32.opt b/gcc/config/cil32/cil32.opt
index 45e3a751ce0..3431f6a543e 100644
--- a/gcc/config/cil32/cil32.opt
+++ b/gcc/config/cil32/cil32.opt
@@ -37,10 +37,6 @@ mopensystemc
Target Undocumented Mask(OPENSYSTEMC)
Use OpenSystem.C Attributes
-mno-stloc-ldloc-removal
-Target Mask(NO_STLOC_LDLOC_REMOVAL)
-Do not do stloc/ldloc couples removal
-
mexpand-abs
Target Mask(EXPAND_ABS)
Expand abs (absolute value) instead of generating a call to Crt::abs
@@ -49,10 +45,6 @@ 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-vcg
Target Mask(EMIT_VCG)
Emits the functions in VCG format
diff --git a/gcc/config/cil32/emit-cil.c b/gcc/config/cil32/emit-cil.c
new file mode 100644
index 00000000000..bc412bc9422
--- /dev/null
+++ b/gcc/config/cil32/emit-cil.c
@@ -0,0 +1,2571 @@
+/* Dump of CIL code into assembly.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "toplev.h"
+#include "errors.h"
+#include "ggc.h"
+#include "real.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "ebitmap.h"
+#include "langhooks.h"
+#include "output.h"
+#include "pointer-set.h"
+#include "varray.h"
+#include "cil-builtins.h"
+#include "cil-refs.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+#include "emit-hints.h"
+#include "emit-cil.h"
+
+/******************************************************************************
+ * Type declarations *
+ ******************************************************************************/
+
+struct fnct_attr
+{
+ const char *assembly_name;
+ const char *cil_name;
+ const char *cusattr_string;
+ const char *pinvoke_assembly;
+ const char *pinvoke_fname;
+};
+
+/* Structure used to store the number of uses of a local variable. */
+
+struct var_uses
+{
+ tree var;
+ unsigned int uses;
+};
+
+typedef struct var_uses var_uses_s;
+
+DEF_VEC_O(var_uses_s);
+DEF_VEC_ALLOC_O(var_uses_s, heap);
+
+/******************************************************************************
+ * Globals *
+ ******************************************************************************/
+
+static bool init = false;
+
+/******************************************************************************
+ * Local function prototypes *
+ ******************************************************************************/
+
+static unsigned int compute_max_stack ( void );
+static void decode_function_attrs (tree, struct fnct_attr *);
+static void emit_enum_decl (FILE *, tree);
+static void emit_array_decl (FILE *, tree);
+static void emit_incomplete_decl (FILE *, tree);
+static void emit_struct_union_decl (FILE *, tree);
+static void emit_valuetype_decl (FILE *, 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_valuetype_name (FILE *, tree);
+static void dump_fun_type (FILE *, tree, tree, const char *, bool);
+static void dump_vector_type (FILE *, tree, bool);
+static void dump_complex_type (FILE *, tree, bool);
+static void dump_type (FILE *, tree, bool, bool);
+static void dump_string_type (FILE *, tree);
+static void dump_string_decl (FILE *, tree);
+static bool dump_type_promoted_type_def (FILE *, tree);
+
+static void emit_referenced_strings (FILE *);
+static void emit_referenced_types (FILE *);
+static void emit_pinvoke_function (FILE *, tree);
+static void emit_referenced_pinvokes (FILE *);
+static void emit_prefixes (FILE *, const_cil_stmt);
+static void emit_ldsfld (FILE *, const_cil_stmt);
+static void emit_ldsflda (FILE *, const_cil_stmt);
+static void emit_ldfld (FILE *, const_cil_stmt);
+static void emit_ldflda (FILE *, const_cil_stmt);
+static void emit_stfld (FILE *, const_cil_stmt);
+static void emit_stsfld (FILE *, const_cil_stmt);
+static void emit_switch (FILE *, const_cil_stmt);
+static void emit_string_custom_attr (FILE *, const char *);
+static bool emit_builtin_call (FILE *, const_cil_stmt);
+static void emit_call (FILE *, const_cil_stmt);
+static void emit_cil_stmt (FILE *, const_cil_stmt);
+static void emit_start_function (FILE *);
+static void rename_var (tree, const char *, unsigned long);
+static void emit_static_vars (FILE *);
+static int var_uses_compare (const void *, const void *);
+static void emit_local_vars (FILE *);
+static void emit_function_header (FILE *);
+static void emit_cil_bb (FILE *, basic_block);
+static void emit_cil_1 (FILE *);
+static unsigned int emit_cil (void);
+
+
+static void emit_cil_vcg_1 (FILE *);
+static bool emit_cil_vcg_gate (void);
+static unsigned int emit_cil_vcg (void);
+
+/******************************************************************************
+ * CIL assembly emission functions *
+ ******************************************************************************/
+
+void
+emit_cil_init (void)
+{
+ FILE *file = asm_out_file;
+
+ gcc_assert (!init);
+
+ if (TARGET_GCC4NET_LINKER)
+ {
+ fputs (".assembly extern mscorlib {}\n"
+ ".assembly extern gcc4net {}\n"
+ ".assembly extern ExternalAssembly {}\n", file);
+ fprintf (file, ".assembly '%s' {\n", aux_base_name);
+ fputs ("\t.custom instance "
+ "void [gcc4net]gcc4net.C_Attributes.CObjectFile::.ctor() "
+ "= (01 00 00 00)\n"
+ "}\n", file);
+ fprintf (file, ".module '%s'\n", aux_base_name);
+ }
+ else if (TARGET_OPENSYSTEMC)
+ {
+ fputs (".assembly extern gcc4net {}\n"
+ ".module '<Module>'\n"
+ ".custom instance "
+ "void ['OpenSystem.C']'OpenSystem.C'.ModuleAttribute::.ctor() "
+ "= (01 00 00 00)\n", file);
+ }
+
+ init = true;
+}
+
+void
+emit_cil_fini (void)
+{
+ gcc_assert (init);
+
+ create_init_method ();
+ emit_referenced_strings (asm_out_file);
+ emit_referenced_types (asm_out_file);
+ emit_referenced_pinvokes (asm_out_file);
+}
+
+void
+emit_cil_decl (FILE *file, tree decl)
+{
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || TREE_PUBLIC (decl)))
+ {
+ tree init = DECL_INITIAL (decl);
+
+ fprintf (file, "\n.field %s static ",
+ TREE_PUBLIC (decl) ? "public" : "private");
+ dump_type (file, TREE_TYPE (decl), true, false);
+ fprintf (file, " ");
+ dump_decl_name (file, decl);
+ fprintf (file, "\n");
+
+ if (init && init != error_mark_node)
+ record_ctor (decl);
+
+ TREE_ASM_WRITTEN (decl) = 1;
+ }
+}
+
+/* Compute and return the maximum stack depth of the current function. */
+
+static unsigned int
+compute_max_stack (void)
+{
+ unsigned int *depths;
+ unsigned int max_depth = 0;
+ unsigned int depth;
+ basic_block bb;
+ edge e;
+ edge_iterator ei;
+
+ depths = XCNEWVEC (unsigned int, last_basic_block);
+
+ FOR_EACH_BB (bb)
+ {
+ depth = cil_seq_stack_depth (cil_bb_seq (bb), depths[bb->index], true);
+ max_depth = (depth > max_depth) ? depth : max_depth;
+ depth = cil_seq_stack_depth (cil_bb_seq (bb), depths[bb->index], false);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ depths[e->dest->index] = depth;
+ }
+ }
+
+ XDELETEVEC (depths);
+
+ return max_depth;
+}
+
+/* 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->cusattr_string = 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, "cil_strattr") == 0)
+ attrs->cusattr_string = 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);
+ }
+}
+
+/* Dump the name of a _DECL node pointed by NODE into the file FILE. */
+
+static void
+dump_decl_name (FILE *file, tree node)
+{
+ gcc_assert (DECL_P (node));
+ fprintf (file, "'");
+
+ mark_decl_referenced (node);
+
+ if (DECL_ASSEMBLER_NAME_SET_P (node))
+ {
+ const char *tname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node));
+
+ if (tname[0] == '*')
+ fprintf (file, tname + 1);
+ else
+ fprintf (file, tname);
+ }
+ else if (DECL_NAME (node))
+ fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node)));
+ else
+ fprintf (file, "?UNNAMED%d", DECL_UID (node));
+
+ fprintf (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%u'", get_string_cst_id (node));
+}
+
+/* Dump the name of a label pointed by NODE into the file FILE. */
+
+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))
+ fprintf (file, "_%s", 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 name = TYPE_NAME (t);
+ const char *str;
+ size_t i;
+ bool builtin_p = cil_builtin_type_p (t);
+
+ 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 (DECL_P (name) || TREE_CODE (name) == IDENTIFIER_NODE);
+
+ if (builtin_p)
+ fprintf (file, "[gcc4net]gcc4net.");
+
+ fputs ("'", file);
+
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ str = IDENTIFIER_POINTER (name);
+ else if (DECL_NAME (name))
+ str = IDENTIFIER_POINTER (DECL_NAME (name));
+ else
+ str = NULL;
+
+ if (str)
+ {
+ /* Dots inside the names of non builtin types are turned into '?'
+ characters. */
+ for (i = 0; i < strlen (str); i++)
+ {
+ if (str[i] == '.' && !builtin_p)
+ fprintf (file, "?");
+ else
+ fprintf (file, "%c", str[i]);
+ }
+ }
+ else
+ fprintf (file, "?UNNAMED%d", DECL_UID (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 *file, 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));
+
+ if (ref)
+ mark_referenced_type (fun_type);
+
+ args_type = TYPE_ARG_TYPES (fun_type);
+
+ if (args_type == NULL)
+ {
+ warning (OPT_Wcil_missing_prototypes,
+ "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;
+ }
+ }
+
+ fprintf (file, "%s", varargs ? "vararg " : "");
+ dump_type (file, TREE_TYPE (fun_type), ref, false);
+ fprintf (file, " ");
+
+ if (fun)
+ {
+ struct fnct_attr attrs;
+
+ decode_function_attrs (fun, &attrs);
+
+ if (attrs.assembly_name)
+ fprintf (file, "[%s]", attrs.assembly_name);
+ else if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (fun) && TREE_PUBLIC (fun))
+ {
+ fputs ("[ExternalAssembly]", file);
+ if (!attrs.cil_name)
+ fputs ("ExternalAssembly::", file);
+ }
+
+ if (attrs.cil_name)
+ fprintf (file, "%s", attrs.cil_name);
+ else
+ dump_decl_name (file, fun);
+ }
+
+ fprintf (file, "%s(", name ? name : "");
+
+ while (args_type != last_arg_type)
+ {
+ dump_type (file, TREE_VALUE (args_type), ref, true);
+ args_type = TREE_CHAIN (args_type);
+
+ if (args_type != last_arg_type)
+ fprintf (file, ", ");
+ }
+
+ fprintf (file, ")");
+}
+
+/* Dump vector type TYPE.
+
+ FULL tells whether the type must be qualified with the 'valuetype' keyword,
+ assembly and namespace.
+ TYPE must be a type node of type VECTOR_TYPE. */
+
+static void
+dump_vector_type (FILE *file, tree node, bool full)
+{
+ tree innertype = TYPE_MAIN_VARIANT (TREE_TYPE (node));
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (innertype), 1);
+
+ gcc_assert (TREE_CODE (node) == VECTOR_TYPE);
+
+ if (full)
+ fprintf (file, "valuetype [gcc4net]gcc4net.");
+
+ fprintf (file, "V"HOST_WIDE_INT_PRINT_UNSIGNED, TYPE_VECTOR_SUBPARTS (node));
+
+ if (TREE_CODE (innertype) == INTEGER_TYPE)
+ {
+ switch (size)
+ {
+ case 8: fprintf (file, "QI"); break;
+ case 16: fprintf (file, "HI"); break;
+ case 32: fprintf (file, "SI"); break;
+ case 64: fprintf (file, "DI"); break;
+ default:
+ internal_error ("Unsupported integer size"
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ else if (TREE_CODE (innertype) == REAL_TYPE)
+ {
+ if (size == 32)
+ fprintf (file, "SF");
+ else if (size == 64)
+ fprintf (file, "DF");
+ else
+ {
+ internal_error ("Unsupported floating point size"
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ else
+ gcc_unreachable ();
+}
+
+static void
+dump_complex_type (FILE *file, tree node, bool full)
+{
+ tree elem_type = TYPE_MAIN_VARIANT (TREE_TYPE (node));
+ const char *name = NULL;
+ const char *prefix = full ? "valuetype [gcc4net]gcc4net." : "";
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (elem_type), 1);
+ bool unsignedp;
+
+ gcc_assert (TREE_CODE (node) == COMPLEX_TYPE);
+
+ if (INTEGRAL_TYPE_P (elem_type))
+ {
+ unsignedp = TYPE_UNSIGNED (elem_type);
+
+ switch (size)
+ {
+ case 8: name = unsignedp ? "uchar" : "char"; break;
+ case 16: name = unsignedp ? "ushort" : "short"; break;
+ case 32: name = unsignedp ? "uint" : "int"; break;
+ case 64: name = unsignedp ? "ulong" : "long"; break;
+ default:
+ internal_error ("Unsupported integer size"
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ else if (SCALAR_FLOAT_TYPE_P (elem_type))
+ {
+ if (size == 32)
+ name = "float";
+ else if (size == 64)
+ name = "double";
+ else
+ {
+ internal_error ("Unsupported floating point size"
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+
+ fprintf (file, "%scomplex_%s", prefix, name);
+}
+
+static void
+emit_enum_decl (FILE *file, tree t)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (t), 1);
+ char tmp_str[8] = "int";
+ char *base_type_str = tmp_str;
+ tree tmp;
+
+ gcc_assert (t != NULL_TREE && TREE_CODE (t) == ENUMERAL_TYPE);
+
+ fprintf (file, "\n.class ");
+
+ if (TYPE_FILE_SCOPE_P (t))
+ fprintf (file, "public ");
+ else
+ fprintf (file, "private ");
+
+ fprintf (file, "sealed serializable ansi ");
+ dump_valuetype_name (file, t);
+ fprintf (file,
+ " extends ['mscorlib']System.Enum\n"
+ "{\n");
+ snprintf (base_type_str + 3, 5, HOST_WIDE_INT_PRINT_UNSIGNED, size);
+ fprintf (file, "\t.field public specialname rtspecialname %s%s 'value__'\n",
+ !TYPE_UNSIGNED (t) ? "unsigned " : "",
+ base_type_str);
+
+ for (tmp = TYPE_VALUES (t); tmp; tmp = TREE_CHAIN (tmp))
+ {
+ fprintf (file, "\t.field public static literal ");
+ dump_type (file, t, false, false);
+ gcc_assert (TREE_CODE (TREE_PURPOSE (tmp)) == IDENTIFIER_NODE);
+ fprintf (file, " '%s' = %s(", IDENTIFIER_POINTER (TREE_PURPOSE (tmp)),
+ base_type_str);
+ dump_double_int (file, TREE_INT_CST (TREE_VALUE (tmp)), false);
+ fprintf (file, ")\n");
+ }
+
+ fprintf (file, "}\n");
+}
+
+static void
+emit_array_decl (FILE *file, tree t)
+{
+ fprintf (file, "\n.class %s explicit sealed serializable ansi ",
+ TYPE_FILE_SCOPE_P (t) ? "public" : "private");
+ dump_valuetype_name (file, t);
+ fprintf (file,
+ " extends ['mscorlib']System.ValueType\n"
+ "{\n"
+ "\t.custom instance "
+ "void [gcc4net]gcc4net.C_Attributes.ArrayType::.ctor() "
+ "= (01 00 00 00)\n"
+ "\t.size " HOST_WIDE_INT_PRINT_DEC "\n"
+ "\t.field [0] public specialname ",
+ tree_low_cst (TYPE_SIZE_UNIT (t), 1));
+ dump_type (file, TREE_TYPE (t), false, false);
+ fprintf (file,
+ " 'elem__'\n"
+ "}\n");
+}
+
+static void
+emit_incomplete_decl (FILE *file, tree t)
+{
+ if (t == NULL_TREE || t == error_mark_node)
+ return;
+
+ if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
+ return;
+
+ gcc_assert (file != 0);
+
+ gcc_assert (TYPE_MAIN_VARIANT (t) == t);
+ gcc_assert (TYPE_NAME (t));
+ gcc_assert (!COMPLETE_TYPE_P (t));
+
+ fputs ("\n.class public sealed ", file);
+ dump_valuetype_name (file, t);
+ fputs (" extends ['mscorlib']System.ValueType\n"
+ "{\n"
+ "\t.custom instance "
+ "void [gcc4net]gcc4net.C_Attributes.IncompleteType::.ctor() "
+ "= (01 00 00 00)\n"
+ "}\n", file);
+}
+
+static void
+emit_struct_union_decl (FILE *file, tree t)
+{
+ tree tmp;
+
+ fprintf (file, "\n.class %s explicit sealed serializable ansi ",
+ TYPE_FILE_SCOPE_P (t) ? "public" : "private");
+ dump_valuetype_name (file, t);
+ fprintf (file,
+ " extends ['mscorlib']System.ValueType\n"
+ "{\n"
+ "\t.size " HOST_WIDE_INT_PRINT_DEC "\n",
+ tree_low_cst (TYPE_SIZE_UNIT (t), 1));
+
+ for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))
+ {
+ if (DECL_NAME (tmp) == NULL_TREE && DECL_BIT_FIELD (tmp))
+ {
+ /* Skip unnamed bitfields */
+ }
+ else
+ {
+ tree type;
+ unsigned HOST_WIDE_INT bit_offset;
+ unsigned HOST_WIDE_INT byte_offset;
+ unsigned HOST_WIDE_INT offset;
+
+ bit_offset = tree_low_cst (DECL_FIELD_BIT_OFFSET (tmp), 1);
+ byte_offset = tree_low_cst (DECL_FIELD_OFFSET (tmp), 1);
+
+ if (DECL_BIT_FIELD (tmp))
+ {
+ unsigned HOST_WIDE_INT 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);
+
+ size = tree_low_cst (TYPE_SIZE (type), 1);
+ offset = byte_offset + (bit_offset & ~(size - 1)) / 8;
+ }
+ else
+ {
+ type = TREE_TYPE (tmp);
+ gcc_assert (bit_offset % 8 == 0);
+ offset = byte_offset + bit_offset / 8;
+ }
+
+ fprintf (file, "\t.field ["HOST_WIDE_INT_PRINT_UNSIGNED"] public ",
+ offset);
+ dump_type (file, type, false, false);
+ fprintf (file, " ");
+ dump_decl_name (file, tmp);
+ fprintf (file, "\n");
+ }
+ }
+
+ fprintf (file, "}\n");
+}
+
+static void
+emit_valuetype_decl (FILE *file, tree t)
+{
+ if (t == NULL_TREE || t == error_mark_node)
+ return;
+
+ if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
+ return;
+
+ gcc_assert (file != 0);
+ gcc_assert (TYPE_MAIN_VARIANT (t) == t);
+ gcc_assert (TYPE_NAME (t));
+
+ if (TREE_CODE (t) == ENUMERAL_TYPE)
+ emit_enum_decl (file, t);
+ else if (TREE_CODE (t) == ARRAY_TYPE)
+ emit_array_decl (file, t);
+ else /* struct or union */
+ emit_struct_union_decl (file, t);
+}
+
+/* Dump type TYPE.
+ REF tells whether the function type (and the types of the return value
+ and of the incoming parameters) have to be marked as referenced.
+ QUALIF tells whether to emit C qualifiers (const, restrict, volatile)
+ NODE must be a type node. */
+
+static void
+dump_type (FILE *file, tree type, bool ref, bool qualif)
+{
+ unsigned HOST_WIDE_INT size;
+
+ if (type == NULL_TREE || type == error_mark_node)
+ return;
+
+ if (TYPE_MAIN_VARIANT (type) == cil32_arg_iterator_type)
+ {
+ fprintf (file, "valuetype [mscorlib]System.ArgIterator");
+ return;
+ }
+
+ switch (TREE_CODE (type))
+ {
+ /* Incomplete and variable-length arrays are pointers and
+ they must be dealt with as such. */
+ case ARRAY_TYPE:
+ if (!TYPE_DOMAIN (type) || ARRAY_TYPE_VARLENGTH (type))
+ goto pointer;
+
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ /* Reference the type if told to do so */
+ if (ref)
+ mark_referenced_type (TYPE_MAIN_VARIANT (type));
+
+ /* Print the name of the structure. */
+ fprintf (file, "valuetype ");
+ dump_valuetype_name (file, TYPE_MAIN_VARIANT (type));
+ break;
+
+ case VOID_TYPE:
+ fprintf (file, "void");
+ break;
+
+ case INTEGER_TYPE:
+ fprintf (file, "%s", TYPE_UNSIGNED (type) ? "unsigned " : "");
+ size = tree_low_cst (TYPE_SIZE (type), 1);
+
+ switch (size)
+ {
+ case 8: fprintf (file, "int8"); break;
+ case 16: fprintf (file, "int16"); break;
+ case 32: fprintf (file, "int32"); break;
+ case 64: fprintf (file, "int64"); break;
+ default:
+ internal_error ("Unsupported integer size "
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ break;
+
+ case REAL_TYPE:
+ size = tree_low_cst (TYPE_SIZE (type), 1);
+
+ gcc_assert (size == 32 || size == 64);
+ fprintf (file, "float" HOST_WIDE_INT_PRINT_UNSIGNED, size);
+ break;
+
+ case BOOLEAN_TYPE:
+ fprintf (file, "int8");
+ break;
+
+pointer:
+ case POINTER_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ {
+ fprintf (file, "method ");
+ dump_fun_type (file, TREE_TYPE (type), NULL, " * ", ref);
+ }
+ else
+ {
+ dump_type (file, TREE_TYPE (type), ref, qualif);
+ fprintf (file, " *");
+ }
+ break;
+
+ case FUNCTION_TYPE:
+/* FIXME?
+ dump_fun_type (file, node, NULL, NULL, ref); */
+ gcc_unreachable ();
+ break;
+
+ case VECTOR_TYPE:
+ dump_vector_type (file, type, true);
+ break;
+
+ case COMPLEX_TYPE:
+ dump_complex_type (file, type, true);
+ break;
+
+ case REFERENCE_TYPE:
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (qualif)
+ {
+ unsigned int quals = TYPE_QUALS (type);
+
+ if (quals & TYPE_QUAL_CONST)
+ fprintf (file, " modopt([gcc4net]gcc4net.CQualifiers.IsConst)");
+ if (quals & TYPE_QUAL_RESTRICT)
+ fprintf (file, " modopt([gcc4net]gcc4net.CQualifiers.IsRestrict)");
+#if 0
+ /* FIXME? */
+ if (quals & TYPE_QUAL_VOLATILE)
+ fprintf (file, " modopt([gcc4net]gcc4net.CQualifiers.IsVolatile)");
+#endif
+ }
+}
+
+static void
+dump_string_type (FILE *file, tree node)
+{
+ tree domain;
+ tree min;
+ tree max;
+
+ gcc_assert(TREE_CODE (node) == ARRAY_TYPE
+ && TYPE_DOMAIN (node)
+ && ! ARRAY_TYPE_VARLENGTH (node));
+
+ domain = TYPE_DOMAIN (node);
+ min = TYPE_MIN_VALUE (domain);
+ max = TYPE_MAX_VALUE (domain);
+ gcc_assert(integer_zerop (min));
+ fprintf (file, "valuetype '?string_type?"HOST_WIDE_INT_PRINT_UNSIGNED"'",
+ tree_low_cst (max, 1) + 1);
+}
+
+/* Print a string declaration pointed by T into the file pointed by FILE. */
+
+static void
+dump_string_decl (FILE *file, tree t)
+{
+ const char *str;
+ unsigned int len, len_type, i;
+
+ str = TREE_STRING_POINTER (t);
+ len = TREE_STRING_LENGTH (t);
+ len_type = tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))), 1) + 1;
+
+ /* Emit the string in readable form as a comment. */
+ fprintf (file, "\n// string: \"");
+
+ for (i = 0; i < len - 1; i++)
+ {
+ switch (str[i])
+ {
+ case '\n': fprintf (file, "\\n"); break;
+ case '"': fprintf (file, "\""); break;
+ default: fputc (str[i], file); break;
+ }
+ }
+
+ fprintf (file,
+ "\"\n"
+ ".data 'DataStr%u' = bytearray(", get_string_cst_id (t));
+
+ for (i = 0; i < len; i++)
+ fprintf (file, "%02x ", (unsigned char) str[i]);
+
+ for (; i < len_type; i++)
+ fprintf (file, "00 ");
+
+ fprintf (file,
+ ")\n"
+ ".field private static ");
+ dump_string_type (file, TREE_TYPE (t));
+ fprintf (file, " ");
+ dump_string_name (file, t);
+ fprintf (file, " at 'DataStr%u'\n", get_string_cst_id (t));
+}
+
+/* Dump the type def of type NODE, promoted following C conventions
+ for var args.
+ NODE must be a type node.
+ returns true if the dumped type is a pointer */
+
+static bool
+dump_type_promoted_type_def (FILE *file, tree node)
+{
+ bool result = false;
+ unsigned HOST_WIDE_INT size;
+
+ if (node == NULL_TREE || node == error_mark_node)
+ return false;
+
+ switch (TREE_CODE (node))
+ {
+ /* Incomplete and variable-length arrays are pointers and
+ they must be dealt with as such. */
+ case ARRAY_TYPE:
+ if (!TYPE_DOMAIN (node) || ARRAY_TYPE_VARLENGTH (node))
+ goto pointer;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ node = TYPE_MAIN_VARIANT (node);
+
+ /* Reference the type if told to do so */
+ mark_referenced_type (node);
+
+ /* Print the name of the structure. */
+ fprintf (file, "valuetype ");
+ dump_valuetype_name (file, node);
+ break;
+
+ case COMPLEX_TYPE:
+ dump_complex_type (file, node, true);
+ break;
+
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ size = tree_low_cst (TYPE_SIZE (node), 1);
+
+ if (size <= 32)
+ fprintf (file, "class [mscorlib]System.UInt32");
+ else if (size <= 64)
+ fprintf (file, "class [mscorlib]System.UInt64");
+ else
+ {
+ internal_error ("Unsupported integer size"
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ break;
+
+ case REAL_TYPE:
+ fprintf (file, "class [mscorlib]System.Double");
+ break;
+
+ pointer:
+ case POINTER_TYPE:
+ /* cil32 is a 32bit machine, in case we support 64bit model
+ * changes are needed
+ */
+ fprintf (file, "class [mscorlib]System.UInt32");
+ result = true;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return result;
+}
+
+/* Emit all the strings referenced in this compilation unit. */
+
+static void
+emit_referenced_strings (FILE *file)
+{
+ htab_iterator hti;
+ str_ref ref;
+ tree str;
+ unsigned int str_size;
+ ebitmap used_stringtypes;
+ ebitmap_iterator ebi;
+
+ used_stringtypes = ebitmap_alloc (1);
+
+ FOR_EACH_HTAB_ELEMENT (referenced_strings_htab (), ref, str_ref, hti)
+ {
+ str = ref->cst;
+ str_size = tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (str))),
+ 1) + 1;
+ dump_string_decl (file, str);
+ ebitmap_set_bit (used_stringtypes, str_size);
+ }
+
+ EXECUTE_IF_SET_IN_EBITMAP(used_stringtypes, 0, str_size, ebi)
+ {
+ fprintf (file,
+ "\n.class public explicit sealed serializable ansi "
+ "'?string_type?%u'", str_size);
+ fprintf (file,
+ " extends ['mscorlib']System.ValueType\n"
+ "{\n"
+ "\t.custom instance "
+ "void [gcc4net]gcc4net.C_Attributes.ConstStringType::.ctor() "
+ "= (01 00 00 00)\n"
+ "\t.size %u\n", str_size);
+ fprintf (file,
+ "\t.field [0] public specialname int8 'elem__'\n"
+ "}\n");
+ }
+
+ ebitmap_free (used_stringtypes);
+}
+
+/* Emit the valuetypes referenced by the current function. */
+
+static void
+emit_referenced_types (FILE *file)
+{
+ /* 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. */
+
+ htab_iterator hti;
+ tree type;
+ struct pointer_set_t *emitted_types = pointer_set_create ();
+ struct pointer_set_t *incomplete_types = pointer_set_create ();
+
+ FOR_EACH_HTAB_ELEMENT (referenced_types_htab (), type, tree, hti)
+ {
+ if (COMPLETE_TYPE_P (type))
+ {
+ tree type_name = TYPE_NAME (type);
+
+ gcc_assert (DECL_P (type_name)
+ || TREE_CODE (type_name) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (type_name) != IDENTIFIER_NODE)
+ type_name = DECL_NAME (type_name);
+
+ if (!pointer_set_contains (emitted_types, type_name))
+ {
+ emit_valuetype_decl (file, type);
+ pointer_set_insert (emitted_types, type_name);
+ }
+ }
+ else if (TARGET_GCC4NET_LINKER)
+ pointer_set_insert (incomplete_types, type);
+ }
+
+ /* emit incomplete types */
+ if (TARGET_GCC4NET_LINKER)
+ {
+ struct pointer_set_iter_t it = pointer_set_begin (incomplete_types);
+
+ while (!POINTER_SET_ITER_IS_END (it))
+ {
+ tree type = (tree)POINTER_SET_ITER_ELEM (it);
+
+ tree type_name = TYPE_NAME (type);
+ gcc_assert (DECL_P (type_name)
+ || TREE_CODE (type_name) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (type_name) != IDENTIFIER_NODE)
+ type_name = DECL_NAME (type_name);
+
+ if (!pointer_set_contains (emitted_types, type_name))
+ {
+ emit_incomplete_decl (file, type);
+ pointer_set_insert (emitted_types, type_name);
+ }
+
+ it = pointer_set_next (incomplete_types, it);
+ }
+ }
+
+ pointer_set_destroy (incomplete_types);
+ pointer_set_destroy (emitted_types);
+}
+
+static void
+emit_pinvoke_function (FILE *file, tree fun)
+{
+ tree fun_type = TREE_TYPE (fun);
+ struct fnct_attr attributes;
+
+ decode_function_attrs (fun, &attributes);
+
+ fprintf (file, ".method %s static pinvokeimpl(\"%s\"",
+ TREE_PUBLIC (fun) ? "public" : "private",
+ attributes.pinvoke_assembly);
+
+ if (attributes.pinvoke_fname)
+ fprintf (file, " as \"%s\"", attributes.pinvoke_fname);
+
+ fprintf (file, ") ");
+ DECL_EXTERNAL (fun) = 0;
+ dump_fun_type (file, fun_type, fun, NULL, false);
+ fprintf (file, " cil managed {}\n");
+}
+
+/* Emit the PINVOKES referenced in this compilation unit. */
+
+static void
+emit_referenced_pinvokes (FILE *file)
+{
+ htab_iterator hti;
+ tree pinvoke;
+
+ FOR_EACH_HTAB_ELEMENT (pinvokes_htab (), pinvoke, tree, hti)
+ {
+ emit_pinvoke_function (file, pinvoke);
+ }
+}
+
+/* Emit an indirect access. */
+
+static void
+emit_prefixes (FILE *file, const_cil_stmt stmt)
+{
+ enum cil_opcode opcode = cil_opcode (stmt);
+
+ if ((opcode == CIL_CALL) || (opcode == CIL_CALLI))
+ {
+ if (cil_prefix_tail (stmt))
+ fprintf (file, "\n\ttail.");
+ }
+ else if ((opcode == CIL_CPBLK) || (opcode == CIL_INITBLK)
+ || ((opcode >= CIL_LDIND_I1) && (opcode <= CIL_LDIND_I))
+ || ((opcode >= CIL_STIND_I1) && (opcode <= CIL_STIND_I))
+ || (opcode == CIL_LDFLD) || (opcode == CIL_STFLD))
+ {
+ if (cil_prefix_unaligned (stmt) != 0)
+ fprintf (file, "\n\tunaligned.%d", cil_prefix_unaligned (stmt));
+ }
+ else if ((opcode == CIL_CPBLK) || (opcode == CIL_INITBLK)
+ || ((opcode >= CIL_LDIND_I1) && (opcode <= CIL_LDIND_I))
+ || ((opcode >= CIL_STIND_I1) && (opcode <= CIL_STIND_I))
+ || (opcode == CIL_LDFLD) || (opcode == CIL_STFLD)
+ || (opcode == CIL_LDSFLD) || (opcode == CIL_STSFLD))
+ {
+ if (cil_prefix_volatile (stmt))
+ fprintf (file, "\n\tvolatile.");
+ }
+}
+
+/* Emit a CIL LDSFLD instruction. */
+
+static void
+emit_ldsfld (FILE *file, const_cil_stmt stmt)
+{
+ tree arg = cil_field (stmt);
+
+ fprintf (file, "\n\tldsfld\t");
+ dump_type (file, TREE_TYPE (arg), true, false);
+ fprintf (file, " ");
+
+ if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (arg) && TREE_PUBLIC (arg))
+ fprintf (file, "[ExternalAssembly]ExternalAssembly::");
+
+ dump_decl_name (file, arg);
+}
+
+/* Emit a CIL LDSFLDA instruction. This instruction is used for obtaining the
+ addresses of global variables but also string constants. */
+
+static void
+emit_ldsflda (FILE *file, const_cil_stmt stmt)
+{
+ tree field = cil_field (stmt);
+
+ fprintf (file, "\n\tldsflda\t");
+
+ if (TREE_CODE (field) == STRING_CST)
+ {
+ dump_string_type (file, TREE_TYPE (field));
+ fprintf (file, " ");
+ dump_string_name (file, field);
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (field) == VAR_DECL);
+
+ if (COMPLETE_TYPE_P (TREE_TYPE (field)))
+ dump_type (file, TREE_TYPE (field), true, false);
+ else
+ fprintf (file, "native int");
+
+ fprintf (file, " ");
+
+ if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (field) && TREE_PUBLIC (field))
+ fprintf (file, "[ExternalAssembly]ExternalAssembly::");
+
+ dump_decl_name (file, field);
+ }
+}
+
+/* Emit a CIL LDFLD instruction. */
+
+static void
+emit_ldfld (FILE *file, const_cil_stmt stmt)
+{
+ tree field = cil_field (stmt);
+ tree obj_type = DECL_FIELD_CONTEXT (field);
+
+ mark_referenced_type (obj_type);
+ fprintf (file, "\n\tldfld\t");
+ dump_type (file, TREE_TYPE (field), true, false);
+ fprintf (file, " ");
+ mark_referenced_type (obj_type);
+ dump_valuetype_name (file, obj_type);
+ fprintf (file, "::");
+ dump_decl_name (file, field);
+}
+
+/* Emit a CIL LDFLDA instruction. */
+
+static void
+emit_ldflda (FILE *file, const_cil_stmt stmt)
+{
+ tree field = cil_field (stmt);
+ tree obj_type = DECL_FIELD_CONTEXT (field);
+
+ mark_referenced_type (obj_type);
+ fprintf (file, "\n\tldflda\t");
+ dump_type (file, TREE_TYPE (field), true, false);
+ fprintf (file, " ");
+ dump_valuetype_name (file, obj_type);
+ fprintf (file, "::");
+ dump_decl_name (file, field);
+}
+
+/* Emit a CIL STFLD instruction. */
+
+static void
+emit_stfld (FILE *file, const_cil_stmt stmt)
+{
+ tree field = cil_field (stmt);
+ tree obj_type = DECL_FIELD_CONTEXT (field);
+
+ mark_referenced_type (obj_type);
+ fprintf (file, "\n\tstfld\t");
+ dump_type (file, TREE_TYPE (field), true, false);
+ fprintf (file, " ");
+ dump_valuetype_name (file, obj_type);
+ fprintf (file, "::");
+ dump_decl_name (file, field);
+}
+
+/* Emit a CIL STSFLD instruction. */
+
+static void
+emit_stsfld (FILE *file, const_cil_stmt stmt)
+{
+ tree arg = cil_field (stmt);
+
+ fprintf (file, "\n\tstsfld\t");
+ dump_type (file, TREE_TYPE (arg), true, false);
+ fprintf (file, " ");
+
+ if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (arg) && TREE_PUBLIC (arg))
+ fprintf (file, "[ExternalAssembly]ExternalAssembly::");
+
+ dump_decl_name (file, arg);
+}
+
+/* Emit a SWITCH instruction. */
+
+static void
+emit_switch (FILE *file, const_cil_stmt stmt)
+{
+ unsigned HOST_WIDE_INT i, range;
+ unsigned int n_cases = cil_switch_ncases (stmt);
+ HOST_WIDE_INT lo, hi, offset, j;
+ tree *labels;
+
+ if (n_cases > 1)
+ {
+ lo = cil_switch_case_low (stmt, 0);
+ hi = cil_switch_case_high (stmt, n_cases - 2);
+ range = hi - lo + 1;
+ labels = XCNEWVEC (tree, range);
+ offset = lo;
+ }
+ else
+ {
+ /* If the switch contains only one case, it's the default label. If the
+ default label is artificial then this is an empty switch we created
+ for a computed GOTO expression. */
+ if (DECL_ARTIFICIAL (CASE_LABEL (cil_switch_default (stmt))))
+ range = 0;
+ else
+ range = 1;
+
+ labels = XCNEWVEC (tree, 1);
+ offset = 0;
+ }
+
+ /* Flatten the cases filling an array of adjacent cases with their
+ associated labels taken from the switch. */
+
+ for (i = 0; i < n_cases - 1; i++)
+ {
+ lo = cil_switch_case_low (stmt, i);
+ hi = cil_switch_case_high (stmt, i);
+
+ for (j = lo; j <= hi; j++)
+ labels[j - offset] = cil_switch_case_label (stmt, i);
+ }
+
+ /* Fill the empty slots in the array with the default case label. */
+
+ for (i = 0; i < range; i++)
+ {
+ if (labels[i] == NULL_TREE)
+ labels[i] = CASE_LABEL (cil_switch_default (stmt));
+ }
+
+ fprintf (file, "\n\tswitch\t(");
+
+ for (i = 0 ; i < range; i++)
+ {
+ dump_label_name (file, labels[i]);
+
+ if (i < range - 1)
+ fprintf (file, ", ");
+ }
+
+ fprintf (file, ")");
+
+ XDELETEVEC (labels);
+}
+
+/* The attribute string must be less than 127 characters and contain only
+ 7-bit ASCII chars. No checks though. */
+
+static void
+emit_string_custom_attr (FILE *file, const char *parameter)
+{
+ size_t i;
+ size_t len = strlen (parameter);
+
+ gcc_assert (len <= 127);
+
+ fprintf (file, "\t.custom instance void [mscorlib]System.String::.ctor(int8 *) = (01 00 %02x ", len);
+
+ for (i = 0; i < len; i++)
+ fprintf (file, "%02x ", parameter[i]);
+
+ fprintf (file, "00 00)\n");
+}
+
+/* Emit the assembler representing a built in call. Return true if the built in
+ was handled, false if it must be emitted like a regular function call. */
+
+static bool
+emit_builtin_call (FILE *file, const_cil_stmt call)
+{
+ tree fdecl = cil_call_fdecl (call);
+
+ if (DECL_BUILT_IN_CLASS (fdecl) == BUILT_IN_MD)
+ {
+ switch (DECL_FUNCTION_CODE (fdecl))
+ {
+ case CIL32_BUILT_IN_VA_START:
+ fprintf (file,
+ "\n\targlist"
+ "\n\tcall\tinstance void "
+ "[mscorlib]System.ArgIterator::.ctor(valuetype "
+ "[mscorlib]System.RuntimeArgumentHandle)");
+ return true;
+
+ case CIL32_BUILT_IN_VA_END:
+ fprintf (file, "\n\tcall\tinstance void [mscorlib]System.ArgIterator::End()");
+ return true;
+
+ case CIL32_BUILT_IN_VA_COPY:
+ fprintf (file, "\n\tcpobj\t[mscorlib]System.ArgIterator");
+ return true;
+
+ case CIL32_BUILT_IN_VA_INIT:
+ fprintf (file, "\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator");
+ return true;
+
+ case CIL32_BUILT_IN_VA_ARG:
+ {
+ tree type = TREE_TYPE (TREE_TYPE (cil_call_dummy_arg (call)));
+
+ fprintf (file,
+ "\n\tcall\tinstance typedref [mscorlib]System.ArgIterator::GetNextArg()"
+ "\n\trefanyval ");
+
+ if (dump_type_promoted_type_def (file, type))
+ fprintf (file, "\n\tconv.i");
+ }
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ else
+ {
+ switch (DECL_FUNCTION_CODE (fdecl))
+ {
+ case BUILT_IN_VA_START:
+ case BUILT_IN_VA_END:
+ case BUILT_IN_VA_COPY:
+ internal_error ("va_* builtins shouldn't be present\n");
+ break;
+
+ case BUILT_IN_TRAP:
+ fprintf (file, "\n\tcall\tvoid 'abort' ()");
+ return true;
+
+ default:
+ /* Go Ahead as a normal function call */
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/* Emit the assembler representing the CALL instruction into the file pointed
+ by STREAM. */
+
+static void
+emit_call (FILE *file, const_cil_stmt call)
+{
+ bool direct = cil_opcode (call) == CIL_CALLI ? false : true;
+ tree ftype = cil_call_ftype (call);
+ tree fdecl;
+ size_t nargs_base;
+ size_t nargs;
+ size_t i;
+
+ switch (cil_opcode (call))
+ {
+ case CIL_CALL:
+ if (DECL_BUILT_IN (cil_call_fdecl (call)))
+ if (emit_builtin_call (file, call))
+ return;
+
+ fprintf (file, "\n\tcall\t");
+ break;
+
+ case CIL_CALLI:
+ fprintf (file, "\n\tcalli\t");
+ break;
+
+ case CIL_JMP:
+ fprintf (file, "\n\tjmp\t");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ fprintf (file, "%s", cil_call_vararg_p (call) ? "vararg " : "");
+ /* Dump the return type. */
+ dump_type (file, TREE_TYPE (ftype), true, false);
+
+ if (direct)
+ {
+ struct fnct_attr attrs;
+
+ fdecl = cil_call_fdecl (call);
+ decode_function_attrs (fdecl, &attrs);
+
+ fprintf (file, " ");
+
+ if (DECL_BUILT_IN (fdecl))
+ {
+ if (DECL_BUILT_IN_CLASS (fdecl) == BUILT_IN_MD)
+ fprintf (file, "%s", IDENTIFIER_POINTER (DECL_NAME (fdecl)));
+ else
+ dump_decl_name (file, fdecl);
+ }
+ else
+ {
+ if (attrs.assembly_name)
+ fprintf (file, "[%s]", attrs.assembly_name);
+ else if (TARGET_GCC4NET_LINKER
+ && DECL_EXTERNAL (fdecl)
+ && TREE_PUBLIC (fdecl))
+ {
+ fputs ("[ExternalAssembly]", file);
+ if (!attrs.cil_name)
+ fputs ("ExternalAssembly::", file);
+ }
+
+ if (attrs.cil_name)
+ fprintf (file, "%s", attrs.cil_name);
+ else
+ dump_decl_name (file, fdecl);
+ }
+ }
+
+ fprintf (file, " (");
+ nargs_base = cil_call_nargs_base (call);
+ nargs = cil_call_nargs (call);
+
+ if (cil_call_static_chain (call))
+ {
+ dump_type (file, cil_call_static_chain (call), true, true);
+
+ if (nargs_base > 0)
+ fprintf (file, ", ");
+ }
+
+ for (i = 0; i < nargs_base; i++)
+ {
+ if (i != 0)
+ fprintf (file, ", ");
+
+ dump_type (file, cil_call_arg_type (call, i), true, true);
+ }
+
+ if (cil_call_vararg_p (call) && i < nargs)
+ fprintf (file, ", ..., ");
+
+ for (; i < nargs; i++)
+ {
+ tree type = cil_call_arg_type (call, i);
+
+ if (i != nargs_base)
+ fprintf (file, ", ");
+
+ if (cil_call_missing_proto_p (call) && cil_pointer_type_p (type))
+ fprintf (file, "native int");
+ else
+ {
+ type = promote_type_for_vararg (type);
+ dump_type (file, type, true, false);
+ }
+ }
+
+ fprintf (file, ")");
+}
+
+/* Emits a single CIL statement STMT the file specified by FILE. */
+
+static void
+emit_cil_stmt (FILE *file, const_cil_stmt stmt)
+{
+ emit_prefixes (file, stmt);
+
+ switch (cil_opcode (stmt))
+ {
+ case CIL_ADD:
+ fprintf (file, "\n\tadd");
+ break;
+
+ case CIL_AND:
+ fprintf (file, "\n\tand");
+ break;
+
+ case CIL_ARGLIST:
+ fprintf (file, "\n\targlist");
+ break;
+
+ case CIL_BEQ:
+ fprintf (file, "\n\tbeq\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BGE:
+ fprintf (file, "\n\tbge\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BGE_UN:
+ fprintf (file, "\n\tbge.un\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BGT:
+ fprintf (file, "\n\tbgt\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BGT_UN:
+ fprintf (file, "\n\tbgt.un\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BLE:
+ fprintf (file, "\n\tble\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BLE_UN:
+ fprintf (file, "\n\tble.un\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BLT:
+ fprintf (file, "\n\tblt\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BLT_UN:
+ fprintf (file, "\n\tblt.un\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BNE_UN:
+ fprintf (file, "\n\tbne.un\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BR:
+ fprintf (file, "\n\tbr\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BREAK:
+ fprintf (file, "\n\tbreak");
+ break;
+
+ case CIL_BRFALSE:
+ fprintf (file, "\n\tbrfalse\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_BRTRUE:
+ fprintf (file, "\n\tbrtrue\t");
+ dump_label_name (file, cil_label (stmt));
+ break;
+
+ case CIL_CALL:
+ case CIL_CALLI:
+ emit_call (file, stmt);
+ break;
+
+ case CIL_CEQ:
+ fprintf (file, "\n\tceq");
+ break;
+
+ case CIL_CGT:
+ fprintf (file, "\n\tcgt");
+ break;
+
+ case CIL_CGT_UN:
+ fprintf (file, "\n\tcgt.un");
+ break;
+
+ case CIL_CKFINITE:
+ fprintf (file, "\n\tckfinite");
+ break;
+
+ case CIL_CLT:
+ fprintf (file, "\n\tclt");
+ break;
+
+ case CIL_CLT_UN:
+ fprintf (file, "\n\tclt.un");
+ break;
+
+ case CIL_CONV_I1:
+ fprintf (file, "\n\tconv.i1");
+ break;
+
+ case CIL_CONV_I2:
+ fprintf (file, "\n\tconv.i2");
+ break;
+
+ case CIL_CONV_I4:
+ fprintf (file, "\n\tconv.i4");
+ break;
+
+ case CIL_CONV_I8:
+ fprintf (file, "\n\tconv.i8");
+ break;
+
+ case CIL_CONV_R4:
+ fprintf (file, "\n\tconv.r4");
+ break;
+
+ case CIL_CONV_R8:
+ fprintf (file, "\n\tconv.r8");
+ break;
+
+ case CIL_CONV_U1:
+ fprintf (file, "\n\tconv.u1");
+ break;
+
+ case CIL_CONV_U2:
+ fprintf (file, "\n\tconv.u2");
+ break;
+
+ case CIL_CONV_U4:
+ fprintf (file, "\n\tconv.u4");
+ break;
+
+ case CIL_CONV_U8:
+ fprintf (file, "\n\tconv.u8");
+ break;
+
+ case CIL_CONV_I:
+ fprintf (file, "\n\tconv.i");
+ break;
+
+ case CIL_CONV_U:
+ fprintf (file, "\n\tconv.u");
+ break;
+
+ case CIL_CONV_R_UN:
+ fprintf (file, "\n\tconv.r.un");
+ break;
+
+ case CIL_CPBLK:
+ fprintf (file, "\n\tcpblk");
+ break;
+
+ case CIL_DIV:
+ fprintf (file, "\n\tdiv");
+ break;
+
+ case CIL_DIV_UN:
+ fprintf (file, "\n\tdiv.un");
+ break;
+
+ case CIL_DUP:
+ fprintf (file, "\n\tdup");
+ break;
+
+ case CIL_INITBLK:
+ fprintf (file, "\n\tinitblk");
+ break;
+
+ case CIL_INITOBJ:
+ fprintf (file, "\n\tinitobj\t");
+ dump_type (file, cil_type (stmt), true, false);
+ break;
+
+ case CIL_JMP:
+ emit_call (file, stmt);
+ break;
+
+ case CIL_LDARG:
+ fprintf (file, "\n\tldarg\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_LDARGA:
+ fprintf (file, "\n\tldarga\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_LDC_I4:
+ fprintf (file, "\n\tldc.i4\t");
+ dump_double_int (file, TREE_INT_CST (cil_cst (stmt)), false);
+ break;
+
+ case CIL_LDC_I8:
+ fprintf (file, "\n\tldc.i8\t");
+ dump_double_int (file, TREE_INT_CST (cil_cst (stmt)), false);
+ break;
+
+ case CIL_LDC_R4:
+ {
+ REAL_VALUE_TYPE d = TREE_REAL_CST (cil_cst (stmt));
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (cil_cst (stmt)));
+ char string[100];
+ long buf;
+
+ real_to_target (&buf, &d, TYPE_MODE (type));
+ real_to_decimal (string, &d, sizeof (string), 0, 1);
+ fprintf (file, "\n\tldc.r4\tfloat32(%#08lx)\t/* %s */",
+ buf, string);
+ }
+ break;
+
+ case CIL_LDC_R8:
+ {
+ REAL_VALUE_TYPE d = TREE_REAL_CST (cil_cst (stmt));
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (cil_cst (stmt)));
+ char string[100];
+ long buf[2];
+
+ real_to_target (buf, &d, TYPE_MODE (type));
+ real_to_decimal (string, &d, sizeof (string), 0, 1);
+ fprintf (file, "\n\tldc.r8\tfloat64(%#08lx%08lx)\t/* %s */",
+ buf[1], buf[0], string);
+ }
+ break;
+
+ case CIL_LDFLD:
+ emit_ldfld (file, stmt);
+ break;
+
+ case CIL_LDFLDA:
+ emit_ldflda (file, stmt);
+ break;
+
+ case CIL_LDFTN:
+ fprintf (file, "\n\tldftn\t");
+ /* FIXME: We shouldn't print the vararg ellipsis */
+ dump_fun_type (file, TREE_TYPE (cil_func (stmt)),
+ cil_func (stmt), NULL, true);
+ break;
+
+ case CIL_LDIND_I1:
+ fprintf (file, "\n\tldind.i1");
+ break;
+
+ case CIL_LDIND_I2:
+ fprintf (file, "\n\tldind.i2");
+ break;
+
+ case CIL_LDIND_I4:
+ fprintf (file, "\n\tldind.i4");
+ break;
+
+ case CIL_LDIND_I8:
+ fprintf (file, "\n\tldind.i8");
+ break;
+
+ case CIL_LDIND_U1:
+ fprintf (file, "\n\tldind.u1");
+ break;
+
+ case CIL_LDIND_U2:
+ fprintf (file, "\n\tldind.u2");
+ break;
+
+ case CIL_LDIND_U4:
+ fprintf (file, "\n\tldind.u4");
+ break;
+
+ case CIL_LDIND_U8:
+ fprintf (file, "\n\tldind.u8");
+ break;
+
+ case CIL_LDIND_R4:
+ fprintf (file, "\n\tldind.r4");
+ break;
+
+ case CIL_LDIND_R8:
+ fprintf (file, "\n\tldind.r8");
+ break;
+
+ case CIL_LDIND_I:
+ fprintf (file, "\n\tldind.i");
+ break;
+
+ case CIL_LDLOC:
+ fprintf (file, "\n\tldloc\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_LDLOCA:
+ fprintf (file, "\n\tldloca\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_LDOBJ:
+ fprintf (file, "\n\tldobj\t");
+ dump_type (file, cil_type (stmt), true, false);
+ break;
+
+ case CIL_LDSFLD:
+ emit_ldsfld (file, stmt);
+ break;
+
+ case CIL_LDSFLDA:
+ emit_ldsflda (file, stmt);
+ break;
+
+ case CIL_LOCALLOC:
+ fprintf (file, "\n\tlocalloc");
+ break;
+
+ case CIL_MUL:
+ fprintf (file, "\n\tmul");
+ break;
+
+ case CIL_NEG:
+ fprintf (file, "\n\tneg");
+ break;
+
+ case CIL_NOT:
+ fprintf (file, "\n\tnot");
+ break;
+
+ case CIL_OR:
+ fprintf (file, "\n\tor");
+ break;
+
+ case CIL_POP:
+ fprintf (file, "\n\tpop");
+ break;
+
+ case CIL_REM:
+ fprintf (file, "\n\trem");
+ break;
+
+ case CIL_REM_UN:
+ fprintf (file, "\n\trem.un");
+ break;
+
+ case CIL_RET:
+ fprintf (file, "\n\tret");
+ break;
+
+ case CIL_SHL:
+ fprintf (file, "\n\tshl");
+ break;
+
+ case CIL_SHR:
+ fprintf (file, "\n\tshr");
+ break;
+
+ case CIL_SHR_UN:
+ fprintf (file, "\n\tshr.un");
+ break;
+
+ case CIL_STARG:
+ fprintf (file, "\n\tstarg\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_STFLD:
+ emit_stfld (file, stmt);
+ break;
+
+ case CIL_STIND_I1:
+ fprintf (file, "\n\tstind.i1");
+ break;
+
+ case CIL_STIND_I2:
+ fprintf (file, "\n\tstind.i2");
+ break;
+
+ case CIL_STIND_I4:
+ fprintf (file, "\n\tstind.i4");
+ break;
+
+ case CIL_STIND_I8:
+ fprintf (file, "\n\tstind.i8");
+ break;
+
+ case CIL_STIND_R4:
+ fprintf (file, "\n\tstind.r4");
+ break;
+
+ case CIL_STIND_R8:
+ fprintf (file, "\n\tstind.r8");
+ break;
+
+ case CIL_STIND_I:
+ fprintf (file, "\n\tstind.i");
+ break;
+
+ case CIL_STLOC:
+ fprintf (file, "\n\tstloc\t");
+ dump_decl_name (file, cil_var (stmt));
+ break;
+
+ case CIL_STOBJ:
+ fprintf (file, "\n\tstobj\t");
+ dump_type (file, cil_type (stmt), true, false);
+ break;
+
+ case CIL_STSFLD:
+ emit_stsfld (file, stmt);
+ break;
+
+ case CIL_SUB:
+ fprintf (file, "\n\tsub");
+ break;
+
+ case CIL_SWITCH:
+ emit_switch (file, stmt);
+ break;
+
+ case CIL_XOR:
+ fprintf (file, "\n\txor");
+ break;
+
+ case CIL_ASM:
+ fprintf (file,
+ "\n\t// BEGIN ASM"
+ "\n\t%s"
+ "\n\t// END ASM",
+ TREE_STRING_POINTER (cil_string (stmt)));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+}
+
+
+/* Emits the start function used to call C's main() function. */
+
+static void
+emit_start_function (FILE *file)
+{
+ size_t nargs = 0;
+ tree args = DECL_ARGUMENTS (current_function_decl);
+
+ while (args)
+ {
+ args = TREE_CHAIN (args);
+ nargs++;
+ }
+
+ fprintf (file,
+ "\n.method public static void '.start'(class [mscorlib]System.String[] 'args') cil managed"
+ "\n{"
+ "\n\t.entrypoint"
+ "\n\t.maxstack 3"
+ "\n\t.locals (int32 'argc', int8** 'argv', int8** 'env')");
+
+ /* TODO?: add startup code*/
+
+ switch (nargs)
+ {
+ case 0:
+ fprintf (file,
+ "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
+ "\n\tcall\tint32 main()");
+ break;
+
+ case 1:
+ fprintf (file,
+ "\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)");
+ break;
+
+ case 2:
+ fprintf (file,
+ "\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**)");
+ break;
+
+ case 3:
+ fprintf (file,
+ "\n\tldloca\t'argc'"
+ "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)"
+ "\n\tstloc\t'argv'"
+ "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetEnvVars()"
+ "\n\tstloc\t'env'"
+ "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
+ "\n\tldloc\t'argc'"
+ "\n\tldloc\t'argv'"
+ "\n\tldloc\t'env'"
+ "\n\tcall\tint32 main(int32, int8**, int8**)");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* TODO?: add exit code*/
+
+ fprintf (file,
+ "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Shutdown(int32)"
+ "\n\tret"
+ "\n} // .start"
+ "\n\n");
+}
+
+/* Rename a single variable using the specified suffix */
+
+static void
+rename_var (tree var, const char *suffix, unsigned long index)
+{
+ const char *orig_name = IDENTIFIER_POINTER (DECL_NAME (var));
+ size_t size = strlen (orig_name) + strlen (suffix) + 10 + 1;
+ char *newsym = XNEWVEC (char, size);
+
+ size = snprintf (newsym, size, "%s%s%lu", orig_name, suffix, index);
+ DECL_NAME (var) = get_identifier_with_length (newsym, size);
+ XDELETEVEC (newsym);
+}
+
+/* Emit the static variables of a function, rename them as appropriate. */
+
+static void
+emit_static_vars (FILE *file)
+{
+ tree cell = cfun->unexpanded_var_list;
+
+ while (cell != NULL_TREE)
+ {
+ tree var = TREE_VALUE (cell);
+
+ if (TREE_STATIC (var) && TREE_ASM_WRITTEN (var) == 0)
+ {
+ /* TODO: Verify if unexpanded_var_list contains variables with
+ DECL_CONTEXT () set to NULL_TREE. */
+ if (DECL_CONTEXT (var))
+ rename_var (var, "?fs", DECL_UID (var));
+
+ emit_cil_decl (file, var);
+ }
+
+ cell = TREE_CHAIN (cell);
+ }
+}
+
+/* Helper function used by as a sorting function for qsort () by
+ emit_local_vars (). */
+
+static int
+var_uses_compare (const void *t1, const void *t2)
+{
+ const var_uses_s *vu1 = t1;
+ const var_uses_s *vu2 = t2;
+
+ if (vu1->uses == vu2->uses)
+ return DECL_UID (vu1->var) - DECL_UID (vu2->var);
+ else
+ return vu1->uses - vu2->uses;
+}
+
+/* Emit the local variables of a function, rename them as appropriate. The
+ most used local variables are emitted first, this is done in order to
+ reduce the size of the CIL code as the LDLOC/STLOC instruction have a
+ shorter form for the first 4 locals. */
+
+static void
+emit_local_vars (FILE *file)
+{
+ VEC (var_uses_s, heap) *locals;
+ var_uses_s entry;
+ struct pointer_map_t *locals_map = pointer_map_create ();
+ unsigned int i, locals_n = 0;
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ basic_block bb;
+ void **slot;
+ tree var;
+
+ /* Count and collect all the local variables used in the function, store them
+ in a pointer-map, the corresponding slots are left empty. */
+
+ FOR_EACH_BB (bb)
+ {
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+
+ switch (cil_opcode (stmt))
+ {
+ case CIL_LDLOC:
+ case CIL_LDLOCA:
+ case CIL_STLOC:
+ var = cil_var (stmt);
+
+ if (!pointer_map_contains (locals_map, var))
+ {
+ *pointer_map_insert (locals_map, var) = NULL;
+ locals_n++;
+ }
+
+ break;
+
+ default:
+ ;
+ }
+ }
+ }
+
+ /* Push into the 'locals' array all the local variables and store the number
+ of times each one is used. LDLOCA instruction do not increase the use
+ count as there is no short version of LDLOCA. */
+
+ locals = VEC_alloc (var_uses_s, heap, locals_n);
+
+ FOR_EACH_BB (bb)
+ {
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+
+ switch (cil_opcode (stmt))
+ {
+ case CIL_LDLOC:
+ case CIL_LDLOCA:
+ case CIL_STLOC:
+ var = cil_var (stmt);
+ slot = pointer_map_contains (locals_map, var);
+
+ if (*slot == NULL)
+ {
+ entry.var = var;
+ entry.uses = 1;
+ *slot = VEC_quick_push (var_uses_s, locals, &entry);
+ }
+ else if (cil_opcode (stmt) != CIL_LDLOCA)
+ ((var_uses_s *) *slot)->uses++;
+
+ break;
+
+ default:
+ ;
+ }
+ }
+ }
+
+ /* Sort the local variables by uses. DECL_UIDs are used to break ties so
+ that the sorting of the array remains the same between different runs. */
+
+ pointer_map_destroy (locals_map);
+ qsort (VEC_address (var_uses_s, locals), locals_n, sizeof (var_uses_s),
+ var_uses_compare);
+
+ /* Emit the local variables starting from the most used ones. */
+
+ fprintf (file, "\n\t.locals (");
+
+ for (i = 0; i < locals_n; i++)
+ {
+ var = (VEC_last (var_uses_s, locals))->var;
+ VEC_pop (var_uses_s, locals);
+
+ if (DECL_NAME (var) != NULL_TREE)
+ rename_var (var, DECL_FROM_INLINE (var) ? "?in" : "?", i);
+
+ if (i != 0)
+ fprintf (file, ", ");
+
+ dump_type (file, promote_local_var_type (var), true, false);
+ fprintf (file, " ");
+ dump_decl_name (file, var);
+ }
+
+ fprintf (file, ")\n");
+}
+
+/* Emit the prototype of the current function, it's attributes, etc... */
+
+static void
+emit_function_header (FILE *file)
+{
+ tree args;
+ bool varargs = false;
+ bool missing = false;
+
+ if (TARGET_OPENSYSTEMC && MAIN_NAME_P (DECL_NAME (current_function_decl)))
+ emit_start_function (file);
+
+ emit_static_vars (file);
+
+ {
+ 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;
+ }
+ else
+ missing = true;
+ }
+
+ fprintf (file, "\n.method %s static %s",
+ TREE_PUBLIC (current_function_decl) ? "public" : "private",
+ varargs ? "vararg " : "");
+ dump_type (file, TREE_TYPE (TREE_TYPE (current_function_decl)), true, false);
+ fprintf (file, " '%s' (",
+ lang_hooks.decl_printable_name (current_function_decl, 1));
+
+ args = DECL_ARGUMENTS (current_function_decl);
+
+ if (cfun->static_chain_decl)
+ {
+ dump_type (file, DECL_ARG_TYPE (cfun->static_chain_decl), true, true);
+ fprintf (file, " ");
+ dump_decl_name (file, cfun->static_chain_decl);
+ fprintf (file, "%s", args ? ", " : "");
+ }
+
+ while (args)
+ {
+ if (missing)
+ {
+ if (cil_pointer_type_p (DECL_ARG_TYPE (args)))
+ fprintf (file, "native int");
+ else
+ {
+ dump_type (file, promote_type_for_vararg (DECL_ARG_TYPE (args)),
+ true, true);
+ }
+ }
+ else
+ dump_type (file, DECL_ARG_TYPE (args), true, true);
+
+ fprintf (file, " ");
+ dump_decl_name (file, args);
+ args = TREE_CHAIN (args);
+
+ if (args)
+ fprintf (file, ", ");
+ else if (varargs)
+ fprintf (file, ", ...");
+ }
+
+ fprintf (file,
+ ") cil managed"
+ "\n{");
+
+ emit_local_vars (file);
+
+ if (DECL_STATIC_CONSTRUCTOR (current_function_decl))
+ {
+ /* For the time being this attribute is a String. */
+ emit_string_custom_attr (file, "initfun");
+
+ if (TARGET_GCC4NET_LINKER)
+ {
+ fputs ("\t.custom instance "
+ "void [gcc4net]gcc4net.C_Attributes.Initializer::.ctor() "
+ "= (01 00 00 00)\n", file);
+ }
+ else if (TARGET_OPENSYSTEMC)
+ {
+ fprintf (file,
+ "\t.custom instance "
+ "void ['OpenSystem.C']'OpenSystem.C'.InitializerAttribute::.ctor() "
+ "= (01 00 00 00)\n");
+ }
+ }
+
+ {
+ struct fnct_attr attributes;
+
+ decode_function_attrs (current_function_decl, &attributes);
+
+ if (attributes.cusattr_string)
+ emit_string_custom_attr (file, attributes.cusattr_string);
+ }
+}
+
+static void
+emit_cil_bb (FILE *file, basic_block bb)
+{
+ cil_stmt_iterator csi;
+ block_stmt_iterator bsi = bsi_start (bb);
+ tree label;
+ cil_stmt stmt = NULL;
+
+ /* Dump this block label */
+ label = LABEL_EXPR_LABEL (bsi_stmt (bsi));
+ fprintf (file, "\n");
+ dump_label_name (file, label);
+ fprintf (file, ":");
+
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+ emit_cil_stmt (file, stmt);
+ }
+}
+
+static void
+emit_cil_1 (FILE *file)
+{
+ basic_block bb;
+
+ /* Make sure that every bb has a label */
+ FOR_EACH_BB (bb)
+ {
+ tree_block_label (bb);
+ }
+
+ emit_function_header (file);
+
+ FOR_EACH_BB (bb)
+ {
+ emit_cil_bb (file, bb);
+ }
+
+/* FIXME
+ if (TARGET_EMIT_JIT_COMPILATION_HINTS)
+ {
+ basic_block_frequency_emit (file);
+ branch_probability_emit_and_reset (file);
+ } */
+
+ fprintf (file,
+ "\n\t.maxstack %u\n"
+ "\n} // %s\n",
+ compute_max_stack (),
+ lang_hooks.decl_printable_name (current_function_decl, 1));
+ TREE_ASM_WRITTEN (current_function_decl) = 1;
+}
+
+/* Gate function of the CIL assembly emission pass. */
+
+static bool
+emit_cil_gate (void)
+{
+ return current_function_decl != NULL;
+}
+
+/* Entry point of the CIL assembly emission pass. */
+
+static unsigned int
+emit_cil (void)
+{
+ emit_cil_1 (asm_out_file);
+
+ return 0;
+}
+
+/* Define the parameters of the CIL assembly emission pass. */
+
+struct tree_opt_pass pass_emit_cil =
+{
+ "emitcil", /* name */
+ emit_cil_gate, /* gate */
+ emit_cil, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_EMIT_CIL, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/* This function is mostly a copy of the last part of 'gen_cil'. */
+static void
+emit_cil_vcg_1 (FILE *vcg_file)
+{
+ basic_block bb;
+ edge_iterator ei;
+ const char *fun_name = lang_hooks.decl_printable_name (current_function_decl, 1);
+ edge e;
+ int i=0;
+
+ fprintf (vcg_file, "graph: {\n");
+ fprintf (vcg_file, "title: \"%s\"\n", fun_name);
+ fprintf (vcg_file, "node: { title: \"%sBB%d\" label: \"ENTRY %s\" }\n",
+ fun_name, ENTRY_BLOCK, fun_name);
+ fprintf (vcg_file, "node: { title: \"%sBB%d\" label: \"EXIT\" }\n",
+ fun_name, EXIT_BLOCK);
+ fprintf (vcg_file, "edge:{sourcename: \"%sBB%d\" targetname: \"%sBB%d\"}\n",
+ fun_name, ENTRY_BLOCK,
+ fun_name, single_succ (ENTRY_BLOCK_PTR)->index);
+
+ FOR_EACH_BB (bb)
+ {
+ fprintf (vcg_file, "node: { title: \"%sBB%d\" label: \"(BB%d, pos: %d)",
+ fun_name, bb->index, bb->index, i++);
+
+ if (bb->loop_depth)
+ fprintf (vcg_file, " LOOP DEPTH %d ", bb->loop_depth);
+
+ emit_cil_bb (vcg_file, bb);
+
+ fprintf (vcg_file, "\" }\n"); /* close 'label' clause */
+
+ for (ei = ei_start (bb->succs); ei_cond (ei, &e); ei_next (&ei))
+ {
+ if (e->flags & EDGE_DFS_BACK)
+ fprintf (vcg_file, "backedge: { color: red");
+ else if (e->flags & EDGE_LOOP_EXIT)
+ fprintf (vcg_file, "edge: { color: blue");
+ else
+ fprintf (vcg_file, "edge: {");
+
+ fprintf (vcg_file, " label:\"%d", e->probability);
+
+ if (e->flags & EDGE_LOOP_EXIT)
+ fprintf (vcg_file, " loop_exit");
+
+ fprintf (vcg_file, "\"");
+
+ fprintf (vcg_file,
+ " sourcename: \"%sBB%d\" targetname: \"%sBB%d\" }\n",
+ fun_name, bb->index, fun_name, e->dest->index);
+ }
+ }
+ fprintf (vcg_file, "}\n");
+}
+
+void
+emit_vcg_init (void)
+{
+ if (TARGET_EMIT_VCG)
+ fputs ("graph: {\n"
+ "display_edge_labels: yes\n", stdout);
+}
+
+void
+emit_vcg_fini (void)
+{
+ if (TARGET_EMIT_VCG)
+ fputs ("}\n", stdout);
+}
+
+static bool
+emit_cil_vcg_gate (void)
+{
+ return TARGET_EMIT_VCG && current_function_decl != NULL;
+}
+
+static unsigned int
+emit_cil_vcg (void)
+{
+ emit_cil_vcg_1(stdout);
+
+ return 0;
+}
+
+/* Define the parameters of the CIL_VCG pass. */
+
+struct tree_opt_pass pass_emit_cil_vcg =
+{
+ "emit_cil_vcg", /* name */
+ emit_cil_vcg_gate, /* gate */
+ emit_cil_vcg, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_EMIT_CIL_VCG, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/tree-simp-cil.h b/gcc/config/cil32/emit-cil.h
index 2ee919f1052..089c8380989 100644
--- a/gcc/config/cil32/tree-simp-cil.h
+++ b/gcc/config/cil32/emit-cil.h
@@ -1,6 +1,6 @@
-/* CIL simplification definitions for GNU compiler.
+/* Prototypes for the CIL dump.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006-2008 Free Software Foundation, Inc.
This file is part of GCC.
@@ -20,10 +20,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
Authors:
- Andrea Bona
Andrea Ornstein
Erven Rohou
- Roberto Costa
Gabriele Svelto
Contact information at STMicroelectronics:
@@ -31,14 +29,21 @@ Andrea C. Ornstein <andrea.ornstein@st.com>
Erven Rohou <erven.rohou@st.com>
*/
-#ifndef TREE_SIMP_CIL_H
-#define TREE_SIMP_CIL_H
+#ifndef EMIT_CIL_H
+#define EMIT_CIL_H
-#include "tree.h"
+#include "config.h"
+#include "coretypes.h"
-extern void expand_init_to_stmt_list (tree, tree, tree *);
-extern tree get_integer_type (int, bool);
-extern bool is_copy_required (tree);
-extern void set_statement_list_location (tree, location_t);
+/******************************************************************************
+ * Function prototypes *
+ ******************************************************************************/
-#endif /* TREE_SIMP_CIL_H */
+void emit_cil_init (void);
+void emit_cil_fini (void);
+void emit_cil_decl (FILE *, tree);
+
+void emit_vcg_init (void);
+void emit_vcg_fini (void);
+
+#endif /* EMIT_CIL_H */
diff --git a/gcc/config/cil32/emit-hints.c b/gcc/config/cil32/emit-hints.c
index 5662af0088d..4f8256a2e35 100644
--- a/gcc/config/cil32/emit-hints.c
+++ b/gcc/config/cil32/emit-hints.c
@@ -1,6 +1,6 @@
/* Emit hints about the CIL program.
- Copyright (C) 2006-2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -19,9 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Authors:
Andrea Bona
+ Roberto Costa
Andrea Ornstein
Erven Rohou
- Roberto Costa
+ Gabriele Svelto
Contact information at STMicroelectronics:
Andrea C. Ornstein <andrea.ornstein@st.com>
@@ -34,7 +35,6 @@ Erven Rohou <erven.rohou@st.com>
#include "tm.h"
#include "tree.h"
#include "tree-flow.h"
-#include "gen-cil.h"
#include "bit-stream.h"
#include "emit-hints.h"
@@ -116,7 +116,7 @@ static struct branch_prob_list_node *branch_prob_list_tail = NULL;
Also dump a comment with such a probability to FILE. */
void
-branch_probability_add (FILE *file, tree node)
+branch_probability_add (FILE *file ATTRIBUTE_UNUSED, tree node)
{
edge e;
struct branch_prob_list_node *n;
@@ -150,12 +150,6 @@ branch_probability_add (FILE *file, tree node)
branch_prob_list_head = n;
branch_prob_list_tail = n;
}
-
- if (TARGET_EMIT_GIMPLE_COMMENTS)
- {
- fprintf (file, "\t/* Probability: %d */",
- e->probability * 100 / REG_BR_PROB_BASE);
- }
}
/* Emit the custom attribute encoding branch probabilities and reset
@@ -278,7 +272,7 @@ basic_block_frequency_emit (FILE *file)
}
/* Allocate memory for basic block frequencies bit stream */
- start_bb_freq_coded = (unsigned char*)xmalloc (emitted_bbs);
+ start_bb_freq_coded = (unsigned char *) xmalloc (emitted_bbs);
bb_freq_coded = start_bb_freq_coded;
/* Emit number of basic blocks */
@@ -347,7 +341,7 @@ basic_block_frequency_emit (FILE *file)
fputs ("\n\t.custom instance void class "
"[gcc4net]gcc4net.JitCompilationHints."
- "JITMethodAttribute::.ctor(unsigned int8*, unsigned int8*) = (01 00 ",
+ "JITMethodAttribute::.ctor(unsigned int8*, unsigned int8 *) = (01 00 ",
file);
dump_compressed_int (file, emitted_bbs);
for (tmp_ptr = start_bb_freq_coded; tmp_ptr < bb_freq_coded; ++tmp_ptr)
diff --git a/gcc/config/cil32/emit-hints.h b/gcc/config/cil32/emit-hints.h
index 8556e27d0c5..eeb930581ea 100644
--- a/gcc/config/cil32/emit-hints.h
+++ b/gcc/config/cil32/emit-hints.h
@@ -1,6 +1,6 @@
/* Hint emission definitions for GNU compiler.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006-2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -19,9 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Authors:
Andrea Bona
+ Roberto Costa
Andrea Ornstein
Erven Rohou
- Roberto Costa
+ Gabriele Svelto
Contact information at STMicroelectronics:
Andrea C. Ornstein <andrea.ornstein@st.com>
@@ -31,14 +32,10 @@ Erven Rohou <erven.rohou@st.com>
#ifndef EMIT_HINTS_H
#define EMIT_HINTS_H
-#include "basic-block.h"
-#include "tree.h"
+#include "coretypes.h"
-void
-branch_probability_add (FILE *, tree);
-void
-branch_probability_emit_and_reset (FILE *);
-void
-basic_block_frequency_emit (FILE *);
+void branch_probability_add (FILE *, tree);
+void branch_probability_emit_and_reset (FILE *);
+void basic_block_frequency_emit (FILE *);
#endif /* EMIT_HINTS_H */
diff --git a/gcc/config/cil32/gen-cil.c b/gcc/config/cil32/gen-cil.c
deleted file mode 100644
index 1f4f9904b26..00000000000
--- a/gcc/config/cil32/gen-cil.c
+++ /dev/null
@@ -1,4120 +0,0 @@
-/* Dump of the GENERIC trees in CIL.
-
- Copyright (C) 2006-2007 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:
-Andrea C. Ornstein <andrea.ornstein@st.com>
-Erven Rohou <erven.rohou@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-pass.h"
-#include "timevar.h"
-#include "toplev.h"
-#include "pointer-set.h"
-#include "output.h"
-#include "varray.h"
-#include "ebitmap.h"
-#include "ggc.h"
-#include "tree-simp-cil.h"
-#include "cil-refs.h"
-#include "cil-builtins.h"
-#include "gen-cil.h"
-#include "emit-hints.h"
-
-struct fnct_attr
-{
- const char *assembly_name;
- const char *cil_name;
- const char *cusattr_string;
- const char *pinvoke_assembly;
- const char *pinvoke_fname;
-};
-
-/* Local functions, macros and variables. */
-static void decode_function_attrs (tree, struct fnct_attr *);
-static void dump_decl_name (FILE *, tree);
-static void dump_string_name (FILE *, tree);
-static void dump_label_name (FILE *, tree);
-static void dump_entry_label_name (FILE *, basic_block);
-static void dump_fun_type (FILE *, tree, tree, const char *, bool);
-static void dump_valuetype_name (FILE *, tree);
-static void gen_addr_expr (FILE *, tree);
-static void print_type_suffix (FILE *, tree, bool);
-static void gen_cil_modify_expr (FILE *, tree, tree);
-static void print_valuetype_decl (FILE *, tree);
-static void print_array_decl (FILE *, tree);
-static void print_incomplete_decl (FILE *, tree);
-static void print_enum_decl (FILE *, tree);
-static void print_struct_union_decl (FILE *, tree);
-static void dump_type (FILE *, tree, bool, bool);
-static void dump_string_type (FILE *, tree);
-static void dump_complex_type (FILE *, tree, bool);
-static void dump_vector_type (FILE *, tree, bool);
-static void dump_type_promotion (FILE *, tree, bool);
-static bool dump_type_promoted_type_def (FILE *, tree);
-static void dump_type_for_builtin (FILE *, tree, bool);
-static void dump_type_eval_mode (FILE *, tree, bool, 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_conv (FILE *, bool, tree, tree);
-static void gen_integral_conv (FILE *, tree, tree);
-static void gen_binary_cond_branch (FILE *, tree, tree);
-static void gen_call_expr (FILE *, tree);
-static void gen_start_function (FILE *);
-static void gen_string_custom_attr (FILE *, const char*);
-static void gen_computed_goto (FILE *, tree);
-static unsigned int gen_cil (void);
-static void gen_cil_vcg (FILE *);
-static void gen_cil_1 (FILE *);
-static void gen_cil_node (FILE *, tree);
-static void gen_cil_bb (FILE *, basic_block);
-static bool gen_cil_gate (void);
-static void print_pinvoke_function (FILE *, tree);
-static void print_string_decl (FILE *, tree);
-static void print_used_strings (FILE *);
-static void print_referenced_types (FILE *);
-static void print_referenced_pinvokes (FILE *);
-
-static unsigned int stack;
-static unsigned int max_stack;
-static basic_block bb;
-
-/* 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->cusattr_string = 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, "cil_strattr") == 0)
- attrs->cusattr_string = 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);
- }
-}
-
-/* Dump the name of a _DECL node. */
-
-static void
-dump_decl_name (FILE* file, tree node)
-{
- gcc_assert (DECL_P (node));
- fputs ("'", file);
-
- mark_decl_referenced (node);
-
- if (DECL_ASSEMBLER_NAME_SET_P (node))
- {
- const char* tname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node));
- if (tname[0] == '*')
- fprintf (file, tname+1);
- else
- fprintf (file, tname);
- }
- else if (DECL_NAME (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%u'", get_string_cst_id (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)));
- }
-}
-
-static void
-dump_entry_label_name (FILE *stream, basic_block bb)
-{
- block_stmt_iterator bsi = bsi_start (bb);
- if (!bsi_end_p (bsi))
- {
- tree stmt = bsi_stmt (bsi);
- if (TREE_CODE (stmt) == LABEL_EXPR)
- {
- tree op0 = TREE_OPERAND (stmt, 0);
- dump_label_name (stream, op0);
- }
- else
- {
- fprintf (stream, "<no label>");
- }
- }
- else
- {
- fprintf (stream, "<no basic block>");
- }
-}
-
-/* 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 name = TYPE_NAME (t);
- const char *str;
- size_t i;
-
- 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 (DECL_P (name) || TREE_CODE (name) == IDENTIFIER_NODE);
-
- fputs ("'", file);
-
- if (TREE_CODE (name) == IDENTIFIER_NODE)
- str = IDENTIFIER_POINTER (name);
- else if (DECL_NAME (name))
- str = IDENTIFIER_POINTER (DECL_NAME (name));
- else
- str = NULL;
-
- if (str)
- {
- for (i = 0; i < strlen (str); i++)
- {
- if (str[i] == '.')
- fprintf (file, "?");
- else
- fprintf (file, "%c", str[i]);
- }
- }
- else
- fprintf (file, "?UNNAMED%d", DECL_UID (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));
-
- if (ref)
- mark_referenced_type (fun_type);
-
- args_type = TYPE_ARG_TYPES (fun_type);
-
- if (args_type == NULL)
- warning (OPT_Wcil_missing_prototypes,
- "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, false);
-
- 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_GCC4NET_LINKER && DECL_EXTERNAL (fun) && TREE_PUBLIC (fun))
- {
- fputs ("[ExternalAssembly]", stream);
- if (!attrs.cil_name)
- fputs ("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, true);
- 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.
- QUALIF tells whether to emit C qualifiers (const, restrict, volatile)
- NODE must be a type node. */
-
-static void
-dump_type (FILE *file, tree node, bool ref, bool qualif)
-{
- if (node == NULL_TREE || node == error_mark_node)
- return;
-
-/* node = TYPE_MAIN_VARIANT (node); */
-
- if (TYPE_MAIN_VARIANT (node) == cil32_arg_iterator_type)
- {
- fputs ("valuetype [mscorlib]System.ArgIterator", file);
- return;
- }
-
- switch (TREE_CODE (node))
- {
- /* Incomplete and variable-length arrays are pointers and
- they must be dealt with as such. */
- case ARRAY_TYPE:
- if (! TYPE_DOMAIN (node) || ARRAY_TYPE_VARLENGTH (node))
- goto pointer;
- case ENUMERAL_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 = TYPE_PRECISION (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;
-
- pointer:
- 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, qualif);
- fputs (" *", file);
- }
- break;
-
- case FUNCTION_TYPE:
-/* dump_fun_type (file, node, NULL, NULL, ref); */
- gcc_assert (0);
- break;
-
- case VECTOR_TYPE:
- dump_vector_type (file, node, true);
- break;
-
- case COMPLEX_TYPE:
- dump_complex_type (file, node, true);
- break;
-
- case REFERENCE_TYPE:
-
- default:
- fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
- gcc_assert (0);
- break;
- }
-
- if (qualif)
- {
- unsigned int quals = TYPE_QUALS (node);
-
- if (quals & TYPE_QUAL_CONST)
- fputs (" modopt([gcc4net]gcc4net.CQualifiers.IsConst)", file);
- if (quals & TYPE_QUAL_RESTRICT)
- fputs (" modopt([gcc4net]gcc4net.CQualifiers.IsRestrict)", file);
-#if 0
- if (quals & TYPE_QUAL_VOLATILE)
- fputs (" modopt([gcc4net]gcc4net.CQualifiers.IsVolatile)", file);
-#endif
- }
-
-}
-
-static void
-dump_string_type (FILE *file, tree node)
-{
- tree domain;
- tree min;
- tree max;
- unsigned int size;
- gcc_assert(TREE_CODE (node) == ARRAY_TYPE
- && TYPE_DOMAIN (node)
- && ! ARRAY_TYPE_VARLENGTH (node));
- domain = TYPE_DOMAIN (node);
- min = TYPE_MIN_VALUE (domain);
- max = TYPE_MAX_VALUE (domain);
- gcc_assert(min
- && max
- && integer_zerop (min)
- && host_integerp (max, 0));
- size = TREE_INT_CST_LOW (max) + 1;
- fprintf (file, "valuetype '?string_type?%d'", size);
-}
-
-
-static void
-dump_complex_type (FILE *file, tree node, bool full)
-{
- int type_size = TYPE_PRECISION (TREE_TYPE (node));
-
- gcc_assert (TREE_CODE (node) == COMPLEX_TYPE);
-
- if (full)
- fputs ("valuetype [gcc4net]gcc4net.", file);
-
- fputs ("complex_", file);
- if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (node))) == MODE_INT)
- {
- if (TYPE_UNSIGNED (node))
- fputs ("u", file);
-
- switch (type_size)
- {
- case 8: fputs ("char", file); break;
- case 16: fputs ("short", file); break;
- case 32: fputs ("int", file); break;
- case 64: fputs ("long", file); break;
- default:
- fprintf (stderr, "Unsupported complex size %d\n", type_size);
- gcc_assert (0);
- }
- }
- else
- {
- switch (type_size)
- {
- case 32: fputs ("float", file); break;
- case 64: fputs ("double", file); break;
- default:
- fprintf (stderr, "Unsupported complex size %d\n", type_size);
- gcc_assert (0);
- }
- }
-}
-
-
-/* Dump vector type NODE.
-
- FULL tells whether the type must be qualified with the 'valuetype' keyword,
- assembly and namespace.
- NODE must be a type node of type VECTOR_TYPE. */
-
-static void
-dump_vector_type (FILE *file, tree node, bool full)
-{
- int vec_bitsize = TREE_INT_CST_LOW (TYPE_SIZE (node));
- tree innertype = TREE_TYPE (node);
- int inner_bitsize = TYPE_PRECISION (innertype);
- enum machine_mode innermode = TYPE_MODE (innertype);
-
- gcc_assert (TREE_CODE (node) == VECTOR_TYPE);
-
- if (full)
- fputs ("valuetype [gcc4net]gcc4net.", file);
-
- fprintf (file, "V%d", vec_bitsize / inner_bitsize);
-
- if (GET_MODE_CLASS (innermode) == MODE_INT)
- {
- switch (inner_bitsize)
- {
- case 8: fputs ("QI", file); break;
- case 16: fputs ("HI", file); break;
- case 32: fputs ("SI", file); break;
- case 64: fputs ("DI", file); break;
- default:
- fprintf (stderr, "Unsupported integer size %d\n", inner_bitsize);
- gcc_assert (0);
- }
- }
- else if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
- {
- switch (inner_bitsize)
- {
- case 32: fputs ("SF", file); break;
- case 64: fputs ("DF", file); break;
- default:
- fprintf (stderr, "Unsupported float size %d\n", inner_bitsize);
- gcc_assert (0);
- }
- }
- else
- {
- fprintf (stderr, "Unsupported mode class\n");
- gcc_assert (0);
- }
-
-}
-
-
-/* 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 *stream, tree node, bool ref)
-{
- if (node == NULL_TREE || node == error_mark_node)
- return;
-
- switch (TREE_CODE (node))
- {
- /* Incomplete and variable-length arrays are pointers and
- they must be dealt with as such. */
- case ARRAY_TYPE:
- if (! TYPE_DOMAIN (node) || ARRAY_TYPE_VARLENGTH (node))
- goto pointer;
- 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 COMPLEX_TYPE:
- dump_complex_type (stream, node, true);
- break;
-
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- case BOOLEAN_TYPE:
- {
- int type_size = TYPE_PRECISION (node);
-
- gcc_assert (type_size <= 64);
-
- if (type_size <= 32)
- fputs ("unsigned int32", stream);
- else
- fputs ("unsigned int64", stream);
- }
- break;
-
- case REAL_TYPE:
- fputs ("float64", stream);
- break;
-
- pointer:
- case POINTER_TYPE:
- /* cil32 is a 32bit machine, in case we support 64bit model
- * changes are needed
- */
- fputs ("unsigned int32", stream);
- 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.
- NODE must be a type node.
- returns true iff the dumped type is a pointer */
-
-static bool
-dump_type_promoted_type_def (FILE *stream, tree node)
-{
- bool result = false;
-
- if (node == NULL_TREE || node == error_mark_node)
- return false;
-
- switch (TREE_CODE (node))
- {
- /* Incomplete and variable-length arrays are pointers and
- they must be dealt with as such. */
- case ARRAY_TYPE:
- if (! TYPE_DOMAIN (node) || ARRAY_TYPE_VARLENGTH (node))
- goto pointer;
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- node = TYPE_MAIN_VARIANT (node);
-
- /* Reference the type if told to do so */
- mark_referenced_type (node);
-
- /* Print the name of the structure. */
- fputs ("valuetype ", stream);
- dump_valuetype_name (stream, node);
- break;
-
- case COMPLEX_TYPE:
- dump_complex_type (stream, node, true);
- break;
-
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- case BOOLEAN_TYPE:
- {
- int type_size = TYPE_PRECISION (node);
-
- gcc_assert (type_size <= 64);
-
- if (type_size <= 32)
- fputs ("class [mscorlib]System.UInt32", stream);
- else
- fputs ("class [mscorlib]System.UInt64", stream);
- }
- break;
-
- case REAL_TYPE:
- fputs ("class [mscorlib]System.Double", stream);
- break;
-
- pointer:
- case POINTER_TYPE:
- /* cil32 is a 32bit machine, in case we support 64bit model
- * changes are needed
- */
- fputs ("class [mscorlib]System.UInt32", stream);
- result = true;
- break;
-
- default:
- fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
- gcc_assert (0);
- break;
- }
- return result;
-}
-
-static void
-dump_type_for_builtin (FILE *file, tree node, bool all_types)
-{
- if (node == NULL_TREE || node == error_mark_node)
- return;
-
-/* node = TYPE_MAIN_VARIANT (node); */
-
- switch (TREE_CODE (node))
- {
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- case BOOLEAN_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 = TYPE_PRECISION (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, bool sign)
-{
- if (node == NULL_TREE || node == error_mark_node)
- return;
-
- switch (TREE_CODE (node))
- {
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- case BOOLEAN_TYPE:
- {
- int type_size = GET_MODE_BITSIZE (TYPE_MODE (node));
-
- if (sign && TYPE_UNSIGNED (node))
- fputs ("u", stream);
-
- 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 ("di", 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;
-
- case VECTOR_TYPE:
- dump_vector_type (stream, node, false);
- break;
-
- default:
- fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]);
- gcc_assert (0);
- break;
- }
-}
-
-static void
-gen_addr_expr (FILE *file, tree t)
-{
- if (t == NULL_TREE || t == error_mark_node)
- return;
-
- switch (TREE_CODE (t))
- {
- case STRING_CST:
- mark_referenced_string (t);
- fputs ("\n\tldsflda\t", file);
- dump_string_type (file, TREE_TYPE (t));
- 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, false);
- else
- fputs ("native int", file);
- fputs (" ", file);
- if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (t) && TREE_PUBLIC (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 LABEL_DECL:
- {
- /* We cannot emit the address of the label in CIL, so we map each
- label to an ID and emit the ID. The GOTO will then be implemented
- with a switch based on that ID. The ID is simply the position in
- the list of all address taken labels. */
-
- tree id = get_addr_taken_label_id (t);
- fprintf (file, "\n\tldc.i4\t%u", (unsigned int) tree_low_cst (id, 1));
- stack_push (1);
- }
- break;
-
- case INDIRECT_REF:
- gen_cil_node (file, TREE_OPERAND (t, 0));
- break;
-
- case ARRAY_REF:
- {
- tree node = t;
-
- do {
- gcc_assert (integer_zerop (TREE_OPERAND (node, 1)));
- node = TREE_OPERAND (node, 0);
- } while (TREE_CODE (node) == ARRAY_REF);
-
- gen_addr_expr (file, node);
- }
- 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));
-
- gen_addr_expr (file, obj);
- fputs ("\n\tldflda\t", file);
- dump_type (file, TREE_TYPE (fld), true, false);
- fputs (" ", file);
- mark_referenced_type (obj_type);
- dump_valuetype_name (file, obj_type);
- fputs ("::", file);
- dump_decl_name (file, fld);
- }
- 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, bool unsign)
-{
- switch (TREE_CODE (type_node))
- {
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- {
- int type_size = TYPE_PRECISION (type_node);
- bool uns = unsign && TYPE_UNSIGNED (type_node);
-
- 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 BOOLEAN_TYPE:
- fputs ((unsign && TYPE_UNSIGNED (type_node))?"u1":"i1", file);
- break;
-
- case REAL_TYPE:
- {
- int type_size = TYPE_PRECISION (type_node);
-
- 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:
- {
- int type_size = TREE_INT_CST_LOW (TYPE_SIZE (type_node));
- bool uns = TYPE_UNSIGNED (type_node) && unsign;
- 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);
-
- 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;
- }
-}
-
-/* Emit a conversion from type IN_TYPE to type OUT_TYPE to file FILE.
- IS_NOP says whether the conversion comes from a NOP_EXPR. */
-
-static void
-gen_conv (FILE *file, bool is_nop, tree out_type, tree in_type)
-{
- if (is_nop
- && INTEGRAL_TYPE_P (out_type)
- && INTEGRAL_TYPE_P (in_type))
- {
- if (TYPE_PRECISION (out_type) > TYPE_PRECISION (in_type))
- {
- tree tmp_type = TYPE_UNSIGNED (in_type)
- ? unsigned_type_for (out_type)
- : signed_type_for (out_type);
-
- gen_integral_conv (file, tmp_type, in_type);
- gen_integral_conv (file, out_type, tmp_type);
- }
- else
- gen_integral_conv (file, out_type, in_type);
- }
-
- /* Special case for conversion to float type are not orthogonal
- in CIL opcode set. */
- else if (SCALAR_FLOAT_TYPE_P (out_type)
- && INTEGRAL_TYPE_P (in_type)
- && TYPE_UNSIGNED (in_type))
- {
- fputs ("\n\tconv.r.un", file);
-
- if (TYPE_PRECISION (out_type) <= 32)
- fputs ("\n\tconv.r4", file);
- }
-
- /* Do nothing for a conversion from two REAL_TYPEs with the
- same precision. */
- else if (! SCALAR_FLOAT_TYPE_P (out_type)
- || ! SCALAR_FLOAT_TYPE_P (in_type)
- || TYPE_PRECISION (out_type) != TYPE_PRECISION (in_type))
- {
- fputs ("\n\tconv.", file);
- print_type_suffix (file, out_type, true);
- }
-}
-
-/* Emit a conversion from integral or pointer type IN_TYPE
- to integral type OUT_TYPE to file FILE.
- If the precision of OUT_TYPE is bigger than that of IN_TYPE,
- then IN_TYPE and OUT_TYPE have to have the same signedness. */
-
-static void
-gen_integral_conv (FILE *file, tree out_type, tree in_type)
-{
- unsigned int out_bits, cont_size, in_bits;
-
- gcc_assert (INTEGRAL_TYPE_P (out_type));
- gcc_assert (INTEGRAL_TYPE_P (in_type) || POINTER_TYPE_P (in_type));
- gcc_assert (TYPE_PRECISION (out_type) <= 64);
- gcc_assert (TYPE_PRECISION (out_type) <= TYPE_PRECISION (in_type)
- || TYPE_UNSIGNED (out_type) == TYPE_UNSIGNED (in_type));
-
- /* Get the precision of the output and input types and the size
- of the output type container */
- in_bits = TYPE_PRECISION (in_type);
- out_bits = TYPE_PRECISION (out_type);
- cont_size = GET_MODE_BITSIZE (TYPE_MODE (out_type));
- gcc_assert (cont_size >= out_bits);
-
- /* Dump a conv with for the container size, if not superfluous */
- if ((cont_size == out_bits && (out_bits != in_bits || out_bits < 32))
- || ((out_bits > 32) ^ (in_bits > 32)))
- {
- fputs ("\n\tconv.", file);
- print_type_suffix (file, get_integer_type (cont_size,
- TYPE_UNSIGNED (out_type)),
- true);
- }
-
- /* If the container is bigger than the output type precision,
- force the output to be of the desired precision. */
- if (cont_size > out_bits)
- {
- if (TYPE_UNSIGNED (out_type))
- {
- unsigned HOST_WIDEST_INT mask;
- double_int mask_di;
-
- /* Compute the mask to be applied to the existing value */
- gcc_assert (HOST_BITS_PER_WIDEST_INT >= 64);
- mask = (1LL << out_bits) - 1LL;
- mask_di.low = mask;
- mask_di.high = (HOST_WIDE_INT)(mask >> HOST_BITS_PER_WIDE_INT);
-
- /* Apply the mask */
- if (out_bits <= 32)
- fputs ("\n\tldc.i4\t", file);
- else
- fputs ("\n\tldc.i8\t", file);
- dump_double_int (file, mask_di, false);
- fputs ("\n\tand", file);
- }
- else
- {
- unsigned int cont_size = (out_bits > 32) ? 64 : 32;
- unsigned int shift = cont_size - out_bits;
-
- /* Do a pair of shift to perform the sign extension */
- fprintf (file, "\n\tldc.i4\t%d", shift);
- fputs ("\n\tshl\t", file);
- fprintf (file, "\n\tldc.i4\t%d", shift);
- fputs ("\n\tshr\t", file);
- }
-
- stack_push (1);
- stack_pop (1);
- }
-}
-
-static void
-gen_binary_cond_branch (FILE *file, tree node, tree label)
-{
- tree op0 = TREE_OPERAND (node, 0);
- tree op1 = TREE_OPERAND (node, 1);
- bool is_unsigned = TYPE_UNSIGNED (TREE_TYPE (op0));
-
- gcc_assert (TREE_CODE (label) == LABEL_DECL);
-
- if (TREE_CODE (node) == UNORDERED_EXPR
- || TREE_CODE (node) == ORDERED_EXPR)
- {
- gen_cil_node (file, op0);
- fputs ("\n\tdup"
- "\n\tceq", file);
-
- stack_push (1);
- stack_pop (1);
-
- gen_cil_node (file, op1);
- fputs ("\n\tdup"
- "\n\tceq"
- "\n\tand"
- "\n\tbr", file);
-
- if (TREE_CODE (node) == UNORDERED_EXPR)
- fputs ("false\t", file);
- else
- fputs ("true\t", file);
-
- dump_label_name (file, label);
-
- stack_push (1);
- stack_pop (3);
-
- return;
- }
-
- gen_cil_node (file, op0);
- gen_cil_node (file, op1);
-
- switch (TREE_CODE (node))
- {
- 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;
- case UNLT_EXPR: fputs ("\n\tblt", file); is_unsigned = TRUE; break;
- case UNLE_EXPR: fputs ("\n\tble", file); is_unsigned = TRUE; break;
- case UNGT_EXPR: fputs ("\n\tbgt", file); is_unsigned = TRUE; break;
- case UNGE_EXPR: fputs ("\n\tbge", file); is_unsigned = TRUE; break;
- default:
- gcc_unreachable ();
- }
-
- if (is_unsigned)
- fputs (".un\t", file);
- else
- fputs ("\t", file);
- dump_label_name (file, label);
-
- stack_pop (2);
-}
-
-/* Dump a CALL_EXPR gimple node NODE in CIL on the file FILE. */
-
-static void
-gen_call_expr (FILE *file, tree node)
-{
- bool done = false;
- tree fdecl;
- tree fun_expr;
- tree fun_type;
- bool direct_call;
- unsigned int nargs;
-
- gcc_assert(TREE_CODE (node) == CALL_EXPR);
-
- fun_expr = get_callee_fndecl (node);
- if (fun_expr)
- {
- fdecl = fun_expr;
- fun_type = TREE_TYPE (fun_expr);
- direct_call = true;
- }
- else
- {
- fun_expr = CALL_EXPR_FN (node);
- fdecl = NULL_TREE;
- fun_type = TREE_TYPE (TREE_TYPE (fun_expr));
- direct_call = false;
- }
- nargs = call_expr_nargs(node);
-
- /* Built-in functions must be handled in a special way */
- if (direct_call && DECL_BUILT_IN (fdecl))
- {
-
- if (DECL_BUILT_IN_CLASS (fdecl) == BUILT_IN_MD)
- {
- switch (DECL_FUNCTION_CODE (fdecl))
- {
- case CIL32_BUILT_IN_VA_START:
- {
- tree va = CALL_EXPR_ARG (node, 0);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va)))
- == cil32_arg_iterator_type);
-
- gen_cil_node (file, va);
- fputs ("\n\tdup"
- "\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator"
- "\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 CIL32_BUILT_IN_VA_ARG:
- {
- tree va = CALL_EXPR_ARG (node, 0);
- tree dummy = CALL_EXPR_ARG (node, 1);
- tree type = TREE_TYPE (TREE_TYPE (dummy));
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va)))
- == cil32_arg_iterator_type);
-
- gen_cil_node (file, va);
- fputs ("\n\tcall\tinstance typedref [mscorlib]System.ArgIterator::GetNextArg()"
- "\n\trefanyval ",
- file);
-
- if (dump_type_promoted_type_def (file, type))
- fputs ("\n\tconv.i", file);
-
- done = true;
- }
- break;
-
- case CIL32_BUILT_IN_VA_END:
- {
- tree va = CALL_EXPR_ARG (node, 0);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va)))
- == cil32_arg_iterator_type);
-
- gen_cil_node (file, va);
- fputs ("\n\tcall\tinstance void [mscorlib]System.ArgIterator::End()",
- file);
-
- stack_pop (1);
- done = true;
- }
- break;
-
- case CIL32_BUILT_IN_VA_COPY:
- {
- tree va_dest = CALL_EXPR_ARG (node, 0);
- tree va_src = CALL_EXPR_ARG (node, 1);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va_dest))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va_dest)))
- == cil32_arg_iterator_type);
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va_src))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va_src)))
- == cil32_arg_iterator_type);
-
- gen_cil_node (file, va_dest);
- fputs ("\n\tdup"
- "\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator",
- file);
- stack_push (1);
- stack_pop (1);
-
- gen_cil_node (file, va_src);
- fputs ("\n\tcpobj\t[mscorlib]System.ArgIterator", file);
-
- stack_pop (2);
- done = true;
- }
- break;
-
- case CIL32_BUILT_IN_CPBLK:
- {
- tree ptr_dst = CALL_EXPR_ARG (node, 0);
- tree ptr_src = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- gen_cil_node (file, ptr_dst);
- 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 CIL32_BUILT_IN_INITBLK:
- {
- tree ptr = CALL_EXPR_ARG (node, 0);
- tree value = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- gen_cil_node (file, ptr);
- gen_cil_node (file, value);
- gen_cil_node (file, size);
-
- fputs ("\n\tunaligned. 1"
- "\n\tinitblk", file);
- stack_pop (3);
- done = true;
- }
- break;
-
- case CIL32_BUILT_IN_IS_LITTLE_ENDIAN:
- {
- fputs ("\n\tcall\tbool [gcc4net]gcc4net.Crt::__isLittleEndian()",
- file);
-
- stack_push (1);
- done = true;
- }
- break;
-
- case CIL32_BUILT_IN_ENDIAN_SELECT:
- {
- tree le_tree = CALL_EXPR_ARG (node, 0);
- tree be_tree = CALL_EXPR_ARG (node, 1);
-
- gen_cil_node (file, le_tree);
- gen_cil_node (file, be_tree);
- fputs ("\n\tcall\tvoid* [gcc4net]gcc4net.Crt::__EndianSelect(void*, void*)",
- file);
-
- stack_pop (2);
- stack_push (1);
- done = true;
- }
- break;
-
- case CIL32_V2SF_CTOR:
- case CIL32_V4SF_CTOR:
- case CIL32_V4QI_CTOR:
- case CIL32_V2HI_CTOR:
- case CIL32_V8QI_CTOR:
- case CIL32_V4HI_CTOR:
- case CIL32_V2SI_CTOR:
- case CIL32_V4SI_CTOR:
- case CIL32_V8HI_CTOR:
- case CIL32_V16QI_CTOR:
- {
- unsigned int i;
- tree arg;
- call_expr_arg_iterator iter;
- tree arg_type;
- tree result = TREE_TYPE (fun_type);
-
- /* the type should be the same for all args. */
- arg_type = TREE_TYPE (CALL_EXPR_ARG (node, 0));
- FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
- gen_cil_node (file, arg);
-
- fputs ("\n\tcall ", file);
- dump_vector_type (file, result, true);
- fputs (" [gcc4net]gcc4net.", file);
- dump_vector_type (file, result, false);
- fputs ("::", file);
- dump_decl_name (file, fdecl);
- fputs ("(", file);
-
- /* emit the same type 'nargs' times */
- for(i = 0; i < nargs; ++i)
- {
- if (i)
- fputs (", ", file);
-
- if (TREE_CODE (arg_type) == INTEGER_TYPE
- && !TYPE_UNSIGNED (arg_type))
- fputs ("unsigned ", file);
-
- dump_type (file, arg_type, false, false);
- }
- fputs (")", file);
-
- stack_pop (nargs-1);
- done = true;
- break;
- }
-
- default:
- gcc_assert (0);
- }
- }
- else
- {
- switch (DECL_FUNCTION_CODE (fdecl))
- {
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- gcc_assert (0);
- break;
-
- case BUILT_IN_INIT_TRAMPOLINE:
- case BUILT_IN_ADJUST_TRAMPOLINE:
- case BUILT_IN_NONLOCAL_GOTO:
- internal_error ("Builtins to support Trampolines not implemented\n");
- break;
-
- case BUILT_IN_PROFILE_FUNC_ENTER:
- case BUILT_IN_PROFILE_FUNC_EXIT:
- internal_error ("Builtins to support Profiling not implemented\n");
- break;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_DISPATCHER:
- case BUILT_IN_SETJMP_RECEIVER:
- internal_error ("Builtins to support Setjump not implemented\n");
- break;
-
- case BUILT_IN_MEMSET:
- {
- tree ptr = CALL_EXPR_ARG (node, 0);
- tree value = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- 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 ptr_dst = CALL_EXPR_ARG (node, 0);
- tree ptr_src = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- 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 size = CALL_EXPR_ARG (node, 0);
-
- gen_cil_node (file, size);
- fputs ("\n\tlocalloc", file);
-
- done = true;
- }
- break;
-
- case BUILT_IN_STACK_SAVE:
- /* This built-in is only used for the implementation
- of variable-length arrays.
- It's not needed in CIL. */
- fputs ("\n\tldc.i4.0"
- "\n\tconv.i", file);
- stack_push (1);
- done = true;
- break;
-
- case BUILT_IN_STACK_RESTORE:
- /* This built-in is only used for the implementation
- of variable-length arrays.
- It's not needed in CIL. */
- done = true;
- break;
-
- case BUILT_IN_EXPECT:
- /* __builtin_expect(exp,val) evalutes exp and tells the
- compiler that it most likely gives val. We just
- evaluate exp. */
- gen_cil_node (file, CALL_EXPR_ARG (node, 0));
- done = true;
- break;
-
- case BUILT_IN_TRAP:
- fputs ("\n\tcall\tvoid 'abort' ()", file);
- done = true;
- break;
-
- case BUILT_IN_CLZ:
- case BUILT_IN_CLZL:
- case BUILT_IN_CLZLL:
- case BUILT_IN_CTZ:
- case BUILT_IN_CTZL:
- case BUILT_IN_CTZLL:
- case BUILT_IN_FFS:
- case BUILT_IN_FFSL:
- case BUILT_IN_FFSLL:
- case BUILT_IN_PARITY:
- case BUILT_IN_PARITYL:
- case BUILT_IN_PARITYLL:
- case BUILT_IN_POPCOUNT:
- case BUILT_IN_POPCOUNTL:
- case BUILT_IN_POPCOUNTLL:
- {
- tree fun_arg_types = TYPE_ARG_TYPES (fun_type);
- tree arg = CALL_EXPR_ARG (node, 0);
- tree arg_type = TREE_VALUE (fun_arg_types);
- gen_cil_node (file, arg);
- fputs ("\n\tcall\tint32 [gcc4net]gcc4net.Crt::__", file);
- switch (DECL_FUNCTION_CODE (fdecl))
- {
- case BUILT_IN_CLZ:
- case BUILT_IN_CLZL:
- case BUILT_IN_CLZLL:
- fputs ("clz", file);
- break;
- case BUILT_IN_CTZ:
- case BUILT_IN_CTZL:
- case BUILT_IN_CTZLL:
- fputs ("ctz", file);
- break;
- case BUILT_IN_FFS:
- case BUILT_IN_FFSL:
- case BUILT_IN_FFSLL:
- fputs ("ffs", file);
- break;
- case BUILT_IN_PARITY:
- case BUILT_IN_PARITYL:
- case BUILT_IN_PARITYLL:
- fputs ("parity", file);
- break;
- case BUILT_IN_POPCOUNT:
- case BUILT_IN_POPCOUNTL:
- case BUILT_IN_POPCOUNTLL:
- fputs ("popcount", file);
- break;
- default:
- gcc_assert (0);
- break;
- }
- dump_type_eval_mode (file, arg_type, false, false);
- fputs ("2(", file);
- dump_type_for_builtin (file, arg_type, false);
- fputs (")", 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 (fdecl))); */
-/* gcc_assert (0); */
-/* } */
- }
- }
- }
-
- if (!done)
- {
- tree args;
- tree args_type;
- tree static_chain;
- bool varargs;
- unsigned int nargs_base;
- unsigned int aidx;
-
- args_type = TYPE_ARG_TYPES (fun_type);
- varargs = FALSE;
-
- if (args_type == NULL)
- {
- if (direct_call)
- warning (OPT_Wcil_missing_prototypes,
- "Missing function %s prototype, guessing it, "
- "you should fix the code",
- IDENTIFIER_POINTER (DECL_NAME (fdecl)));
- else
- warning (OPT_Wcil_missing_prototypes,
- "Missing indirect function prototype, guessing it, "
- "you should fix the code");
- /* Guess types using the type of the arguments */
- nargs_base = 0;
- }
- else
- {
- tree last_arg_type = tree_last (args_type);
- nargs_base = list_length (args_type);
-
- if (TREE_VALUE (last_arg_type) != void_type_node)
- {
- varargs = TRUE;
- }
- else
- {
- --nargs_base;
- }
- }
-
- /* Print parameters. */
-
- /* If static Chain present, it will be the first argument */
- static_chain = CALL_EXPR_STATIC_CHAIN(node);
- if (static_chain)
- gen_cil_node (file, static_chain);
-
- for (aidx=0;aidx<nargs_base;++aidx)
- {
- gen_cil_node (file, CALL_EXPR_ARG (node, aidx));
- }
-
- for (;aidx<nargs;++aidx) {
- tree targ = CALL_EXPR_ARG (node, aidx);
- tree targ_type = TREE_TYPE(targ);
- gen_cil_node (file, targ);
- if (TREE_CODE (targ_type) == POINTER_TYPE
- || (TREE_CODE (targ_type) == ARRAY_TYPE
- && (! TYPE_DOMAIN (targ_type) || ARRAY_TYPE_VARLENGTH (targ_type))))
- fputs ("\n\tconv.i", file);
- }
-
- /* Print function pointer, in case of indirect call */
- if (!direct_call)
- gen_cil_node (file, fun_expr);
-
-#if 0
- 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);
-
- if (varargs)
- fputs ("vararg ", file);
-
- dump_type (file, TREE_TYPE (fun_type), true, false);
-
- if (direct_call)
- {
- struct fnct_attr attrs;
- decode_function_attrs (fdecl, &attrs);
-
- fputs (" ", file);
-
- if (attrs.assembly_name)
- fprintf (file, "[%s]", attrs.assembly_name);
- else if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (fdecl) && TREE_PUBLIC (fdecl))
- {
- fputs ("[ExternalAssembly]", file);
- if (!attrs.cil_name)
- fputs ("ExternalAssembly::", file);
- }
-
- if (attrs.cil_name)
- fprintf (file, "%s", attrs.cil_name);
- else
- dump_decl_name (file, fdecl);
- }
-
- fputs (" (", file);
- args = TREE_OPERAND (node, 1);
-
- if (static_chain)
- {
- dump_type (file, TREE_TYPE (static_chain), true, true);
- if (nargs_base > 0)
- fputs (", ", file);
- }
-
- for (aidx=0;aidx<nargs_base;++aidx)
- {
- if (aidx!=0)
- {
- fputs (", ", file);
- }
-
- dump_type (file, TREE_VALUE (args_type), true, true);
- args_type = TREE_CHAIN (args_type);
- }
-
- if (varargs && aidx<nargs)
- fputs (", ..., ", file);
-
- for (;aidx<nargs;++aidx)
- {
- if (aidx!=nargs_base)
- {
- fputs (", ", file);
- }
-
- dump_type_promotion (file, TREE_TYPE (CALL_EXPR_ARG (node, aidx)), true);
- }
-
- fputs (")", file);
-
- if (!direct_call)
- ++nargs;
- if (static_chain)
- ++nargs;
- stack_pop (nargs);
-
- if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE)
- stack_push (1);
- }
-}
-
-/* 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 || node == error_mark_node)
- return;
-
- 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 = TYPE_PRECISION (TREE_TYPE (node));
-
- gcc_assert (type_size <= 64);
- if (type_size <= 32)
- fputs ("\n\tldc.i4\t", file);
- else
- fputs ("\n\tldc.i8\t", file);
- dump_double_int (file, TREE_INT_CST (node), false);
-
- if (POINTER_TYPE_P (TREE_TYPE (node)))
- fputs ("\n\tconv.i", file);
-
- stack_push (1);
- }
- break;
-
- case COMPLEX_CST:
- {
- tree cplx_type = TREE_TYPE (node);
- tree re = TREE_REALPART (node);
- tree im = TREE_IMAGPART (node);
-
- gen_cil_node (file, re);
- gen_cil_node (file, im);
- fputs ("\n\tcall ", file);
- dump_complex_type (file, cplx_type, true);
- fputs (" [gcc4net]gcc4net.", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("::", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("_ctor (", file);
- dump_type (file, TREE_TYPE (re), false, false);
- fputs (", ", file);
- dump_type (file, TREE_TYPE (re), false, false);
- fputs (")", file);
- stack_pop (2);
- 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 = TYPE_PRECISION (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:
- {
- int num_elt = 0;
- int i;
- tree elt;
- tree vector_type = TREE_TYPE (node);
- int vector_bitsize = TREE_INT_CST_LOW (TYPE_SIZE (vector_type));
- tree unit_type = TREE_TYPE (vector_type);
- int unit_bitsize = TYPE_PRECISION (unit_type);
-
- gcc_assert (HOST_BITS_PER_WIDEST_INT >= 64);
-
- for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt))
- {
- tree elt_val = TREE_VALUE (elt);
- gen_cil_node (file, elt_val);
- ++num_elt;
- }
- /* Fill in the missing initializers, if any */
- for ( ; num_elt < vector_bitsize/unit_bitsize; ++num_elt)
- {
- if (GET_MODE_CLASS (TYPE_MODE (unit_type)) == MODE_INT)
- {
- fputs ("\n\tldc.i4.0", file);
- }
- else if (GET_MODE_CLASS (TYPE_MODE (unit_type)) == MODE_FLOAT)
- {
- fputs ("\n\tldc.r4 0.0", file);
- }
- else
- internal_error ("\n\nDo not know how to initialize vector\n");
-
- stack_push (1);
- }
- fputs ("\n\tcall ", file);
- dump_type(file, vector_type, false, false);
- fputs (" [gcc4net]gcc4net.", file);
- dump_vector_type(file, vector_type, false);
- fputs ("::", file);
- dump_vector_type(file, vector_type, false);
- fputs ("_ctor1(", file);
- for (i=0; i < num_elt; ++i)
- {
- if (i)
- fputs (", ", file);
- if ((GET_MODE_CLASS (TYPE_MODE (unit_type)) == MODE_INT) &&
- (!TYPE_UNSIGNED (unit_type)))
- {
- fputs ("unsigned ", file);
- }
-
- dump_type (file, unit_type, false, false);
- }
- fputs (")", file);
- stack_pop (num_elt);
- 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:
- case GIMPLE_MODIFY_STMT:
- gen_cil_modify_expr (file,
- GENERIC_TREE_OPERAND (node, 0),
- GENERIC_TREE_OPERAND (node, 1));
- break;
-
- case GOTO_EXPR:
- {
- tree label_decl = GOTO_DESTINATION (node);
-
- if (TREE_CODE (label_decl) != LABEL_DECL)
- {
- /* This is a goto to the address of a label. Labels have been
- numbered, and we emit a switch based on that ID. */
- gen_computed_goto (file, label_decl);
- }
- else
- {
- basic_block dest_bb = label_to_block (label_decl);
-
- if (bb->next_bb != dest_bb)
- {
- fputs ("\n\tbr\t", file);
- dump_label_name (file, label_decl);
- }
- }
- gcc_assert (stack == 0);
- }
- break;
-
- case COND_EXPR:
- {
- tree label_then, label_else;
-
- if (COND_EXPR_THEN (node)
- && simple_goto_p (COND_EXPR_THEN (node)))
- {
- /* At this point, both clauses of COND_EXPR must contain simple gotos */
- gcc_assert (COND_EXPR_ELSE (node)
- && simple_goto_p (COND_EXPR_ELSE (node)));
- label_then = GOTO_DESTINATION (COND_EXPR_THEN (node));
- label_else = GOTO_DESTINATION (COND_EXPR_ELSE (node));
- }
- else
- {
- edge true_edge;
- edge false_edge;
- extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
- label_then = tree_block_label (true_edge->dest);
- label_else = tree_block_label (false_edge->dest);
- }
-
- gcc_assert (label_then != NULL_TREE && label_else != NULL_TREE);
-
- op0 = COND_EXPR_COND (node);
- if (TREE_CODE (op0) == EQ_EXPR
- || TREE_CODE (op0) == NE_EXPR)
- {
- tree op00 = TREE_OPERAND (op0, 0);
- tree op01 = TREE_OPERAND (op0, 1);
- tree cond_type = TREE_TYPE (op00);
-
- if ((INTEGRAL_TYPE_P (cond_type) || POINTER_TYPE_P (cond_type))
- && ((TREE_CODE (op00) == INTEGER_CST
- && double_int_zero_p (TREE_INT_CST (op00)))
- || (TREE_CODE (op01) == INTEGER_CST
- && double_int_zero_p (TREE_INT_CST (op01)))))
- {
- if ((TREE_CODE (op00) == INTEGER_CST
- && double_int_zero_p (TREE_INT_CST (op00))))
- gen_cil_node (file, op01);
- else
- gen_cil_node (file, op00);
-
- if (TREE_CODE (op0) == EQ_EXPR)
- fputs ("\n\tbrfalse\t", file);
- else
- fputs ("\n\tbrtrue\t", file);
- dump_label_name (file, label_then);
-
- stack_pop (1);
- }
- else
- gen_binary_cond_branch (file, op0, label_then);
- }
- else if (TREE_CODE (op0) == LE_EXPR
- || TREE_CODE (op0) == LT_EXPR
- || TREE_CODE (op0) == GE_EXPR
- || TREE_CODE (op0) == GT_EXPR
- || TREE_CODE (op0) == UNLT_EXPR
- || TREE_CODE (op0) == UNLE_EXPR
- || TREE_CODE (op0) == UNGT_EXPR
- || TREE_CODE (op0) == UNGE_EXPR)
- {
- gen_binary_cond_branch (file, op0, label_then);
- }
- else
- {
- gen_cil_node (file, op0);
- fputs ("\n\tldc.i4.0"
- "\n\tbne.un\t", file);
- dump_label_name (file, label_then);
- stack_push (1);
- stack_pop (2);
- }
-
- if (TARGET_EMIT_JIT_COMPILATION_HINTS)
- branch_probability_add (file, node);
-
- {
- basic_block dest_bb = label_to_block (label_else);
-
- /* Emit else block only if it is not a fallthrough */
- if (bb->next_bb != dest_bb)
- {
- fputs ("\n\tbr\t", file);
- dump_label_name (file, label_else);
- }
- 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:
- gen_call_expr (file, node);
- break;
-
- case MULT_EXPR:
- case PLUS_EXPR:
- case POINTER_PLUS_EXPR:
- case MINUS_EXPR:
- case RDIV_EXPR:
- case LSHIFT_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 POINTER_PLUS_EXPR:
- 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;
- default:
- gcc_unreachable ();
- }
-
- stack_pop (1);
-
- /* Values with precision smaller than the one used
- on the evaluation stack require an explicit conversion. */
- if (INTEGRAL_TYPE_P (TREE_TYPE (node)))
- gen_integral_conv (file, TREE_TYPE (node), TREE_TYPE (node));
- break;
-
- case BIT_IOR_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 BIT_IOR_EXPR: fputs ("\n\tor", file); break;
- case BIT_XOR_EXPR: fputs ("\n\txor", file); break;
- default:
- gcc_unreachable ();
- }
-
- /* No need for conversions even in case of values with precision
- smaller than the one used on the evaluation stack,
- since for these operations the output is
- always less or equal than both operands. */
-
- stack_pop (1);
- break;
-
- case BIT_AND_EXPR:
- op0 = TREE_OPERAND (node, 0);
- op1 = TREE_OPERAND (node, 1);
-
- if (TREE_CODE (op0) == INTEGER_CST
- && (TREE_INT_CST_LOW (op0) == 255U
- || TREE_INT_CST_LOW (op0) == 65535U
- || TREE_INT_CST_LOW (op0) == 4294967295U)
- && TREE_INT_CST_HIGH (op0) == 0)
- {
- gen_cil_node (file, op1);
-
- fputs ("\n\tconv.u", file);
-
- switch (TREE_INT_CST_LOW (op0))
- {
- case 255U: fputs ("1", file); break;
- case 65535U: fputs ("2", file); break;
- case 4294967295U: fputs ("4", file); break;
- default:
- gcc_unreachable ();
- }
-
- if (TYPE_PRECISION (TREE_TYPE (node)) > 32)
- fputs ("\n\tconv.u8", file);
- }
- else if (TREE_CODE (op1) == INTEGER_CST
- && (TREE_INT_CST_LOW (op1) == 255U
- || TREE_INT_CST_LOW (op1) == 65535U
- || TREE_INT_CST_LOW (op1) == 4294967295U)
- && TREE_INT_CST_HIGH (op1) == 0)
- {
- gen_cil_node (file, op0);
-
- fputs ("\n\tconv.u", file);
-
- switch (TREE_INT_CST_LOW (op1))
- {
- case 255U: fputs ("1", file); break;
- case 65535U: fputs ("2", file); break;
- case 4294967295U: fputs ("4", file); break;
- default:
- gcc_unreachable ();
- }
-
- if (TYPE_PRECISION (TREE_TYPE (node)) > 32)
- fputs ("\n\tconv.u8", file);
- }
- else
- {
- gen_cil_node (file, op0);
- gen_cil_node (file, op1);
-
- fputs ("\n\tand", file);
-
- /* No need for conversions even in case of values with precision
- smaller than the one used on the evaluation stack,
- 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:
- case UNLT_EXPR:
- case UNGT_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;
- case UNLT_EXPR: fputs ("\n\tclt.un", file); break;
- case UNGT_EXPR: fputs ("\n\tcgt.un", file); break;
-
- default:
- gcc_unreachable ();
- }
-
- if (TYPE_PRECISION (TREE_TYPE (node)) > 32)
- 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 (TYPE_PRECISION (TREE_TYPE (node)) > 32)
- fputs ("\n\tconv.i8", file);
-
- stack_pop (1);
- break;
-
- case UNORDERED_EXPR:
- op0 = TREE_OPERAND (node, 0);
- op1 = TREE_OPERAND (node, 1);
-
- gen_cil_node (file, op0);
- fputs ("\n\tdup"
- "\n\tceq", file);
-
- stack_push (1);
- stack_pop (1);
-
- gen_cil_node (file, op1);
- fputs ("\n\tdup"
- "\n\tceq"
- "\n\tand"
- "\n\tldc.i4.1"
- "\n\txor", file);
-
- stack_push (1);
- stack_pop (2);
- break;
-
- case ORDERED_EXPR:
- op0 = TREE_OPERAND (node, 0);
- op1 = TREE_OPERAND (node, 1);
-
- gen_cil_node (file, op0);
- fputs ("\n\tdup"
- "\n\tceq", file);
-
- stack_push (1);
- stack_pop (1);
-
- gen_cil_node (file, op1);
- fputs ("\n\tdup"
- "\n\tceq"
- "\n\tand", file);
-
- stack_push (1);
- stack_pop (2);
- 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 with precision
- smaller than the one used on the evaluation stack,
- 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
- internal_error ("\n\nFLOOR_DIV_EXPR is not completely supported\n");
-
- /* No need for conversions even in case of values with precision
- smaller than the one used on the evaluation stack,
- since for these operations 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 with precision smaller than the one used
- on the evaluation stack require an explicit conversion.
- 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 (INTEGRAL_TYPE_P (TREE_TYPE (node)))
- gen_integral_conv (file, TREE_TYPE (node), TREE_TYPE (node));
- break;
-
- case INDIRECT_REF:
- case ARRAY_REF:
- gen_addr_expr (file, node);
-
- if (TREE_THIS_VOLATILE (node))
- fputs ("\n\tvolatile.", file);
-
- if (AGGREGATE_TYPE_P (TREE_TYPE (node)))
- {
- fputs ("\n\tldobj\t", file);
- dump_type (file, TREE_TYPE (node), true, false);
- }
- else if (TREE_CODE (TREE_TYPE (node)) == COMPLEX_TYPE)
- {
- fputs ("\n\tldobj ", file);
- dump_complex_type (file, TREE_TYPE (node), true);
- }
- else if (TREE_CODE (TREE_TYPE (node)) == VECTOR_TYPE)
- {
- fputs ("\n\tldobj ", file);
- dump_vector_type (file, TREE_TYPE (node), true);
- }
- else
- {
- fputs ("\n\tldind.", file);
- print_type_suffix (file, TREE_TYPE (node), true);
- }
- break;
-
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- /* ER: if flag_trapv is set, we could generate the .ovf version? */
- /* TODO: */
- case FIX_TRUNC_EXPR:
- case NOP_EXPR:
- gen_cil_node (file, TREE_OPERAND (node, 0));
- gen_conv (file,
- (TREE_CODE (node) == NOP_EXPR),
- TREE_TYPE (node),
- TREE_TYPE (TREE_OPERAND (node, 0)));
- 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 || TREE_CODE (op0) == GIMPLE_MODIFY_STMT)
- op0 = GENERIC_TREE_OPERAND (op0, 1);
-
- 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, 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, 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))
- {
- if (TREE_THIS_VOLATILE (node))
- {
- /* put the address of the loc on the stack */
- fputs ("\n\tldloca\t", file);
- dump_decl_name (file, node);
- /* and emit a volatile ldind or ldobj */
- fputs ("\n\tvolatile.", file);
- if (AGGREGATE_TYPE_P (TREE_TYPE (node)) ||
- TREE_CODE (TREE_TYPE (node)) == COMPLEX_TYPE ||
- TREE_CODE (TREE_TYPE (node)) == VECTOR_TYPE)
- {
- fputs ("\n\tldobj\t", file);
- dump_type (file, TREE_TYPE (node), true, false);
- }
- else
- {
- fputs ("\n\tldind.", file);
- print_type_suffix (file, TREE_TYPE (node), true);
- }
- }
- else
- {
- fputs ("\n\tldloc\t", file);
- dump_decl_name (file, node);
- }
- }
- else
- {
- if (TREE_THIS_VOLATILE (node))
- fputs ("\n\tvolatile.", file);
- fputs ("\n\tldsfld\t", file);
- dump_type (file, TREE_TYPE (node), true, false);
- fputs (" ", file);
- if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (node) && TREE_PUBLIC (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);
-
- /* K&R C allows declaration type to be wider than the actual type */
- if (TREE_TYPE (node) != DECL_ARG_TYPE (node))
- {
- mark_referenced_type (DECL_ARG_TYPE (node));
- gen_conv (file, true, TREE_TYPE (node), DECL_ARG_TYPE (node));
- }
- 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:
- gen_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));
-
- gen_addr_expr (file, obj);
- if (TREE_THIS_VOLATILE (node))
- fputs ("\n\tvolatile.", file);
- fputs ("\n\tldfld\t", file);
- dump_type (file, fld_type, true, false);
- fputs (" ", file);
- mark_referenced_type (obj_type);
- dump_valuetype_name (file, obj_type);
- fputs ("::", file);
- dump_decl_name (file, fld);
- }
- 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);
- gcc_assert (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE);
- 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);
- gcc_assert (TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE
- || TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE);
- 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 VIEW_CONVERT_EXPR:
- {
- op0 = TREE_OPERAND (node, 0);
- gen_cil_node (file, op0);
-
- if (TREE_CODE (TREE_TYPE (op0)) == VECTOR_TYPE)
- {
- /* Convert a vector type to something. */
- tree vec_type = TREE_TYPE (op0);
- fputs ("\n\tcall ", file);
- dump_type (file, TREE_TYPE (node), false, false);
- fputs (" [gcc4net]gcc4net.", file);
- dump_vector_type (file, vec_type, false);
- fputs ("::", file);
- dump_vector_type (file, vec_type, false);
- fputs ("_to_", file);
- dump_type_eval_mode (file, TREE_TYPE (node), true, true);
- fputs (" (", file);
- dump_type (file, vec_type, false, false);
- fputs (")", file);
- }
- else if (TREE_CODE (TREE_TYPE (node)) == VECTOR_TYPE)
- {
- /* Convert something to a vector type. */
- tree vec_type = TREE_TYPE (node);
- fputs ("\n\tcall ", file);
- dump_type (file, vec_type, false, false);
- fputs (" [gcc4net]gcc4net.", file);
- dump_vector_type (file, vec_type, false);
- fputs ("::ctor (", file);
- dump_type (file, TREE_TYPE (op0), false, false);
- fputs (")", file);
- }
- else
- {
- internal_error ("\n\nVIEW_CONVERT_EXPR not supported on '%s'\n",
- tree_code_name[TREE_CODE (TREE_TYPE (node))]);
- }
- }
- break;
-
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- {
- tree cplx_type = TREE_TYPE (TREE_OPERAND (node, 0));
- op0 = TREE_OPERAND (node, 0);
-
- gcc_assert (TREE_CODE (cplx_type) == COMPLEX_TYPE);
-
- gen_cil_node (file, op0);
- fputs ("\n\tcall ", file);
- dump_type (file, TREE_TYPE (node), false, false);
- fputs (" [gcc4net]gcc4net.", file);
- dump_complex_type (file, cplx_type, false);
- fputs ("::", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("_", file);
- if (TREE_CODE (node) == REALPART_EXPR)
- fputs ("Re(", file);
- else
- fputs ("Im(", file);
- dump_complex_type(file, cplx_type, true);
- fputs (") ", file);
- stack_pop (1);
- stack_push (1);
- }
- break;
-
- case COMPLEX_EXPR:
- {
- tree cplx_type = TREE_TYPE (node);
- op0 = TREE_OPERAND (node, 0);
- op1 = TREE_OPERAND (node, 1);
- gen_cil_node (file, op0);
- gen_cil_node (file, op1);
- fputs ("\n\tcall ", file);
- dump_complex_type (file, cplx_type, true);
- fputs (" [gcc4net]gcc4net.", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("::", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("_ctor (", file);
- dump_type (file, TREE_TYPE (op0), false, false);
- fputs (", ", file);
- dump_type (file, TREE_TYPE (op0), false, false);
- fputs (")", file);
- stack_pop (2);
- stack_push (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 lhs, tree rhs)
-{
- switch (TREE_CODE (lhs))
- {
- case SSA_NAME:
- gcc_assert (0);
- break;
-
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- {
- tree cplx_op = TREE_OPERAND (lhs, 0);
- tree cplx_type = TREE_TYPE (cplx_op);
-
- gen_addr_expr (file, cplx_op);
- gen_cil_node (file, rhs);
-
- fputs ("\n\tcall instance void [gcc4net]gcc4net.", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("::", file);
- dump_complex_type(file, cplx_type, false);
- fputs ("_set_", file);
- if (TREE_CODE (lhs) == REALPART_EXPR)
- fputs ("Re(", file);
- else
- fputs ("Im(", file);
- dump_type (file, TREE_TYPE (lhs), false, false);
- fputs (")", file);
- stack_pop (2);
- }
- break;
-
- case INDIRECT_REF:
- case ARRAY_REF:
- case COMPLEX_EXPR:
- gen_addr_expr (file, lhs);
- gen_cil_node (file, rhs);
-
- if (TREE_THIS_VOLATILE (lhs))
- fputs ("\n\tvolatile.", file);
-
- if (AGGREGATE_TYPE_P (TREE_TYPE (lhs)) ||
- TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE ||
- TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
- {
- fputs ("\n\tstobj\t", file);
- dump_type (file, TREE_TYPE (lhs), true, false);
- }
- else
- {
- fputs ("\n\tstind.", file);
- print_type_suffix (file, TREE_TYPE (lhs), false);
- }
-
- stack_pop (2);
- break;
-
- case VAR_DECL:
- mark_referenced_type (TREE_TYPE (lhs));
-
- if (!DECL_FILE_SCOPE_P (lhs))
- {
- if (TREE_THIS_VOLATILE (lhs))
- {
- /* put the address of the loc on the stack */
- fputs ("\n\tldloca\t", file);
- dump_decl_name (file, lhs);
- stack_push (1);
- /* put the value */
- gen_cil_node (file, rhs);
- /* and emit a volatile stind or stobj */
- fputs ("\n\tvolatile.", file);
- if (AGGREGATE_TYPE_P (TREE_TYPE (lhs)) ||
- TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE ||
- TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
- {
- fputs ("\n\tstobj\t", file);
- dump_type (file, TREE_TYPE (lhs), true, false);
- }
- else
- {
- fputs ("\n\tstind.", file);
- print_type_suffix (file, TREE_TYPE (lhs), true);
- }
- stack_pop (2);
- }
- else
- {
- gen_cil_node (file, rhs);
- fputs ("\n\tstloc\t", file);
- dump_decl_name (file, lhs);
- stack_pop (1);
- }
- }
- else
- {
- gen_cil_node (file, rhs);
- if (TREE_THIS_VOLATILE (lhs))
- fputs ("\n\tvolatile.", file);
- fputs ("\n\tstsfld\t", file);
- dump_type (file, TREE_TYPE (lhs), true, false);
- fputs (" ", file);
- if (TARGET_GCC4NET_LINKER && DECL_EXTERNAL (lhs) && TREE_PUBLIC (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));
-
- gen_addr_expr (file, obj);
- gen_cil_node (file, rhs);
- mark_referenced_type (obj_type);
- if (TREE_THIS_VOLATILE (lhs))
- fputs ("\n\tvolatile.", file);
- fputs ("\n\tstfld\t", file);
- dump_type (file, fld_type, true, false);
- fputs (" ", file);
- dump_valuetype_name (file, obj_type);
- fputs ("::", file);
- dump_decl_name (file, fld);
- stack_pop (2);
- }
- break;
-
- default:
- fprintf (stderr, "CIL: Cannot handle lhs: ");
- debug_generic_expr (lhs);
- gcc_assert (0);
- }
-}
-
-static void
-print_incomplete_decl (FILE *file, tree t)
-{
- if (t == NULL_TREE || t == error_mark_node)
- return;
-
- if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
- return;
-
- gcc_assert (file != 0);
-
- gcc_assert (TYPE_MAIN_VARIANT (t) == t);
- gcc_assert (TYPE_NAME (t));
- gcc_assert (!COMPLETE_TYPE_P (t));
-
- fputs ("\n.class public sealed ", file);
- dump_valuetype_name (file, t);
- fputs (" extends ['mscorlib']System.ValueType\n"
- "{\n", file);
- fputs ("\t.custom instance "
- "void [gcc4net]gcc4net.C_Attributes.IncompleteType::.ctor() "
- "= (01 00 00 00)\n", file);
- fputs ("}\n", file);
-}
-
-static void
-gen_cil_bb (FILE *stream, basic_block bb)
-{
- block_stmt_iterator bsi;
- tree stmt = NULL_TREE;
-
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- gcc_assert (stack == 0);
-
- stmt = bsi_stmt (bsi);
-
- if (TARGET_EMIT_GIMPLE_COMMENTS)
- {
- fprintf (stream, "\n\t/* ");
- print_generic_expr (stream, stmt, 0);
- fprintf (stream, " */");
- }
-
- 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 = CALL_EXPR_FN (stmt);
- 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. */
- if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb))
- {
- tree label = tree_block_label (succ);
- fputs ("\n\tbr\t", stream);
- dump_label_name (stream, label);
- gcc_assert (stack == 0);
- }
- }
-}
-
-
-static void
-print_enum_decl (FILE *file, tree t)
-{
- gcc_assert (t != NULL_TREE && TREE_CODE (t) == ENUMERAL_TYPE);
-
- fputs ("\n.class ", file);
-
- if (TYPE_FILE_SCOPE_P (t)) fputs ("public ", file);
- else fputs ("private ", file);
-
- fputs ("sealed serializable ansi ", file);
- dump_valuetype_name (file, t);
- fputs (" extends ['mscorlib']System.Enum\n"
- "{\n", file);
-
- {
- int type_size = TYPE_PRECISION (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, false);
- fputs (" '", file);
- gcc_assert (TREE_CODE (TREE_PURPOSE (tmp)) == IDENTIFIER_NODE);
- fprintf (file, IDENTIFIER_POINTER (TREE_PURPOSE (tmp)));
- fprintf (file, "' = %s(%ld)\n",
- base_type_str, TREE_INT_CST_LOW (TREE_VALUE (tmp)));
- tmp = TREE_CHAIN (tmp);
- }
- }
-
- fputs ("}\n", file);
-}
-
-static void
-print_array_decl (FILE *file, tree t)
-{
- fputs ("\n.class ", file);
-
- if (TYPE_FILE_SCOPE_P (t)) fputs ("public ", file);
- else fputs ("private ", file);
-
- fputs ("explicit sealed serializable ansi ", file);
- dump_valuetype_name (file, t);
- fputs (" extends ['mscorlib']System.ValueType\n"
- "{\n"
- "\t.custom instance "
- "void [gcc4net]gcc4net.C_Attributes.ArrayType::.ctor() "
- "= (01 00 00 00)\n", file);
-
- fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t)));
- fputs ("\t.field [0] public specialname ", file);
- dump_type (file, TREE_TYPE (t), false, false);
- fputs (" 'elem__'\n"
- "}\n", file);
-}
-
-static void
-print_struct_union_decl (FILE *file, tree t)
-{
- tree tmp;
-
- fputs ("\n.class ", file);
-
- if (TYPE_FILE_SCOPE_P (t)) fputs ("public ", file);
- else fputs ("private ", file);
-
- fputs ("explicit sealed serializable ansi ", file);
- dump_valuetype_name (file, t);
- fputs (" extends ['mscorlib']System.ValueType\n"
- "{\n", file);
-
- fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t)));
-
- tmp = TYPE_FIELDS (t);
- while (tmp)
- {
-
- if (DECL_NAME (tmp) == 0 && DECL_BIT_FIELD (tmp))
- {
- /* Skip unnamed bitfields */
- }
- else
- {
- 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;
-
-
- 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, false);
- fputs (" ", file );
- dump_decl_name (file, tmp);
- fputs ("\n", file);
- }
-
- tmp = TREE_CHAIN (tmp);
- }
-
- fputs ("}\n", file);
-}
-
-static void
-print_valuetype_decl (FILE *file, tree t)
-{
- if (t == NULL_TREE || t == error_mark_node)
- return;
-
- if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
- return;
-
- gcc_assert (file != 0);
-
- gcc_assert (TYPE_MAIN_VARIANT (t) == t);
- gcc_assert (TYPE_NAME (t));
-
- if (TREE_CODE (t) == ENUMERAL_TYPE)
- print_enum_decl (file, t);
- else if (TREE_CODE (t) == ARRAY_TYPE)
- print_array_decl (file, t);
- else /* struct or union */
- print_struct_union_decl (file, t);
-
-}
-
-/* The attribute string must be less than 127 characters and contain only
- 7-bit ASCII chars. No checks though. */
-static void
-gen_string_custom_attr (FILE *stream, const char* parameter)
-{
- int i;
- int len = strlen (parameter);
-
- if (TARGET_EMIT_GIMPLE_COMMENTS)
- fprintf (stream, "\t// Custom attribute String \"%s\"\n", parameter);
-
- gcc_assert (len <= 127);
-
- fprintf (stream, "\t.custom instance void [mscorlib]System.String::.ctor(int8 *) = (01 00 %02x ", len);
- for (i=0; i < len; ++i)
- fprintf (stream, "%02x ", parameter[i]);
- fputs ("00 00)\n", stream);
-}
-
-/* Dumps the labels of a switch used for implementing a computed GOTO */
-
-static void
-gen_computed_goto (FILE *file, tree node)
-{
- tree addrs = get_label_addrs ();
- unsigned int n = TREE_VEC_LENGTH (addrs);
- unsigned int i;
-
- gen_cil_node (file, node);
- fprintf (file, "\n\tswitch (");
-
- for (i = 0; i < n; i++)
- {
- dump_label_name (file, CASE_LABEL (TREE_VEC_ELT (addrs, i)));
-
- if (i + 1 < n)
- fprintf (file, ", ");
- }
-
- fprintf (file, ")");
- stack_pop (1);
-}
-
-static void
-print_string_decl (FILE *file, tree t)
-{
- const char *str;
- int len, len_type, i;
-
- gcc_assert (TREE_CODE (t) == STRING_CST);
- str = TREE_STRING_POINTER (t);
- len = TREE_STRING_LENGTH (t);
-
- len_type = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t)))) + 1;
-
- /* 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%u' = bytearray(", get_string_cst_id (t));
- for (i=0; i < len; ++i)
- fprintf (file, "%02x ", (unsigned char)str[i]);
- for (; i < len_type; ++i)
- fputs ("00 ", file);
- fputs (")\n", file);
-
- fputs (".field private static ", file);
- dump_string_type (file, TREE_TYPE (t));
- fputs (" ", file);
- dump_string_name (file, t);
- fprintf (file, " at 'DataStr%u'\n", get_string_cst_id (t));
-}
-
-static void
-print_used_strings (FILE *file)
-{
- htab_iterator hti;
- str_ref ref;
- tree str;
- unsigned int str_size;
- ebitmap used_stringtypes;
- ebitmap_iterator ebi;
-
- used_stringtypes = ebitmap_alloc (1);
-
- FOR_EACH_HTAB_ELEMENT (referenced_strings_htab (), ref, str_ref, hti)
- {
- str = ref->cst;
- str_size = tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (str))),
- 1) + 1;
- print_string_decl (file, str);
- ebitmap_set_bit (used_stringtypes, str_size);
- }
-
- EXECUTE_IF_SET_IN_EBITMAP(used_stringtypes, 0, str_size, ebi)
- {
- fprintf (file,
- "\n.class public explicit sealed serializable ansi '?string_type?%d'"
- " extends ['mscorlib']System.ValueType\n"
- "{\n"
- "\t.custom instance "
- "void [gcc4net]gcc4net.C_Attributes.ConstStringType::.ctor() "
- "= (01 00 00 00)\n"
- "\t.size %d\n"
- "\t.field [0] public specialname int8 'elem__'\n"
- "}\n", str_size, str_size);
- }
-
- ebitmap_free (used_stringtypes);
-}
-
-/* Emit the valuetypes referenced by the current function. */
-
-static void
-print_referenced_types (FILE *file)
-{
- /* 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. */
-
- htab_iterator hti;
- tree type;
- struct pointer_set_t *emitted_types = pointer_set_create ();
- struct pointer_set_t *incomplete_types = pointer_set_create ();
-
- FOR_EACH_HTAB_ELEMENT (referenced_types_htab (), type, tree, hti)
- {
- if (COMPLETE_TYPE_P (type))
- {
- tree type_name = TYPE_NAME (type);
-
- gcc_assert (DECL_P (type_name)
- || TREE_CODE (type_name) == IDENTIFIER_NODE);
-
- if (TREE_CODE (type_name) != IDENTIFIER_NODE)
- type_name = DECL_NAME (type_name);
-
- if (!pointer_set_contains (emitted_types, type_name))
- {
- print_valuetype_decl (file, type);
- pointer_set_insert (emitted_types, type_name);
- }
- }
- else if (TARGET_GCC4NET_LINKER)
- pointer_set_insert (incomplete_types, type);
- }
-
- /* emit incomplete types */
- if (TARGET_GCC4NET_LINKER)
- {
- struct pointer_set_iter_t it = pointer_set_begin (incomplete_types);
- while (!POINTER_SET_ITER_IS_END (it))
- {
- tree type = (tree)POINTER_SET_ITER_ELEM (it);
-
- tree type_name = TYPE_NAME (type);
- gcc_assert (DECL_P (type_name)
- || TREE_CODE (type_name) == IDENTIFIER_NODE);
-
- if (TREE_CODE (type_name) != IDENTIFIER_NODE)
- type_name = DECL_NAME (type_name);
-
- if (!pointer_set_contains (emitted_types, type_name))
- {
- print_incomplete_decl (file, type);
- pointer_set_insert (emitted_types, type_name);
- }
-
- it = pointer_set_next (incomplete_types, it);
- }
- }
-
- pointer_set_destroy (incomplete_types);
- pointer_set_destroy (emitted_types);
-}
-
-static void
-print_pinvoke_function (FILE *file, tree fun)
-{
- tree fun_type = TREE_TYPE (fun);
- struct fnct_attr attributes;
-
- decode_function_attrs (fun, &attributes);
-
- fputs (".method ", file);
-
- if (TREE_PUBLIC (fun)) fputs ("public ", file);
- else fputs ("private ", file);
-
- fprintf (file, "static pinvokeimpl(\"%s\"", attributes.pinvoke_assembly);
-
- if (attributes.pinvoke_fname)
- fprintf (file, " as \"%s\"", attributes.pinvoke_fname);
-
- fputs (") ", file);
-
- DECL_EXTERNAL (fun) = 0;
- dump_fun_type (file, fun_type, fun, NULL, false);
-
- fputs (" cil managed {}\n", file);
-}
-
-/* Emit the PINVOKES referenced in this compilation unit. */
-
-static void
-print_referenced_pinvokes (FILE *file)
-{
- htab_iterator hti;
- tree pinvoke;
-
- FOR_EACH_HTAB_ELEMENT (pinvokes_htab (), pinvoke, tree, hti)
- {
- print_pinvoke_function (file, pinvoke);
- }
-}
-
-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 3"
- "\n\t.locals (int32 'argc', int8** 'argv', int8** 'env')", 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;
-
- case 3:
- fputs ("\n\tldloca\t'argc'"
- "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)"
- "\n\tstloc\t'argv'"
- "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetEnvVars()"
- "\n\tstloc\t'env'"
- "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()"
- "\n\tldloc\t'argc'"
- "\n\tldloc\t'argv'"
- "\n\tldloc\t'env'"
- "\n\tcall\tint32 main(int32, int8**, 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)
-{
- block_stmt_iterator bsi;
- bool varargs = FALSE;
- tree args;
-
- if (!TARGET_NO_STLOC_LDLOC_REMOVAL)
- remove_stloc_ldloc ();
-
- FOR_EACH_BB (bb)
- {
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- tree stmt = bsi_stmt (bsi);
-
- /* Record the address taken labels. */
- if (TREE_CODE (stmt) == LABEL_EXPR)
- {
- tree label = LABEL_EXPR_LABEL (stmt);
- /* Check if the label has its address taken. */
- if (FORCED_LABEL (label))
- record_addr_taken_label (label);
- }
- }
- }
-
- /* Make sure that every bb has a label */
- FOR_EACH_BB (bb)
- {
- tree_block_label (bb);
- }
-
- stack_reset ();
- max_stack = 0;
-
- if (TARGET_OPENSYSTEMC)
- if (MAIN_NAME_P (DECL_NAME (current_function_decl)))
- 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, false);
- fprintf (stream, " '%s' (",
- lang_hooks.decl_printable_name (current_function_decl, 1));
-
- args = DECL_ARGUMENTS (current_function_decl);
-
- if (cfun->static_chain_decl)
- {
- dump_type (stream, DECL_ARG_TYPE (cfun->static_chain_decl), true, true);
- fputs (" ", stream);
- dump_decl_name (stream, cfun->static_chain_decl);
- if (args)
- fputs (", ", stream);
- }
-
-
- while (args)
- {
- dump_type (stream, DECL_ARG_TYPE (args), true, 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{", stream);
-
- fputs ("\n\t.locals (", 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, false);
- fputs (" ", stream);
- dump_decl_name (stream, var);
- }
- }
- }
- fputs (")\n", stream);
-
- if (DECL_STATIC_CONSTRUCTOR (current_function_decl))
- {
- /* For the time being this attribute is a String. */
- gen_string_custom_attr (stream, "initfun");
-
- if (TARGET_GCC4NET_LINKER)
- fputs ("\t.custom instance "
- "void [gcc4net]gcc4net.C_Attributes.Initializer::.ctor() "
- "= (01 00 00 00)\n", stream);
- else if (TARGET_OPENSYSTEMC)
- fputs ("\t.custom instance "
- "void ['OpenSystem.C']'OpenSystem.C'.InitializerAttribute::.ctor() "
- "= (01 00 00 00)\n", stream);
- }
-
- {
- struct fnct_attr attributes;
- decode_function_attrs (current_function_decl, &attributes);
- if (attributes.cusattr_string)
- gen_string_custom_attr (stream, attributes.cusattr_string);
- }
-
- FOR_EACH_BB (bb)
- {
-
- if (TARGET_EMIT_GIMPLE_COMMENTS)
- {
- fprintf (stream, "\n\n\t/* Basic block frequency: %d */",
- bb->frequency * 100 / BB_FREQ_MAX);
- }
-
- gen_cil_bb (stream, bb);
-
- if (TARGET_EMIT_GIMPLE_COMMENTS)
- {
- edge e;
- edge_iterator ei;
-
- fputs ("\n\t/* Edge probabilities: ", stream);
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- dump_entry_label_name (stream, e->dest);
- fprintf (stream, ": %d ", e->probability * 100 / REG_BR_PROB_BASE);
- }
- fputs ("*/", stream);
- }
- }
-
- if (TARGET_EMIT_JIT_COMPILATION_HINTS)
- {
- basic_block_frequency_emit (stream);
- branch_probability_emit_and_reset (stream);
- }
-
- 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;
-}
-
-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, false);
- fputs (" ", stream);
- dump_decl_name (stream, decl);
- fputs ("\n", stream);
-
- if (init && init != error_mark_node)
- record_ctor (decl);
-
- TREE_ASM_WRITTEN (decl) = 1;
- }
-}
-
-void
-gen_cil_init (void)
-{
- FILE *stream = asm_out_file;
-
-
- if (TARGET_GCC4NET_LINKER)
- {
- fputs (".assembly extern mscorlib {}\n"
- ".assembly extern gcc4net {}\n"
- ".assembly extern ExternalAssembly {}\n", stream);
- fprintf (stream, ".assembly '%s' {\n", aux_base_name);
- fputs ("\t.custom instance "
- "void [gcc4net]gcc4net.C_Attributes.CObjectFile::.ctor() "
- "= (01 00 00 00)\n"
- "}\n", stream);
- fprintf (stream, ".module '%s'\n", aux_base_name);
- }
- else if (TARGET_OPENSYSTEMC)
- {
- fputs (".assembly extern gcc4net {}\n"
- ".module '<Module>'\n"
- ".custom instance "
- "void ['OpenSystem.C']'OpenSystem.C'.ModuleAttribute::.ctor() "
- "= (01 00 00 00)\n", stream);
- }
-}
-
-void
-gen_cil_fini (void)
-{
- FILE *stream = asm_out_file;
-
- create_init_method ();
- print_used_strings (stream);
- print_referenced_types (stream);
- print_referenced_pinvokes (stream);
-}
-
-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 */
-};
-
-/* This function is mostly a copy of the last part of 'gen_cil'. */
-static void
-gen_cil_vcg (FILE *vcg_stream)
-{
- edge_iterator ei;
- const char *fun_name = lang_hooks.decl_printable_name (current_function_decl, 1);
- edge e;
- int i=0;
-
- fprintf (vcg_stream, "graph: {\n");
- fprintf (vcg_stream, "title: \"%s\"\n", fun_name);
- fprintf (vcg_stream, "node: { title: \"%sBB%d\" label: \"ENTRY %s\" }\n",
- fun_name, ENTRY_BLOCK, fun_name);
- fprintf (vcg_stream, "node: { title: \"%sBB%d\" label: \"EXIT\" }\n",
- fun_name, EXIT_BLOCK);
- fprintf (vcg_stream, "edge:{sourcename: \"%sBB%d\" targetname: \"%sBB%d\"}\n",
- fun_name, ENTRY_BLOCK,
- fun_name, single_succ (ENTRY_BLOCK_PTR)->index);
-
- FOR_EACH_BB (bb)
- {
- fprintf (vcg_stream, "node: { title: \"%sBB%d\" label: \"(BB%d, pos: %d)",
- fun_name, bb->index, bb->index, i++);
-
- if (bb->loop_depth)
- fprintf (vcg_stream, " LOOP DEPTH %d ", bb->loop_depth);
-
- gen_cil_bb (vcg_stream, bb);
-
- fprintf (vcg_stream, "\" }\n"); /* close 'label' clause */
-
- for (ei = ei_start (bb->succs); ei_cond (ei, &e); ei_next (&ei))
- {
- if (e->flags & EDGE_DFS_BACK)
- fprintf (vcg_stream, "backedge: { color: red");
- else if (e->flags & EDGE_LOOP_EXIT)
- fprintf (vcg_stream, "edge: { color: blue");
- else
- fprintf (vcg_stream, "edge: {");
-
- fprintf (vcg_stream, " label:\"%d", e->probability);
-
- if (e->flags & EDGE_LOOP_EXIT)
- fprintf (vcg_stream, " loop_exit");
-
- fprintf (vcg_stream, "\"");
-
- fprintf (vcg_stream,
- " sourcename: \"%sBB%d\" targetname: \"%sBB%d\" }\n",
- fun_name, bb->index, fun_name, e->dest->index);
- }
- }
- fprintf (vcg_stream, "}\n");
-}
-
-void
-cil_vcg_init (void)
-{
- if (TARGET_EMIT_VCG)
- fputs ("graph: {\n"
- "display_edge_labels: yes\n", stdout);
-}
-
-void
-cil_vcg_fini (void)
-{
- if (TARGET_EMIT_VCG)
- fputs ("}\n", stdout);
-}
-
-static bool
-cil_vcg_gate (void)
-{
- return TARGET_EMIT_VCG && current_function_decl != NULL;
-}
-
-static unsigned int
-cil_vcg (void)
-{
- gen_cil_vcg(stdout);
-
- return 0;
-}
-
-/* Define the parameters of the CIL_VCG pass. */
-
-struct tree_opt_pass pass_cil_vcg =
-{
- "cil_vcg", /* name */
- cil_vcg_gate, /* gate */
- cil_vcg, /* 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/gen-cil.h b/gcc/config/cil32/gen-cil.h
deleted file mode 100644
index 954107b9546..00000000000
--- a/gcc/config/cil32/gen-cil.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* 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:
-Andrea C. Ornstein <andrea.ornstein@st.com>
-Erven Rohou <erven.rohou@st.com>
-*/
-
-#ifndef GEN_CIL_H
-#define GEN_CIL_H
-
-#include "tree.h"
-
-void
-make_decl_cil (FILE *, tree);
-
-void
-gen_cil_init (void);
-void
-gen_cil_fini (void);
-
-void
-cil_vcg_init (void);
-void
-cil_vcg_fini (void);
-
-
-/* Defined in rm_ldloc.c */
-void remove_stloc_ldloc (void);
-
-#endif /* GEN_CIL_H */
diff --git a/gcc/config/cil32/gimple-to-cil.c b/gcc/config/cil32/gimple-to-cil.c
new file mode 100644
index 00000000000..32c25388bcc
--- /dev/null
+++ b/gcc/config/cil32/gimple-to-cil.c
@@ -0,0 +1,3395 @@
+/* GIMPLE to CIL conversion pass.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "errors.h"
+#include "ggc.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "pointer-set.h"
+#include "cil-builtins.h"
+#include "cil-refs.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+#include "emit-cil.h"
+
+/******************************************************************************
+ * Globals *
+ ******************************************************************************/
+
+/* Return variable for pre-C99 functions which contain VOID return statements
+ even though they are declared to return a non-VOID value. */
+static tree res_var;
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static void gen_integer_cst (cil_stmt_iterator *, tree);
+static void gen_addr_expr (cil_stmt_iterator *, tree);
+static void gen_array_ref_addr_expr (cil_stmt_iterator *, tree);
+static void gen_scalar_ld_st_ind (cil_stmt_iterator *, tree, bool, bool);
+static inline void gen_scalar_stind (cil_stmt_iterator *, tree, bool);
+static inline void gen_scalar_ldind (cil_stmt_iterator *, tree, bool);
+static void gen_ldind (cil_stmt_iterator *, tree, bool);
+static void gen_stind (cil_stmt_iterator *, tree, bool);
+static void gen_bit_field_modify_expr (cil_stmt_iterator *, tree, tree);
+static void gen_target_mem_ref_modify_expr (cil_stmt_iterator *, tree, tree);
+static void gen_vector_bitfield_ref_modify_expr (cil_stmt_iterator *,
+ tree, tree);
+static void gen_modify_expr (cil_stmt_iterator *, tree, tree);
+static void gen_goto_expr (cil_stmt_iterator *, tree);
+static void gen_cond_expr (cil_stmt_iterator *, tree);
+static void gen_switch_expr (cil_stmt_iterator *, tree);
+static void gen_vector_constructor (cil_stmt_iterator *, tree);
+static void gen_builtin_va_start (cil_stmt_iterator *, tree);
+static void gen_builtin_va_end (cil_stmt_iterator *, tree);
+static void gen_builtin_va_copy (cil_stmt_iterator *, tree);
+static bool gen_call_builtin (cil_stmt_iterator *, tree, tree);
+static void gen_call_expr (cil_stmt_iterator *, tree);
+static tree gen_expr_copy (cil_stmt_iterator *, tree);
+static void gen_bit_and_expr (cil_stmt_iterator *, tree);
+static void gen_compare_expr (cil_stmt_iterator *, tree);
+static void gen_minmax_expr (cil_stmt_iterator *, tree);
+static void gen_abs_expr (cil_stmt_iterator *, tree);
+static void gen_var_decl (cil_stmt_iterator *, tree);
+static void gen_bit_field_comp_ref (cil_stmt_iterator *, tree);
+static void gen_comp_ref (cil_stmt_iterator *, tree);
+static void gen_vector_bitfield_ref (cil_stmt_iterator *, tree);
+static void gen_bit_field_ref (cil_stmt_iterator *, tree);
+static void gen_truth_expr (cil_stmt_iterator *, tree);
+static void gen_target_mem_ref (cil_stmt_iterator *, tree);
+static void gen_view_convert_expr (cil_stmt_iterator *, tree);
+static void gen_complex_part_expr (cil_stmt_iterator *, tree);
+static void gen_complex (cil_stmt_iterator *, tree, tree, tree);
+static enum cil_opcode conv_opcode_from_type (tree);
+static tree get_integer_type (unsigned int, bool);
+static void gen_integral_conv (cil_stmt_iterator *, tree, tree);
+static void gen_conv (cil_stmt_iterator *, bool, tree, tree);
+static void gen_rotate (cil_stmt_iterator *, tree);
+static void gimple_to_cil_node (cil_stmt_iterator *, tree);
+static void process_labels (void);
+static void process_initializers (void);
+
+/******************************************************************************
+ * GIMPLE/generic to CIL conversion functions *
+ ******************************************************************************/
+
+/* Load the value of the integer constant CST on the stack. The constant will
+ be 32-bits or 64-bits wide depending on the type of CST. The generated
+ statement will be appended to the current function's CIL code using the CSI
+ iterator. */
+
+static void
+gen_integer_cst (cil_stmt_iterator *csi, tree cst)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (TREE_TYPE (cst)), 1);
+ enum cil_opcode opcode;
+ cil_stmt stmt;
+
+ opcode = (size <= 32) ? CIL_LDC_I4 : CIL_LDC_I8;
+ stmt = cil_build_stmt_arg (opcode, cst);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generates a sequence which computes the address of the object described by
+ OBJ and pushes it on top of the stack. The generated statements are
+ appended to the current function's CIL code using the CSI iterator. */
+
+static void
+gen_addr_expr (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+
+ switch (TREE_CODE (node))
+ {
+ case STRING_CST:
+ node = mark_referenced_string (node);
+ stmt = cil_build_stmt_arg (CIL_LDSFLDA, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case VAR_DECL:
+ case RESULT_DECL:
+ /* Function local static variables are promoted to global variables. */
+ if (!DECL_FILE_SCOPE_P (node) && !TREE_STATIC (node))
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, node);
+ else
+ stmt = cil_build_stmt_arg (CIL_LDSFLDA, node);
+
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ if (TREE_CODE (TREE_TYPE (node)) == ARRAY_TYPE)
+ {
+ stmt = cil_build_stmt (CIL_CONV_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case PARM_DECL:
+ stmt = cil_build_stmt_arg (CIL_LDARGA, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ if (TREE_CODE (TREE_TYPE (node)) == ARRAY_TYPE)
+ {
+ stmt = cil_build_stmt (CIL_CONV_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case FUNCTION_DECL:
+ stmt = cil_build_stmt_arg (CIL_LDFTN, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case LABEL_DECL:
+ {
+ /* We cannot emit the address of the label in CIL, so we map each
+ label to an ID and emit the ID. The GOTO will then be implemented
+ with a switch based on that ID. The ID is simply the position in
+ the list of all address taken labels. */
+
+ tree id = get_addr_taken_label_id (node);
+ gen_integer_cst (csi, id);
+ }
+ break;
+
+ case INDIRECT_REF:
+ gimple_to_cil_node (csi, GENERIC_TREE_OPERAND (node, 0));
+ break;
+
+ case ARRAY_REF:
+ gen_array_ref_addr_expr (csi, node);
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree obj = GENERIC_TREE_OPERAND (node, 0);
+ tree fld = GENERIC_TREE_OPERAND (node, 1);
+ tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj));
+
+ gcc_assert (!DECL_BIT_FIELD (fld));
+
+ gen_addr_expr (csi, obj);
+ stmt = cil_build_stmt_arg (CIL_LDFLDA, fld);
+ mark_referenced_type (obj_type);
+ /* Some statements might have been added */
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ gen_addr_expr (csi, GENERIC_TREE_OPERAND (node, 0));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Generates the address of an ARRAY_REF expression. The generated statements
+ are appended to the current funcion's CIL code using the CSI iterator. */
+
+static void
+gen_array_ref_addr_expr (cil_stmt_iterator *csi, tree node)
+{
+ HOST_WIDE_INT bitsize = 0;
+ HOST_WIDE_INT bitpos = 0;
+ tree offset = NULL_TREE;
+ enum machine_mode mode;
+ int unsignedp = 0;
+ int volatilep = 0;
+ cil_stmt stmt;
+ tree ref;
+
+ ref = get_inner_reference (node, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ gen_addr_expr (csi, ref);
+
+ if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE)
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+
+ if (bitpos != 0)
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node, bitpos / BITS_PER_UNIT));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (offset != NULL_TREE)
+ {
+ gimple_to_cil_node (csi, offset);
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates a load/store indirect statement for the scalar type specified by
+ TYPE. If STORE is true then a store is generated, otherwise a load.
+ The statement is made volatile if VOLAT is true. The generated statements
+ are appended to the current function's CIL code using the CSI iterator. */
+
+static void
+gen_scalar_ld_st_ind (cil_stmt_iterator *csi, tree type, bool store, bool volat)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ enum cil_opcode opcode;
+ cil_stmt stmt;
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ if (TYPE_UNSIGNED (type))
+ {
+ switch (size)
+ {
+ case 8: opcode = store ? CIL_STIND_I1 : CIL_LDIND_U1; break;
+ case 16: opcode = store ? CIL_STIND_I2 : CIL_LDIND_U2; break;
+ case 32: opcode = store ? CIL_STIND_I4 : CIL_LDIND_U4; break;
+ case 64: opcode = store ? CIL_STIND_I8 : CIL_LDIND_U8; break;
+ default:
+ internal_error ("Unsupported integer size "
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 8: opcode = store ? CIL_STIND_I1 : CIL_LDIND_I1; break;
+ case 16: opcode = store ? CIL_STIND_I2 : CIL_LDIND_I2; break;
+ case 32: opcode = store ? CIL_STIND_I4 : CIL_LDIND_I4; break;
+ case 64: opcode = store ? CIL_STIND_I8 : CIL_LDIND_I8; break;
+ default:
+ internal_error ("Unsupported integer size "
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ }
+ else if (POINTER_TYPE_P (type))
+ opcode = store ? CIL_STIND_I : CIL_LDIND_I;
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ switch (size)
+ {
+ case 32: opcode = store ? CIL_STIND_R4 : CIL_LDIND_R4; break;
+ case 64: opcode = store ? CIL_STIND_R8 : CIL_LDIND_R8; break;
+ default:
+ internal_error ("Unsupported floating point size "
+ HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+ }
+ }
+ else
+ gcc_unreachable ();
+
+ stmt = cil_build_stmt (opcode);
+ cil_set_prefix_volatile (stmt, volat);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generates a load indirect statement for the scalar type specified by TYPE.
+ The statement is made volatile if VOLAT is true. The generated statements
+ are appended to the current function's CIL code using the CSI iterator. */
+
+static inline void
+gen_scalar_ldind (cil_stmt_iterator *csi, tree type, bool volat)
+{
+ gen_scalar_ld_st_ind (csi, type, false, volat);
+}
+
+/* Generates a store indirect statement for the scalar type specified by TYPE.
+ The statement is made volatile if VOLAT is true. The generated statements
+ are appended to the current function's CIL code using the CSI iterator. */
+
+static inline void
+gen_scalar_stind (cil_stmt_iterator *csi, tree type, bool volat)
+{
+ gen_scalar_ld_st_ind (csi, type, true, volat);
+}
+
+/* Generate a load indirect statement for the type specified by TYPE. The
+ load is made volatile if VOLAT is true. The generated statements are
+ appended to the current function's CIL code using the CSI iterator. */
+
+static void
+gen_ldind (cil_stmt_iterator *csi, tree type, bool volat)
+{
+ cil_stmt stmt;
+
+ if (AGGREGATE_TYPE_P (type) ||
+ TREE_CODE (type) == COMPLEX_TYPE ||
+ TREE_CODE (type) == VECTOR_TYPE)
+ {
+ stmt = cil_build_stmt_arg (CIL_LDOBJ, type);
+ cil_set_prefix_volatile (stmt, volat);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ gen_scalar_ldind (csi, type, true);
+}
+
+/* Generate a store indirect statement for the type specified by TYPE. The
+ store is made volatile if VOLAT is true. The generated statements are
+ appended to the current function's CIL code using the CSI iterator. */
+
+static void
+gen_stind (cil_stmt_iterator *csi, tree type, bool volat)
+{
+ cil_stmt stmt;
+
+ if (AGGREGATE_TYPE_P (type) ||
+ TREE_CODE (type) == COMPLEX_TYPE ||
+ TREE_CODE (type) == VECTOR_TYPE)
+ {
+ stmt = cil_build_stmt_arg (CIL_STOBJ, type);
+ cil_set_prefix_volatile (stmt, volat);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ gen_scalar_stind (csi, type, true);
+}
+
+/* Generates a GIMPLE_MODIFY_STMT, MODIFY_EXPR or INIT_EXPR with a bit field as
+ its left hand side operand. The left hand side operand is pointed by LHS
+ abd the right hand side one by RHS. The generated statements are appended
+ to the current function's CIL code using the CSI iterator. */
+
+static void
+gen_bit_field_modify_expr (cil_stmt_iterator *csi, tree lhs, tree rhs)
+{
+ HOST_WIDE_INT bit_size = 0;
+ HOST_WIDE_INT bit_pos = 0;
+ HOST_WIDE_INT cont_off;
+ HOST_WIDE_INT cont_size = 8;
+ tree offset = NULL_TREE;
+ enum machine_mode mode;
+ int unsignedp = 0;
+ int volatilep = 0;
+ cil_stmt stmt;
+ tree cont_type;
+ tree mask_cst, shift_cst;
+ tree ref;
+ tree folded_rhs, tmp;
+
+ /* TODO: Add support for packed bit-fields crossing 64-bit boundaries.
+ TODO: Add support for big-endian targets. */
+
+ /* Get the object base address and emit it. */
+ ref = get_inner_reference (lhs, &bit_size, &bit_pos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ gen_addr_expr (csi, ref);
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+
+ /* Calculate the container size. */
+ while ((bit_pos % cont_size + bit_size) > cont_size)
+ cont_size *= 2;
+
+ cont_type = get_integer_type (cont_size, true);
+ cont_off = bit_pos % cont_size;
+
+ /* Calculate the container address if needed. */
+ if ((bit_pos - cont_off) / BITS_PER_UNIT != 0)
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node,
+ (bit_pos - cont_off) / BITS_PER_UNIT));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (offset != NULL_TREE)
+ {
+ gimple_to_cil_node (csi, offset);
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* Duplicate the container address, we will need it later. */
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* Load the container. */
+ gen_scalar_ldind (csi, cont_type, volatilep);
+
+ /* Compute the mask to be applied to the container. */
+ shift_cst = build_int_cst (intSI_type_node, cont_off);
+ mask_cst = size_binop (LSHIFT_EXPR, build_int_cst (cont_type, 1),
+ build_int_cst (intSI_type_node, bit_size));
+ mask_cst = size_binop (MINUS_EXPR, mask_cst, build_int_cst (cont_type, 1));
+ mask_cst = size_binop (LSHIFT_EXPR, mask_cst, shift_cst);
+
+ /* Apply the mask to the container. */
+ gen_integer_cst (csi, size_binop (BIT_XOR_EXPR, mask_cst,
+ build_int_cst (cont_type, -1)));
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* Put the new value on the stack. If the rhs is a constant fold the
+ shift & mask operations, if it is not copy it and convert it in the
+ container type */
+ folded_rhs = fold_binary_to_constant (LSHIFT_EXPR, cont_type,
+ fold_convert (cont_type, rhs),
+ shift_cst);
+
+ if (folded_rhs != NULL_TREE)
+ {
+ folded_rhs = fold_binary_to_constant (BIT_AND_EXPR, cont_type,
+ fold_convert (cont_type,
+ folded_rhs),
+ mask_cst);
+ }
+
+ if (folded_rhs != NULL_TREE)
+ {
+ if (!integer_zerop (folded_rhs))
+ gimple_to_cil_node (csi, folded_rhs);
+ }
+ else
+ {
+ tmp = rhs;
+
+ /* Strip redundant conversions. */
+ while (TREE_CODE (tmp) == NOP_EXPR && INTEGRAL_TYPE_P (TREE_TYPE (tmp)))
+ tmp = GENERIC_TREE_OPERAND (tmp, 0);
+
+ gimple_to_cil_node (csi, tmp);
+
+ if (TYPE_PRECISION (TREE_TYPE (tmp)) > 32 && cont_size <= 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_U4);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else if (TYPE_PRECISION (TREE_TYPE (tmp)) <= 32 && cont_size > 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_U8);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (!integer_zerop (shift_cst))
+ {
+ gen_integer_cst (csi, shift_cst);
+ stmt = cil_build_stmt (CIL_SHL);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (cont_off + bit_size != cont_size)
+ {
+ gen_integer_cst (csi, mask_cst);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+
+ if (folded_rhs == NULL_TREE || !integer_zerop (folded_rhs))
+ {
+ /* Insert the new value inside the container. */
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* Store the container in memory. */
+ gen_scalar_stind (csi, cont_type, volatilep);
+}
+
+/* Generates a MODIFY_EXPR using a TARGET_MEM_REF node as its LHS operand. */
+
+static void
+gen_target_mem_ref_modify_expr (cil_stmt_iterator *csi, tree lhs, tree rhs)
+{
+ tree type = TREE_TYPE (lhs);
+ tree ptr_type = build_pointer_type (type);
+
+ gimple_to_cil_node (csi, tree_mem_ref_addr (ptr_type, lhs));
+ gimple_to_cil_node (csi, rhs);
+ gen_stind (csi, type, TREE_THIS_VOLATILE (lhs));
+}
+
+/* Generates a MODIFY_EXPR using a BIT_FIELD_REF scalar-element vector access
+ as its LHS operand. */
+
+static void
+gen_vector_bitfield_ref_modify_expr (cil_stmt_iterator *csi, tree lhs, tree rhs)
+{
+ cil_stmt stmt;
+ tree cst;
+
+ gen_addr_expr (csi, GENERIC_TREE_OPERAND (lhs, 0));
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+ cst = size_binop (TRUNC_DIV_EXPR, GENERIC_TREE_OPERAND (lhs, 2),
+ bitsize_unit_node);
+
+ if (!integer_zerop (cst))
+ {
+ gen_integer_cst (csi, fold_convert (intSI_type_node, cst));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ gimple_to_cil_node (csi, rhs);
+ gen_stind (csi, TREE_TYPE (rhs), TREE_THIS_VOLATILE (lhs));
+}
+
+/* Converts a GIMPLE_MODIFY_STMT, MODIFY_EXPR or INIT_EXPR into the CIL form
+ eventually expanding the arguments if they cannot be converted directly. The
+ left hand side operand is pointed by LHS and the right hand side one by RHS.
+ The generated statements are appended to the current function's CIL code
+ using the CSI iterator. */
+
+static void
+gen_modify_expr (cil_stmt_iterator *csi, tree lhs, tree rhs)
+{
+ cil_stmt stmt;
+
+ switch (TREE_CODE (lhs))
+ {
+ case VAR_DECL:
+ case RESULT_DECL:
+ mark_referenced_type (TREE_TYPE (lhs));
+
+ if (!DECL_FILE_SCOPE_P (lhs) && !TREE_STATIC (lhs))
+ {
+ if (TREE_THIS_VOLATILE (lhs))
+ {
+ /* put the address of the loc on the stack */
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, lhs);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ /* put the value on the stack */
+ gimple_to_cil_node (csi, rhs);
+ /* and emit a volatile stind or stobj */
+ gen_stind (csi, TREE_TYPE (lhs), true);
+ }
+ else
+ {
+ /* put the value on the stack */
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (CIL_STLOC, lhs);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else
+ {
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (CIL_STSFLD, lhs);
+ cil_set_prefix_volatile (stmt, TREE_THIS_VOLATILE (lhs));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case PARM_DECL:
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (CIL_STARG, lhs);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ gen_addr_expr (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+ gen_stind (csi, TREE_TYPE (rhs), TREE_THIS_VOLATILE (lhs));
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree obj = TREE_OPERAND (lhs, 0);
+ tree fld = TREE_OPERAND (lhs, 1);
+
+ mark_referenced_type (TYPE_MAIN_VARIANT (TREE_TYPE (obj)));
+
+ if (DECL_BIT_FIELD (fld))
+ gen_bit_field_modify_expr (csi, lhs, rhs);
+ else
+ {
+ /* put the value on the stack */
+ gen_addr_expr (csi, obj);
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (CIL_STFLD, fld);
+ cil_set_prefix_volatile (stmt, TREE_THIS_VOLATILE (lhs));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ break;
+
+ case TARGET_MEM_REF:
+ gen_target_mem_ref_modify_expr (csi, lhs, rhs);
+ break;
+
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ gen_addr_expr (csi, GENERIC_TREE_OPERAND (lhs, 0));
+
+ if (TREE_CODE (lhs) == IMAGPART_EXPR)
+ {
+ gen_integer_cst (csi,
+ fold_convert (intSI_type_node,
+ TYPE_SIZE_UNIT (TREE_TYPE (lhs))));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ gimple_to_cil_node (csi, rhs);
+ gen_scalar_stind (csi, TREE_TYPE (lhs), TREE_THIS_VOLATILE (lhs));
+ break;
+
+ case BIT_FIELD_REF:
+ if (TREE_CODE (TREE_TYPE (GENERIC_TREE_OPERAND (lhs, 0))) == VECTOR_TYPE)
+ gen_vector_bitfield_ref_modify_expr (csi, lhs, rhs);
+ else
+ gcc_unreachable ();
+
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Generates a GOTO_EXPR including the emulation needed for computed GOTOs. */
+
+static void
+gen_goto_expr (cil_stmt_iterator *csi, tree node)
+{
+ tree label_decl = GOTO_DESTINATION (node);
+ cil_stmt stmt;
+
+ if (computed_goto_p (node))
+ {
+ /* This is a goto to the address of a label. Labels have
+ been numbered, and we emit a switch based on that ID. */
+ gimple_to_cil_node (csi, label_decl);
+ stmt = cil_build_switch (get_label_addrs());
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ basic_block dest_bb = label_to_block (label_decl);
+
+ if (csi_bb (*csi)->next_bb != dest_bb)
+ {
+ stmt = cil_build_stmt_arg (CIL_BR, label_decl);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+}
+
+/* Generates a conditional expression. */
+
+static void
+gen_cond_expr (cil_stmt_iterator *csi, tree node)
+{
+ edge true_edge, false_edge;
+ tree label_then, label_else, cond, lhs, rhs, type;
+ basic_block dest_bb;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ bool uns;
+
+ extract_true_false_edges_from_block (csi_bb (*csi), &true_edge, &false_edge);
+ label_then = tree_block_label (true_edge->dest);
+ label_else = tree_block_label (false_edge->dest);
+
+ cond = COND_EXPR_COND (node);
+
+ if (DECL_P (cond))
+ {
+ gimple_to_cil_node (csi, cond);
+ gimple_to_cil_node (csi,
+ fold_convert (TREE_TYPE (cond), integer_zero_node));
+ stmt = cil_build_stmt_arg (CIL_BNE_UN, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ lhs = TREE_OPERAND (cond, 0);
+ rhs = TREE_OPERAND (cond, 1);
+ type = TREE_TYPE (lhs);
+
+ switch (TREE_CODE (cond))
+ {
+ case EQ_EXPR:
+ case NE_EXPR:
+ if (tree_int_cst_equal (lhs, integer_zero_node)
+ && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
+ {
+ opcode = TREE_CODE (cond) == EQ_EXPR ? CIL_BRFALSE : CIL_BRTRUE;
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (opcode, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else if (tree_int_cst_equal (rhs, integer_zero_node)
+ && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
+ {
+ opcode = TREE_CODE (cond) == EQ_EXPR ? CIL_BRFALSE : CIL_BRTRUE;
+ gimple_to_cil_node (csi, lhs);
+ stmt = cil_build_stmt_arg (opcode, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ opcode = TREE_CODE (cond) == EQ_EXPR ? CIL_BEQ : CIL_BNE_UN;
+ gimple_to_cil_node (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt_arg (opcode, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case LE_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case GT_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ uns = TYPE_UNSIGNED (type);
+ gimple_to_cil_node (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+
+ switch (TREE_CODE (cond))
+ {
+ case LE_EXPR: opcode = uns ? CIL_BLE_UN : CIL_BLE; break;
+ case LT_EXPR: opcode = uns ? CIL_BLT_UN : CIL_BLT; break;
+ case GE_EXPR: opcode = uns ? CIL_BGE_UN : CIL_BGE; break;
+ case GT_EXPR: opcode = uns ? CIL_BGT_UN : CIL_BGT; break;
+ case UNLT_EXPR: opcode = CIL_BLT_UN; break;
+ case UNLE_EXPR: opcode = CIL_BLE_UN; break;
+ case UNGT_EXPR: opcode = CIL_BGT_UN; break;
+ case UNGE_EXPR: opcode = CIL_BGE_UN; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ stmt = cil_build_stmt_arg (opcode, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ gimple_to_cil_node (csi, lhs);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ opcode = (TREE_CODE (cond) == ORDERED_EXPR) ? CIL_BRTRUE : CIL_BRFALSE;
+ stmt = cil_build_stmt_arg (opcode, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case UNEQ_EXPR:
+ lhs = gen_expr_copy (csi, lhs);
+ rhs = gen_expr_copy (csi, rhs);
+
+ /* Emit the equivalent of an UNORDERED_EXPR ... */
+ gimple_to_cil_node (csi, lhs);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* ... plus an equal comparison. */
+ gimple_to_cil_node (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt_arg (CIL_BRTRUE, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case LTGT_EXPR:
+ lhs = gen_expr_copy (csi, lhs);
+ rhs = gen_expr_copy (csi, rhs);
+
+ gimple_to_cil_node (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt (CIL_CGT);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gimple_to_cil_node (csi, lhs);
+ gimple_to_cil_node (csi, rhs);
+ stmt = cil_build_stmt (CIL_CLT);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt_arg (CIL_BRTRUE, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ default:
+ gimple_to_cil_node (csi, cond);
+ stmt = cil_build_stmt_arg (CIL_BRTRUE, label_then);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+
+ /* TODO: Emit JIT compilation hints
+ if (TARGET_EMIT_JIT_COMPILATION_HINTS)
+ branch_probability_add (file, node); */
+
+ dest_bb = label_to_block (label_else);
+
+ /* Emit else block only if it is not a fallthrough */
+ if (csi_bb (*csi)->next_bb != dest_bb)
+ {
+ stmt = cil_build_stmt_arg (CIL_BR, label_else);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Emit a switch expression. */
+
+static void
+gen_switch_expr (cil_stmt_iterator *csi, tree node)
+{
+ tree labels = SWITCH_LABELS (node);
+ tree min = TREE_VEC_ELT (labels, 0);
+ unsigned int length = TREE_VEC_LENGTH (labels);
+ tree default_label = CASE_LABEL (TREE_VEC_ELT (labels, length - 1));
+ basic_block dest_bb;
+ cil_stmt stmt;
+
+ /* Generate the switch condition. */
+ gimple_to_cil_node (csi, SWITCH_COND (node));
+
+ /* 'Normalize' the condition. */
+ if (!tree_int_cst_equal (CASE_LOW (min), integer_zero_node))
+ {
+ gen_integer_cst (csi, CASE_LOW (min));
+ stmt = cil_build_stmt (CIL_SUB);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* Generate the switch and the default label fall thru. */
+ stmt = cil_build_switch (labels);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ dest_bb = label_to_block (default_label);
+
+ if (csi_bb (*csi)->next_bb != dest_bb)
+ {
+ stmt = cil_build_stmt_arg (CIL_BR, default_label);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates a call to a builtin constructor for initializing a vector of type
+ VECTOR_TYPE. The generated statements are appended to the current
+ function's CIL code using the CSI iterator. */
+
+static void
+gen_vector_constructor (cil_stmt_iterator *csi, tree vector_type)
+{
+ tree elem_type = TREE_TYPE (vector_type);
+ unsigned HOST_WIDE_INT elem_num = TYPE_VECTOR_SUBPARTS (vector_type);
+ unsigned HOST_WIDE_INT elem_size = tree_low_cst (TYPE_SIZE (elem_type), 1);
+ enum cil32_builtin builtin;
+ cil_stmt stmt;
+
+ if (INTEGRAL_TYPE_P (elem_type))
+ {
+ switch (elem_size)
+ {
+ case 8:
+ switch (elem_num)
+ {
+ case 4: builtin = CIL32_V4QI_CTOR; break;
+ case 8: builtin = CIL32_V8QI_CTOR; break;
+ case 16: builtin = CIL32_V16QI_CTOR; break;
+ default: internal_error ("Unsupported vector size\n");
+ }
+ break;
+
+ case 16:
+ switch (elem_num)
+ {
+ case 2: builtin = CIL32_V2HI_CTOR; break;
+ case 4: builtin = CIL32_V4HI_CTOR; break;
+ case 8: builtin = CIL32_V8HI_CTOR; break;
+ default: internal_error ("Unsupported vector size\n");
+ }
+ break;
+
+ case 32:
+ switch (elem_num)
+ {
+ case 2: builtin = CIL32_V2SI_CTOR; break;
+ case 4: builtin = CIL32_V4SI_CTOR; break;
+ default: internal_error ("Unsupported vector size\n");
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ gcc_assert (SCALAR_FLOAT_TYPE_P (elem_type));
+
+ if (elem_size == 32)
+ {
+ switch (elem_num)
+ {
+ case 2: builtin = CIL32_V2SF_CTOR; break;
+ case 4: builtin = CIL32_V4SF_CTOR; break;
+ default: internal_error ("Unsupported vector size\n");
+ }
+ }
+ else
+ internal_error ("Vectors with double-typed elements are unsupported\n");
+ }
+
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generate the CIL code associated with the __builtin_va_start() call
+ specified by NODE. The generated CIL statements will be appended to CSI. */
+
+static void
+gen_builtin_va_start (cil_stmt_iterator *csi, tree node)
+{
+ tree argiter = create_tmp_var (cil32_arg_iterator_type, "arg_iterator");
+ cil_stmt stmt;
+
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, argiter);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_call (cil32_builtins[CIL32_BUILT_IN_VA_INIT]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_call (cil32_builtins[CIL32_BUILT_IN_VA_START]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* FIXME: The extra indirection step may be optimized out in the common case
+ or removed later using a peephole optimization. */
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, argiter);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_STIND_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generate the CIL code associated with the __builtin_va_end() call
+ specified by NODE. The generated CIL statements will be appended to CSI. */
+
+static void
+gen_builtin_va_end (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+
+ /* FIXME: The extra indirection step may be optimized out in the common case
+ or removed later using a peephole optimization. */
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_stmt (CIL_LDIND_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_call (cil32_builtins[CIL32_BUILT_IN_VA_END]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generate the CIL code associated with the __builtin_va_copy() call
+ specified by NODE. The generated CIL statements will be appended to CSI. */
+
+static void
+gen_builtin_va_copy (cil_stmt_iterator *csi, tree node)
+{
+ tree argiter = create_tmp_var (cil32_arg_iterator_type, "arg_iterator");
+ cil_stmt stmt;
+
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, argiter);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_call (cil32_builtins[CIL32_BUILT_IN_VA_INIT]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* FIXME: The extra indirection step may be optimized out in the common case
+ or removed later using a peephole optimization. */
+ /* Load the source argument iterator. */
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, argiter);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_STIND_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* Load the destination argument iterator.*/
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 1));
+
+ /* Make the copy. */
+ stmt = cil_build_call (cil32_builtins[CIL32_BUILT_IN_VA_COPY]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Inspired from 'expand_builtin_object_size' in builtins.c. We return -1
+ for types 0 and 1, and 0 for types 2 and 3. */
+
+static void
+gen_builtin_object_size (cil_stmt_iterator *csi, tree node)
+{
+ tree arg2 = CALL_EXPR_ARG (node, 1);
+ int obj_type;
+
+ STRIP_NOPS (arg2);
+ gcc_assert (TREE_CODE (arg2) == INTEGER_CST);
+ obj_type = tree_low_cst (arg2, 0);
+
+ switch (obj_type)
+ {
+ case 0:
+ case 1:
+ gen_integer_cst (csi, integer_zero_node);
+ break;
+
+ case 2:
+ case 3:
+ gen_integer_cst (csi, integer_minus_one_node);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Try to handle a builtin call. In some cases this function will expand the
+ builtin and return true, this indicates that the call has been effectively
+ removed and no other action is required, otherwise false will be
+ returned. The current CALL_EXPR is passed in NODE and the function
+ declaration in FDECL. If the builtin is expanded the generated CIL
+ statements will be appended to CSI. */
+
+static bool
+gen_call_builtin (cil_stmt_iterator *csi, tree node, tree fdecl)
+{
+ cil_stmt stmt;
+
+ if (DECL_BUILT_IN_CLASS (fdecl) != BUILT_IN_MD)
+ {
+ switch (DECL_FUNCTION_CODE (fdecl))
+ {
+ case BUILT_IN_VA_START:
+ gen_builtin_va_start (csi, node);
+ return true;
+
+ case BUILT_IN_VA_END:
+ gen_builtin_va_end (csi, node);
+ return true;
+
+ case BUILT_IN_VA_COPY:
+ gen_builtin_va_copy (csi, node);
+ return true;
+
+ case BUILT_IN_CLZ:
+ case BUILT_IN_CLZL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_CLZSI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_CLZLL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_CLZDI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_CTZ:
+ case BUILT_IN_CTZL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_CTZSI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_CTZLL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_CTZDI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_FFS:
+ case BUILT_IN_FFSL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_FFSSI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_FFSLL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_FFSDI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_PARITY:
+ case BUILT_IN_PARITYL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_PARITYSI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_PARITYLL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_PARITYDI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_POPCOUNT:
+ case BUILT_IN_POPCOUNTL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_POPCOUNTSI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_POPCOUNTLL:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (cil32_builtins[CIL32_POPCOUNTDI2]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_OBJECT_SIZE:
+ gen_builtin_object_size (csi, node);
+ return true;
+
+ case BUILT_IN_INIT_TRAMPOLINE:
+ case BUILT_IN_ADJUST_TRAMPOLINE:
+ case BUILT_IN_NONLOCAL_GOTO:
+ internal_error ("Builtins to support Trampolines not implemented\n");
+
+ case BUILT_IN_PROFILE_FUNC_ENTER:
+ case BUILT_IN_PROFILE_FUNC_EXIT:
+ internal_error ("Builtins to support Profiling not implemented\n");
+
+ case BUILT_IN_SETJMP_SETUP:
+ case BUILT_IN_SETJMP_DISPATCHER:
+ case BUILT_IN_SETJMP_RECEIVER:
+ internal_error ("Builtins to support Setjump not implemented\n");
+
+ case BUILT_IN_MEMSET:
+ {
+ tree ptr = CALL_EXPR_ARG (node, 0);
+ tree value = CALL_EXPR_ARG (node, 1);
+ tree size = CALL_EXPR_ARG (node, 2);
+
+ gimple_to_cil_node (csi, ptr);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gimple_to_cil_node (csi, value);
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_INITBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ case BUILT_IN_MEMCPY:
+ {
+ tree ptr_dst = CALL_EXPR_ARG (node, 0);
+ tree ptr_src = CALL_EXPR_ARG (node, 1);
+ tree size = CALL_EXPR_ARG (node, 2);
+
+ gimple_to_cil_node (csi, ptr_dst);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gimple_to_cil_node (csi, ptr_src);
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_CPBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ case BUILT_IN_ALLOCA:
+ {
+ tree size = CALL_EXPR_ARG (node, 0);
+
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_LOCALLOC);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ case BUILT_IN_STACK_SAVE:
+ /* FIXME: This built-in is only used for the implementation
+ of variable-length arrays. It is not needed in CIL. */
+ gen_integer_cst (csi, integer_zero_node);
+ stmt = cil_build_stmt (CIL_CONV_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case BUILT_IN_STACK_RESTORE:
+ /* FIXME: This built-in is only used for the implementation
+ of variable-length arrays. It is not needed in CIL. */
+ return true;
+
+ case BUILT_IN_EXPECT:
+ /* TODO: __builtin_expect(exp,val) evalutes exp and tells the
+ compiler that it most likely gives val. We just evaluate exp
+ but we could flag it for JIT hints emission. */
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ return true;
+
+ case BUILT_IN_PREFETCH:
+ if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (node, 0)))
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+
+ return true;
+
+ case BUILT_IN_FRAME_ADDRESS:
+ case BUILT_IN_RETURN_ADDRESS:
+ {
+ /* Supported (sort of) only for non-zero parameter, when it is ok
+ to return NULL. */
+ tree arg = CALL_EXPR_ARG (node, 0);
+ int int_arg = tree_low_cst (arg, 0);
+
+ if (int_arg == 0)
+ internal_error ("__builtin_{return,frame}_address not implemented\n");
+ else
+ gen_integer_cst (csi, integer_zero_node);
+ }
+ return true;
+
+ case BUILT_IN_BZERO:
+ {
+ tree ptr = CALL_EXPR_ARG (node, 0);
+ tree size = CALL_EXPR_ARG (node, 1);
+
+ gimple_to_cil_node (csi, ptr);
+ gen_integer_cst (csi, build_int_cst (intSI_type_node, 0));
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_INITBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ case BUILT_IN_BCOPY:
+ {
+ tree ptr_src = CALL_EXPR_ARG (node, 0);
+ tree ptr_dst = CALL_EXPR_ARG (node, 1);
+ tree size = CALL_EXPR_ARG (node, 2);
+
+ gimple_to_cil_node (csi, ptr_dst);
+ gimple_to_cil_node (csi, ptr_src);
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_CPBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ default:
+ if (DECL_ASSEMBLER_NAME_SET_P (node))
+ {
+ /* Go ahead as a normal function call */
+ }
+ }
+ }
+ else
+ {
+ switch (DECL_FUNCTION_CODE (fdecl))
+ {
+ case CIL32_BUILT_IN_VA_ARG:
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, 0));
+ stmt = cil_build_call (fdecl);
+ cil_call_set_dummy_arg (stmt, CALL_EXPR_ARG (node, 1));
+ /* We 'patch' the generated call statement so as to make it behave as
+ if it had been passed a single argument. */
+ stmt->arg.fcall->nargs = 1;
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+
+ case CIL32_BUILT_IN_CPBLK:
+ {
+ tree ptr_dst = CALL_EXPR_ARG (node, 0);
+ tree ptr_src = CALL_EXPR_ARG (node, 1);
+ tree size = CALL_EXPR_ARG (node, 2);
+
+ gimple_to_cil_node (csi, ptr_dst);
+ gimple_to_cil_node (csi, ptr_src);
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_CPBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ case CIL32_BUILT_IN_INITBLK:
+ {
+ tree ptr = CALL_EXPR_ARG (node, 0);
+ tree value = CALL_EXPR_ARG (node, 1);
+ tree size = CALL_EXPR_ARG (node, 2);
+
+ gimple_to_cil_node (csi, ptr);
+ gimple_to_cil_node (csi, value);
+ gimple_to_cil_node (csi, size);
+ stmt = cil_build_stmt (CIL_INITBLK);
+ cil_set_prefix_unaligned (stmt, 1);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ return true;
+ }
+
+ default:
+ ;
+ }
+ }
+
+ return false;
+}
+
+/* Generates a function call from a CALL_EXPR gimple node NODE. The generated
+ statements are appended to the current function's CIL code using the CSI
+ iterator. */
+
+static void
+gen_call_expr (cil_stmt_iterator *csi, tree node)
+{
+ tree fdecl;
+ tree ftype;
+ tree arg_types;
+ VEC(tree, heap) *arglist;
+ tree static_chain;
+ bool direct = true;
+ bool varargs = false;
+ bool missing = false;
+ size_t nargs_base;
+ size_t nargs;
+ size_t i;
+ cil_stmt stmt;
+
+ gcc_assert (TREE_CODE (node) == CALL_EXPR);
+ fdecl = get_callee_fndecl (node);
+ nargs = call_expr_nargs (node);
+
+ if (fdecl != NULL_TREE)
+ ftype = TREE_TYPE (fdecl);
+ else
+ {
+ ftype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (node)));
+ direct = false;
+ }
+
+ /* Built-in functions must be handled in a special way */
+ if (direct && DECL_BUILT_IN (fdecl))
+ {
+ if (gen_call_builtin (csi, node, fdecl))
+ return;
+ }
+
+ arg_types = TYPE_ARG_TYPES (ftype);
+
+ if (arg_types == NULL)
+ {
+ if (direct)
+ {
+ warning (OPT_Wcil_missing_prototypes,
+ "Missing function %s prototype, guessing it, you should fix "
+ "the code",
+ IDENTIFIER_POINTER (DECL_NAME (fdecl)));
+ }
+ else
+ {
+ warning (OPT_Wcil_missing_prototypes,
+ "Missing indirect function prototype, guessing it, you "
+ "should fix the code");
+ }
+
+ /* Guess types using the type of the arguments. */
+ nargs_base = 0;
+ missing = true;
+ }
+ else
+ {
+ tree last_arg_type = tree_last (arg_types);
+ nargs_base = list_length (arg_types);
+
+ if (TREE_VALUE (last_arg_type) != void_type_node)
+ varargs = true;
+ else
+ nargs_base--;
+ }
+
+ arglist = VEC_alloc (tree, heap, nargs - nargs_base);
+
+ /* If static chain present, it will be the first argument. */
+ static_chain = CALL_EXPR_STATIC_CHAIN (node);
+
+ if (static_chain)
+ gimple_to_cil_node (csi, static_chain);
+
+ for (i = 0; i < nargs_base; i++)
+ gimple_to_cil_node (csi, CALL_EXPR_ARG (node, i));
+
+ /* Vararg parameters, this will be added only if they are present. */
+ for (; i < nargs; i++)
+ {
+ tree arg = CALL_EXPR_ARG (node, i);
+ tree arg_type = TREE_TYPE (arg);
+
+ gimple_to_cil_node (csi, arg);
+ VEC_quick_insert (tree, arglist, i - nargs_base, arg_type);
+
+ if (TREE_CODE (arg_type) == POINTER_TYPE
+ || (TREE_CODE (arg_type) == ARRAY_TYPE
+ && (!TYPE_DOMAIN (arg_type) || ARRAY_TYPE_VARLENGTH (arg_type))))
+ {
+ stmt = cil_build_stmt (CIL_CONV_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+
+ /* TODO: We could do return slot optimizations, or insertion of the tail
+ call prefix here? */
+ if (!direct)
+ {
+ /* Generate the function pointer, in case of an indirect call. */
+ gimple_to_cil_node (csi, CALL_EXPR_FN (node));
+
+ if (varargs)
+ stmt = cil_build_calli_va (ftype, arglist);
+ else if (missing)
+ stmt = cil_build_calli_mp (ftype, arglist);
+ else
+ stmt = cil_build_calli (ftype);
+ }
+ else
+ {
+ if (varargs)
+ stmt = cil_build_call_va (fdecl, arglist);
+ else if (missing)
+ stmt = cil_build_call_mp (fdecl, arglist);
+ else
+ stmt = cil_build_call (fdecl);
+ }
+
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ if (static_chain)
+ cil_call_set_static_chain (stmt, TREE_TYPE (static_chain));
+
+ if (arglist != NULL)
+ VEC_free (tree, heap, arglist);
+}
+
+/* Generates a copy inside a temporary variable of the expression NODE if it is
+ necessary or beneficial. Returns the new variable holding the copy or the
+ original expression if it wasn't copied. */
+
+static tree
+gen_expr_copy (cil_stmt_iterator *csi, tree node)
+{
+ enum tree_code code = TREE_CODE (node);
+ cil_stmt stmt;
+ tree tmp;
+
+ if (!TREE_SIDE_EFFECTS (node)
+ && ((code == INTEGER_CST) || (code == REAL_CST)
+ || (code == VAR_DECL) || (code == PARM_DECL)))
+ {
+ return node;
+ }
+
+ tmp = create_tmp_var (TREE_TYPE (node), "gimple2cil");
+ gimple_to_cil_node (csi, node);
+ stmt = cil_build_stmt_arg (CIL_STLOC, tmp);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ return tmp;
+}
+
+/* Generates a BIT_AND_EXPR potentially folding it into a conversion in order
+ to minimize code size. */
+
+static void
+gen_bit_and_expr (cil_stmt_iterator *csi, tree node)
+{
+ enum cil_opcode opcode;
+ cil_stmt stmt;
+ tree op0 = GENERIC_TREE_OPERAND (node, 0);
+ tree op1 = GENERIC_TREE_OPERAND (node, 1);
+
+ if (TREE_CODE (op0) == INTEGER_CST
+ && (TREE_INT_CST_LOW (op0) == 255U
+ || TREE_INT_CST_LOW (op0) == 65535U
+ || TREE_INT_CST_LOW (op0) == 4294967295U)
+ && TREE_INT_CST_HIGH (op0) == 0)
+ {
+ gimple_to_cil_node (csi, op1);
+
+ switch (TREE_INT_CST_LOW (op0))
+ {
+ case 255U: opcode = CIL_CONV_U1; break;
+ case 65535U: opcode = CIL_CONV_U2; break;
+ case 4294967295U: opcode = CIL_CONV_U4; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ csi_insert_after (csi, cil_build_stmt (opcode), CSI_CONTINUE_LINKING);
+
+ if (TYPE_PRECISION (TREE_TYPE (node)) > 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_U8);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else if (TREE_CODE (op1) == INTEGER_CST
+ && (TREE_INT_CST_LOW (op1) == 255U
+ || TREE_INT_CST_LOW (op1) == 65535U
+ || TREE_INT_CST_LOW (op1) == 4294967295U)
+ && TREE_INT_CST_HIGH (op1) == 0)
+ {
+ gimple_to_cil_node (csi, op0);
+
+ switch (TREE_INT_CST_LOW (op1))
+ {
+ case 255U: opcode = CIL_CONV_U1; break;
+ case 65535U: opcode = CIL_CONV_U2; break;
+ case 4294967295U: opcode = CIL_CONV_U4; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ csi_insert_after (csi, cil_build_stmt (opcode), CSI_CONTINUE_LINKING);
+
+ if (TYPE_PRECISION (TREE_TYPE (node)) > 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_U8);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else
+ {
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* No need for conversions even in case of values with precision
+ smaller than the one used on the evaluation stack, since for these
+ operations the output is always less or equal than both operands. */
+}
+
+/* Generates a LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EQ_EXPR, NE_EXPR,
+ UNORDERED_EXPR, ORDERED_EXPR, UNLT_EXPR, UNLE_EXPR, UNGT_EXPR, UNGE_EXPR,
+ UNEQ_EXPR or LTGT_EXPR expression used outside of a COND_EXPR. */
+
+static void
+gen_compare_expr (cil_stmt_iterator *csi, tree node)
+{
+ enum tree_code code = TREE_CODE (node);
+ tree op0 = GENERIC_TREE_OPERAND (node, 0);
+ tree op1 = GENERIC_TREE_OPERAND (node, 1);
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+
+ switch (code)
+ {
+ case LT_EXPR:
+ case GT_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case UNLT_EXPR:
+ case UNGT_EXPR:
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+
+ if (TREE_CODE (node) == NE_EXPR)
+ {
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ switch (TREE_CODE (node))
+ {
+ case LT_EXPR:
+ opcode = TYPE_UNSIGNED (TREE_TYPE (op0)) ? CIL_CLT_UN : CIL_CLT;
+ break;
+
+ case GT_EXPR:
+ opcode = TYPE_UNSIGNED (TREE_TYPE (op0)) ? CIL_CGT_UN : CIL_CGT;
+ break;
+
+ case EQ_EXPR:
+ opcode = CIL_CEQ;
+ break;
+
+ case UNLT_EXPR:
+ opcode = CIL_CLT_UN;
+ break;
+
+ case UNGT_EXPR:
+ opcode = CIL_CGT_UN;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case LE_EXPR:
+ case GE_EXPR:
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+
+ if (TREE_CODE (node) == LE_EXPR)
+ opcode = TYPE_UNSIGNED (TREE_TYPE (op0)) ? CIL_CGT_UN : CIL_CGT;
+ else
+ opcode = TYPE_UNSIGNED (TREE_TYPE (op0)) ? CIL_CLT_UN : CIL_CLT;
+
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ gimple_to_cil_node (csi, op0);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ if (TREE_CODE (node) == UNORDERED_EXPR)
+ {
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case UNEQ_EXPR:
+ case UNLE_EXPR:
+ case UNGE_EXPR:
+ op0 = gen_expr_copy (csi, op0);
+ op1 = gen_expr_copy (csi, op1);
+
+ /* Emit the equivalent of an ORDERED_EXPR ... */
+ gimple_to_cil_node (csi, op0);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_DUP);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* ... plus the relevant comparison. */
+ if (code == UNEQ_EXPR)
+ {
+ /* !ORDERED_EXPR || EQ_EXPR */
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ /* !(ORDERED_EXPR && GT_EXPR) or !(ORDERED_EXPR && LT_EXPR) */
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (code == UNLE_EXPR ? CIL_CGT : CIL_CLT);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case LTGT_EXPR:
+ op0 = gen_expr_copy (csi, op0);
+ op1 = gen_expr_copy (csi, op1);
+
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_CGT);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+ stmt = cil_build_stmt (CIL_CLT);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (tree_low_cst (TYPE_SIZE (TREE_TYPE (node)), 1) > 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_I8);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates CIL code for a (MIN|MAX)_EXPR held in the tree NODE. The node is
+ either expanded or replaced with a builtin call, depending on the options
+ and the optimization level. The generated statements are appended to the
+ current function's CIL code using the CSI iterator. */
+
+static void
+gen_minmax_expr (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+ tree type = TREE_TYPE (node);
+ bool max = (TREE_CODE (node) == MAX_EXPR);
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ bool unsignedp;
+ enum cil32_builtin builtin = 0;
+
+ gimple_to_cil_node (csi, TREE_OPERAND (node, 0));
+ gimple_to_cil_node (csi, TREE_OPERAND (node, 1));
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ unsignedp = TYPE_UNSIGNED (type);
+
+ if (size <= 32)
+ {
+ if (max)
+ builtin = unsignedp ? CIL32_UMAXSI3 : CIL32_MAXSI3;
+ else
+ builtin = unsignedp ? CIL32_UMINSI3 : CIL32_MINSI3;
+ }
+ else
+ {
+ gcc_assert (size <= 64);
+
+ if (max)
+ builtin = unsignedp ? CIL32_UMAXDI3 : CIL32_MAXDI3;
+ else
+ builtin = unsignedp ? CIL32_UMINDI3 : CIL32_MINDI3;
+ }
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ if (size == 32)
+ builtin = max ? CIL32_MAXSF3 : CIL32_MINSF3;
+ else
+ {
+ gcc_assert (size == 64);
+ builtin = max ? CIL32_MAXDF3 : CIL32_MINDF3;
+ }
+ }
+ else
+ gcc_unreachable ();
+
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generates CIL code for an ABS_EXPR held in the tree NODE. The node is
+ either expanded or replaced with a builtin call, depending on the options
+ and the optimization level. The generated statements are appended to the
+ current function's CIL code using the CSI iterator. */
+
+static void
+gen_abs_expr (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+ tree type = TREE_TYPE (node);
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ enum cil32_builtin builtin = 0;
+
+ gcc_assert (!TARGET_EXPAND_ABS);
+
+ gimple_to_cil_node (csi, TREE_OPERAND (node, 0));
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ if (size == 32)
+ builtin = CIL32_ABSSI2;
+ else
+ {
+ gcc_assert (size == 64);
+ builtin = CIL32_ABSDI2;
+ }
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ if (size == 32)
+ builtin = CIL32_ABSSF2;
+ else
+ {
+ gcc_assert (size == 64);
+ builtin = CIL32_ABSDF2;
+ }
+ }
+ else
+ gcc_unreachable ();
+
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Generates CIL code for a VAR_DECL expression held in the tree NODE. The
+ generated statements are appended to the current function's CIL code using
+ the CSI iterator. */
+
+static void
+gen_var_decl (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+ tree type = TREE_TYPE (node);
+
+ mark_referenced_type (type);
+
+ /* Function local static variables are promoted to global variables. */
+ if (!DECL_FILE_SCOPE_P (node) && !TREE_STATIC (node))
+ {
+ if (TREE_THIS_VOLATILE (node))
+ {
+ /* put the address of the loc on the stack */
+ stmt = cil_build_stmt_arg (CIL_LDLOCA, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ /* and emit a volatile ldind or ldobj */
+ gen_ldind (csi, type, true);
+ }
+ else
+ {
+ stmt = cil_build_stmt_arg (CIL_LDLOC, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else
+ {
+ stmt = cil_build_stmt_arg (CIL_LDSFLD, node);
+ cil_set_prefix_volatile (stmt, TREE_THIS_VOLATILE (node));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates CIL code for a COMPONENT_REF working on a bit field held in the
+ tree NODE. The generated statements are appended to the current function's
+ CIL code using the CSI iterator. */
+
+static void
+gen_bit_field_comp_ref (cil_stmt_iterator *csi, tree node)
+{
+ HOST_WIDE_INT bit_size = 0;
+ HOST_WIDE_INT bit_pos = 0;
+ HOST_WIDE_INT cont_off;
+ HOST_WIDE_INT cont_size = 8;
+ tree offset = NULL_TREE;
+ enum machine_mode mode;
+ int unsignedp = 0;
+ int volatilep = 0;
+ cil_stmt stmt;
+ tree cont_type;
+ tree ref;
+
+ /* TODO: Add support for packed bit-fields crossing 64-bit boundaries.
+ TODO: Add support for big-endian targets. */
+
+ /* Get the object base address and emit it. */
+ ref = get_inner_reference (node, &bit_size, &bit_pos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ gen_addr_expr (csi, ref);
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+
+ /* Calculate the container size. */
+ while ((bit_pos % cont_size + bit_size) > cont_size)
+ cont_size *= 2;
+
+ cont_type = get_integer_type (cont_size, unsignedp);
+ cont_off = bit_pos % cont_size;
+
+ /* Calculate the container address if needed. */
+ if ((bit_pos - cont_off) / BITS_PER_UNIT != 0)
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node,
+ (bit_pos - cont_off) / BITS_PER_UNIT));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (offset != NULL_TREE)
+ {
+ gimple_to_cil_node (csi, offset);
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* Load the container. */
+ gen_scalar_ldind (csi, cont_type, volatilep);
+
+ /* Shift the resulting value into the correct position, zero/sign extending
+ it as appropriate. Since the value is now on the stack the container size
+ is either 32 or 64. */
+ if (cont_size <= 32)
+ cont_size = 32;
+ else
+ cont_size = 64;
+
+ if (cont_size - (cont_off + bit_size))
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node,
+ cont_size - (cont_off + bit_size)));
+ stmt = cil_build_stmt (CIL_SHL);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (cont_size - bit_size)
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node, cont_size - bit_size));
+ stmt = cil_build_stmt (unsignedp ? CIL_SHR_UN : CIL_SHR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (TYPE_PRECISION (TREE_TYPE (node)) <= 32)
+ {
+ if (cont_size > 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_I4);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else
+ {
+ if (cont_size <= 32)
+ {
+ stmt = cil_build_stmt (unsignedp ? CIL_CONV_U8 : CIL_CONV_I8);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+}
+
+/* Generates CIL code for a COMPONENT_REF expression held in the tree NODE.
+ The generated statements are appended to the current function's CIL code
+ using the CSI iterator. */
+
+static void
+gen_comp_ref (cil_stmt_iterator *csi, tree node)
+{
+ tree obj = TREE_OPERAND (node, 0);
+ tree fld = TREE_OPERAND (node, 1);
+ cil_stmt stmt;
+
+ gcc_assert (TREE_CODE (fld) == FIELD_DECL);
+
+ mark_referenced_type (TYPE_MAIN_VARIANT (TREE_TYPE (obj)));
+
+ if (DECL_BIT_FIELD (fld))
+ gen_bit_field_comp_ref (csi, node);
+ else
+ {
+ gen_addr_expr (csi, obj);
+ stmt = cil_build_stmt_arg (CIL_LDFLD, fld);
+ cil_set_prefix_volatile (stmt, TREE_THIS_VOLATILE (node));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates CIL code for a BIT_FIELD_REF expression used to access a vector
+ element. The generated statements are appended to the current function's CIL
+ code using the CSI iterator. */
+
+static void
+gen_vector_bitfield_ref (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+ tree cst;
+
+ gen_addr_expr (csi, GENERIC_TREE_OPERAND (node, 0));
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+ cst = size_binop (TRUNC_DIV_EXPR, GENERIC_TREE_OPERAND (node, 2),
+ bitsize_unit_node);
+
+ if (!integer_zerop (cst))
+ {
+ gen_integer_cst (csi, fold_convert (intSI_type_node, cst));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ gen_ldind (csi, TREE_TYPE (node), TREE_THIS_VOLATILE (node));
+}
+
+/* Generates CIL code for a BIT_FIELD_REF expression held in the tree NODE.
+ The generated statements are appended to the current function's CIL code
+ using the CSI iterator. Hopefully this function will go away with
+ BIT_FIELD_REFs sooner than later. */
+
+static void
+gen_bit_field_ref (cil_stmt_iterator *csi, tree node)
+{
+ unsigned HOST_WIDE_INT bit_size = 0;
+ unsigned HOST_WIDE_INT bit_pos = 0;
+ unsigned HOST_WIDE_INT cont_off;
+ unsigned HOST_WIDE_INT cont_size = 8;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ tree cont_type;
+ tree cst;
+ tree offset = GENERIC_TREE_OPERAND (node, 2);
+
+ /* TODO: Add support for big-endian targets. */
+ gen_addr_expr (csi, GENERIC_TREE_OPERAND (node, 0));
+ csi_insert_after (csi, cil_build_stmt (CIL_CONV_I), CSI_CONTINUE_LINKING);
+
+ cst = size_binop (TRUNC_DIV_EXPR, offset, bitsize_unit_node);
+
+ if (!integer_zerop (cst))
+ {
+ gen_integer_cst (csi, fold_convert (intSI_type_node, cst));
+ stmt = cil_build_stmt (CIL_ADD);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* Calculate the container size. */
+ cst = size_binop (TRUNC_MOD_EXPR, offset, bitsize_unit_node);
+ bit_pos = tree_low_cst (cst, 1);
+ bit_size = tree_low_cst (TREE_OPERAND (node, 1), 1);
+
+ while ((bit_pos % cont_size + bit_size) > cont_size)
+ cont_size *= 2;
+
+ cont_type = get_integer_type (cont_size, BIT_FIELD_REF_UNSIGNED (node));
+ cont_off = bit_pos % cont_size;
+
+ /* Load the container. */
+ gen_scalar_ldind (csi, cont_type, TREE_THIS_VOLATILE (node));
+
+ /* Shift the resulting value into the correct position, zero extending it.
+ Since the value is now on the stack the container size is either 32
+ or 64. */
+ if (bit_size != cont_size)
+ {
+ if (cont_size <= 32)
+ cont_size = 32;
+ else
+ cont_size = 64;
+
+ if (cont_size - (cont_off + bit_size))
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node,
+ cont_size - (cont_off + bit_size)));
+ stmt = cil_build_stmt (CIL_SHL);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ if (cont_size - bit_size)
+ {
+ gen_integer_cst (csi,
+ build_int_cst (intSI_type_node,
+ cont_size - bit_size));
+ opcode = BIT_FIELD_REF_UNSIGNED (node) ? CIL_SHR_UN : CIL_SHR;
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+}
+
+/* Generates CIL code for a TRUTH_(AND|OR|XOR)_EXPR expression held in the tree
+ NODE. The generated statements are appended to the current function's CIL
+ code using the CSI iterator. */
+
+static void
+gen_truth_expr (cil_stmt_iterator *csi, tree node)
+{
+ tree op0 = TREE_OPERAND (node, 0);
+ tree op1 = TREE_OPERAND (node, 1);
+ cil_stmt stmt;
+
+ gimple_to_cil_node (csi, op0);
+
+ if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE)
+ {
+ gen_integer_cst (csi, integer_zero_node);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ gcc_assert (TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE);
+
+ gimple_to_cil_node (csi, op1);
+
+ if (TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE)
+ {
+ gen_integer_cst (csi, integer_zero_node);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ gcc_assert (TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE);
+
+ if (TREE_CODE (node) == TRUTH_AND_EXPR)
+ {
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else if (TREE_CODE (node) == TRUTH_OR_EXPR)
+ {
+ stmt = cil_build_stmt (CIL_OR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ stmt = cil_build_stmt (CIL_XOR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, integer_one_node);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates the address of a TARGET_MEM_REF node specified by NODE and push it
+ on the stack. The generated statements are appended to the current
+ function's CIL code using the CSI iterator. */
+
+static void
+gen_target_mem_ref (cil_stmt_iterator *csi, tree node)
+{
+ tree type = TREE_TYPE (node);
+ tree ptr_type = build_pointer_type (type);
+
+ gimple_to_cil_node (csi, tree_mem_ref_addr (ptr_type, node));
+ gen_ldind (csi, type, TREE_THIS_VOLATILE (node));
+}
+
+/* Generates CIL code for a VIEW_CONVERT_EXPR held in the tree NODE. The
+ generated statements are appended to the current function's CIL code using
+ the CSI iterator. */
+
+static void
+gen_view_convert_expr (cil_stmt_iterator *csi, tree node)
+{
+ tree op0 = TREE_OPERAND (node, 0);
+ tree dest_type = TREE_TYPE (node);
+ tree src_type = TREE_TYPE (op0);
+ tree elem_type;
+ unsigned HOST_WIDE_INT dest_size = tree_low_cst (TYPE_SIZE (dest_type), 1);
+ unsigned HOST_WIDE_INT src_size = tree_low_cst (TYPE_SIZE (src_type), 1);
+ unsigned HOST_WIDE_INT elem_size, n_elem;
+ bool unsignedp;
+ enum cil32_builtin builtin = CIL32_MAX_BUILT_IN; /* Placeholder */
+ cil_stmt stmt;
+
+ gimple_to_cil_node (csi, op0);
+
+ if (TREE_CODE (src_type) == VECTOR_TYPE)
+ {
+ /* Convert a vector type to something. */
+ elem_type = TREE_TYPE (src_type);
+ elem_size = tree_low_cst (TYPE_SIZE (elem_type), 1);
+ n_elem = TYPE_VECTOR_SUBPARTS (src_type);
+ unsignedp = TYPE_UNSIGNED (dest_type);
+
+ if (INTEGRAL_TYPE_P (dest_type))
+ {
+ if (dest_size == 32 && INTEGRAL_TYPE_P (elem_type))
+ {
+ if (elem_size == 8 && n_elem == 4)
+ builtin = unsignedp ? CIL32_V4QI_TO_USI : CIL32_V4QI_TO_SI;
+ else if (elem_size == 16 && n_elem == 2)
+ builtin = unsignedp ? CIL32_V2HI_TO_USI : CIL32_V2HI_TO_SI;
+ }
+ else if (dest_size == 64 && INTEGRAL_TYPE_P (elem_type))
+ {
+ if (elem_size == 8 && n_elem == 8)
+ builtin = unsignedp ? CIL32_V8QI_TO_UDI : CIL32_V8QI_TO_DI;
+ else if (elem_size == 16 && n_elem == 4)
+ builtin = unsignedp ? CIL32_V4HI_TO_UDI : CIL32_V4HI_TO_DI;
+ else if (elem_size == 32 && n_elem == 2)
+ builtin = unsignedp ? CIL32_V2SI_TO_UDI : CIL32_V2SI_TO_DI;
+ }
+ else if (dest_size == 64 && SCALAR_FLOAT_TYPE_P (elem_type))
+ {
+ if (elem_size == 32)
+ builtin = CIL32_V2SF_TO_DI;
+ }
+ }
+ else if (TREE_CODE (dest_type) == VECTOR_TYPE)
+ {
+ if ((INTEGRAL_TYPE_P (elem_type) && elem_size == 32)
+ && (SCALAR_FLOAT_TYPE_P (TREE_TYPE (dest_type))
+ && tree_low_cst (TYPE_SIZE (TREE_TYPE (dest_type)), 1) == 32)
+ && dest_size == src_size)
+ {
+ builtin = CIL32_V4SI_TO_V4SF;
+ }
+ }
+ }
+ else if (TREE_CODE (dest_type) == VECTOR_TYPE)
+ {
+ /* Convert something to a vector type */
+ elem_type = TREE_TYPE (dest_type);
+ elem_size = tree_low_cst (TYPE_SIZE (elem_type), 1);
+ n_elem = TYPE_VECTOR_SUBPARTS (dest_type);
+
+ if (INTEGRAL_TYPE_P (src_type))
+ {
+ if (src_size == 32)
+ {
+ if (elem_size == 8 && n_elem == 4)
+ builtin = CIL32_V4QI_CTOR2;
+ else if (elem_size == 16 && n_elem == 2)
+ builtin = CIL32_V2HI_CTOR2;
+ }
+ else if (src_size == 64)
+ {
+ if (elem_size == 8 && n_elem == 8)
+ builtin = CIL32_V8QI_CTOR2;
+ else if (elem_size == 16 && n_elem == 4)
+ builtin = CIL32_V4HI_CTOR2;
+ else if (elem_size == 32 && n_elem == 2)
+ builtin = CIL32_V2SI_CTOR2;
+ }
+ }
+ }
+
+ if (builtin == CIL32_MAX_BUILT_IN)
+ {
+ internal_error ("Unsupported VIEW_CONVERT_EXPR\n");
+ }
+
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Emit the code needed to generate a REALPART_ or IMAGPART_EXPR expression. */
+
+static void
+gen_complex_part_expr (cil_stmt_iterator *csi, tree node)
+{
+ cil_stmt stmt;
+ tree op0 = GENERIC_TREE_OPERAND (node, 0);
+ tree type = TREE_TYPE (node);
+
+ if (TREE_CODE (op0) == COMPLEX_EXPR)
+ {
+ /* Get the relevant part immediately */
+ if (TREE_CODE (node) == REALPART_EXPR)
+ gimple_to_cil_node (csi, GENERIC_TREE_OPERAND (op0, 0));
+ else
+ gimple_to_cil_node (csi, GENERIC_TREE_OPERAND (op0, 1));
+ }
+ else
+ {
+ if (DECL_P (op0)
+ || TREE_CODE (op0) == INDIRECT_REF
+ || TREE_CODE (op0) == ARRAY_REF
+ || TREE_CODE (op0) == COMPONENT_REF)
+ {
+ /* Generate the object's address */
+ gen_addr_expr (csi, op0);
+ }
+ else
+ gimple_to_cil_node (csi, op0);
+
+ if (TREE_CODE (node) == REALPART_EXPR)
+ {
+ stmt = cil_build_stmt_arg (CIL_LDFLD,
+ cil_get_builtin_complex_real_fld (type));
+ }
+ else
+ {
+ stmt = cil_build_stmt_arg (CIL_LDFLD,
+ cil_get_builtin_complex_imag_fld (type));
+ }
+
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Emit the code needed for COMPLEX_CST/COMPLEX_EXPR expressions. */
+
+static void
+gen_complex (cil_stmt_iterator *csi, tree type, tree real, tree imag)
+{
+ tree elem_type = TREE_TYPE (type);
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (elem_type), 1);
+ enum cil32_builtin builtin = 0;
+ cil_stmt stmt;
+ bool unsignedp;
+
+ gimple_to_cil_node (csi, real);
+ gimple_to_cil_node (csi, imag);
+
+ if (INTEGRAL_TYPE_P (elem_type))
+ {
+ unsignedp = TYPE_UNSIGNED (elem_type);
+
+ switch (size)
+ {
+ case 8:
+ builtin = unsignedp ? CIL32_CPLX_UCHAR_CTOR : CIL32_CPLX_CHAR_CTOR;
+ break;
+
+ case 16:
+ builtin = unsignedp ? CIL32_CPLX_USHORT_CTOR : CIL32_CPLX_SHORT_CTOR;
+ break;
+
+ case 32:
+ builtin = unsignedp ? CIL32_CPLX_UINT_CTOR : CIL32_CPLX_INT_CTOR;
+ break;
+
+ case 64:
+ builtin = unsignedp ? CIL32_CPLX_ULONG_CTOR : CIL32_CPLX_LONG_CTOR;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ gcc_assert (SCALAR_FLOAT_TYPE_P (elem_type)
+ && ((size == 32) || (size == 64)));
+
+ if (size == 32)
+ builtin = CIL32_CPLX_FLOAT_CTOR;
+ else
+ builtin = CIL32_CPLX_DOUBLE_CTOR;
+ }
+
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+}
+
+/* Return the opcode associated with the conversion to the TYPE type. */
+
+static enum cil_opcode
+conv_opcode_from_type (tree type)
+{
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ bool unsignedp;
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ unsignedp = TYPE_UNSIGNED (type);
+
+ switch (size)
+ {
+ case 8: return (unsignedp ? CIL_CONV_U1 : CIL_CONV_I1);
+ case 16: return (unsignedp ? CIL_CONV_U2 : CIL_CONV_I2);
+ case 32: return (unsignedp ? CIL_CONV_U4 : CIL_CONV_I4);
+ case 64: return (unsignedp ? CIL_CONV_U8 : CIL_CONV_I8);
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else if (POINTER_TYPE_P (type))
+ return CIL_CONV_I;
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ if (size == 32)
+ return CIL_CONV_R4;
+ else
+ {
+ gcc_assert (size == 64);
+ return CIL_CONV_R8;
+ }
+ }
+ else
+ gcc_unreachable ();
+}
+
+/* Return an integer type of SIZE bits, unsigned if UNSIGNEDP is set, signed
+ otherwise. */
+
+static tree
+get_integer_type (unsigned int size, bool unsignedp)
+{
+ switch (size)
+ {
+ case 8: return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+ case 16: return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+ case 32: return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+ case 64: return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Emit a conversion from integral or pointer type SRC to integral type DST.
+ If the precision of DST is bigger than that of SRC, then SRC and DST have
+ to have the same signedness. */
+
+static void
+gen_integral_conv (cil_stmt_iterator *csi, tree dst, tree src)
+{
+ unsigned int dst_bits, cont_size, src_bits;
+ enum cil_opcode opcode;
+ cil_stmt stmt;
+ tree type;
+
+ gcc_assert (INTEGRAL_TYPE_P (dst));
+ gcc_assert (INTEGRAL_TYPE_P (src) || POINTER_TYPE_P (src));
+ gcc_assert (TYPE_PRECISION (dst) <= 64);
+ gcc_assert (TYPE_PRECISION (dst) <= TYPE_PRECISION (src)
+ || TYPE_UNSIGNED (dst) == TYPE_UNSIGNED (src));
+
+ /* Get the precision of the output and input types and the size
+ of the output type container */
+ src_bits = TYPE_PRECISION (src);
+ dst_bits = TYPE_PRECISION (dst);
+ cont_size = GET_MODE_BITSIZE (TYPE_MODE (dst));
+ gcc_assert (cont_size >= dst_bits);
+
+ /* Dump a conv with for the container size, if not superfluous */
+ if ((cont_size == dst_bits && (dst_bits != src_bits || dst_bits < 32))
+ || ((dst_bits > 32) ^ (src_bits > 32)))
+ {
+ opcode = conv_opcode_from_type (get_integer_type (cont_size,
+ TYPE_UNSIGNED (dst)));
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ /* If the container is bigger than the output type precision,
+ force the output to be of the desired precision. */
+ if (cont_size > dst_bits)
+ {
+ type = (dst_bits <= 32) ? intSI_type_node : intDI_type_node;
+
+ if (TYPE_UNSIGNED (dst))
+ {
+ tree mask;
+
+ mask = size_binop (LSHIFT_EXPR, build_int_cst (type, 1),
+ build_int_cst (type, dst_bits));
+ mask = size_binop (MINUS_EXPR, mask, build_int_cst (type, 1));
+ gen_integer_cst (csi, mask);
+ stmt = cil_build_stmt (CIL_AND);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ {
+ tree shift;
+
+ if (dst_bits <= 32)
+ shift = build_int_cst (intSI_type_node, 32 - dst_bits);
+ else
+ shift = build_int_cst (intSI_type_node, 64 - dst_bits);
+
+ /* Do a pair of shift to perform the sign extension */
+ gen_integer_cst (csi, shift);
+ stmt = cil_build_stmt (CIL_SHL);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ gen_integer_cst (csi, shift);
+ stmt = cil_build_stmt (CIL_SHR);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+}
+
+/* Emit a conversion from type IN_TYPE to type OUT_TYPE to file FILE.
+ IS_NOP says whether the conversion comes from a NOP_EXPR. */
+
+static void
+gen_conv (cil_stmt_iterator *csi, bool is_nop, tree dst, tree src)
+{
+ cil_stmt stmt;
+
+ if (is_nop && INTEGRAL_TYPE_P (dst) && INTEGRAL_TYPE_P (src))
+ {
+ if (TYPE_PRECISION (dst) > TYPE_PRECISION (src))
+ {
+ tree tmp = TYPE_UNSIGNED (src)
+ ? unsigned_type_for (dst)
+ : signed_type_for (dst);
+
+ gen_integral_conv (csi, tmp, src);
+ gen_integral_conv (csi, dst, tmp);
+ }
+ else
+ gen_integral_conv (csi, dst, src);
+ }
+
+ /* Special case for conversion to float type are not orthogonal
+ in CIL opcode set. */
+ else if (SCALAR_FLOAT_TYPE_P (dst)
+ && INTEGRAL_TYPE_P (src)
+ && TYPE_UNSIGNED (src))
+ {
+ stmt = cil_build_stmt (CIL_CONV_R_UN);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ if (TYPE_PRECISION (dst) <= 32)
+ {
+ stmt = cil_build_stmt (CIL_CONV_R4);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+
+ /* Do nothing for a conversion from two REAL_TYPEs with the
+ same precision or two pointers. */
+ else if (!SCALAR_FLOAT_TYPE_P (dst)
+ || !SCALAR_FLOAT_TYPE_P (src)
+ || TYPE_PRECISION (dst) != TYPE_PRECISION (src))
+ {
+ stmt = cil_build_stmt (conv_opcode_from_type (dst));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+}
+
+/* Generates the equivalent CIL code for rotate expressions. Since rotations
+ are not available in CIL they are emulated using shifts. */
+
+static void
+gen_rotate (cil_stmt_iterator *csi, tree node)
+{
+ bool left = (TREE_CODE (node) == LROTATE_EXPR);
+ tree op0, op1;
+ tree t1, t2;
+ tree uns_type;
+
+ /* Rotation is replaced by shifts on unsigned values:
+ generate the unsigned version of first operand type. */
+ op0 = TREE_OPERAND (node, 0);
+ uns_type = unsigned_type_for (TREE_TYPE (op0));
+ op0 = fold_convert (uns_type, op0);
+
+ /* Convert the second operand to 32-bit. */
+ op1 = fold_convert (intSI_type_node, TREE_OPERAND (node, 1));
+
+ /* Build first shift. */
+ t1 = fold_build2 (left ? LSHIFT_EXPR : RSHIFT_EXPR, uns_type, op0, op1);
+
+ /* Build second shift. */
+ t2 = fold_build2 (left ? RSHIFT_EXPR : LSHIFT_EXPR, uns_type,
+ op0,
+ fold_build2 (MINUS_EXPR, unsigned_intSI_type_node,
+ fold_convert (unsigned_intSI_type_node,
+ TYPE_SIZE (TREE_TYPE (op0))),
+ op1));
+
+ /* Build the rotate result. We do not use fold_build2() as it would
+ recreate the *ROTATE_EXPR. */
+ t1 = build2 (BIT_IOR_EXPR, uns_type, t1, t2);
+ t1 = fold_convert (TREE_TYPE (TREE_OPERAND (node, 0)), t1);
+
+ /* Generate the code */
+ gimple_to_cil_node (csi, t1);
+}
+
+/* Converts a GIMPLE/generic node into its CIL form. The generated statements
+ * are appended to the current function's CIL code using the CSI iterator. */
+
+static void
+gimple_to_cil_node (cil_stmt_iterator *csi, tree node)
+{
+ tree op0, op1;
+ cil_stmt stmt = NULL;
+ enum cil_opcode opcode;
+ bool uns;
+
+ if (node == NULL_TREE || node == error_mark_node)
+ return;
+
+ switch (TREE_CODE (node))
+ {
+ case INTEGER_CST:
+ gen_integer_cst (csi, node);
+
+ if (POINTER_TYPE_P (TREE_TYPE (node)))
+ {
+ stmt = cil_build_stmt (CIL_CONV_I);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ break;
+
+ case REAL_CST:
+ if (tree_low_cst (TYPE_SIZE (TREE_TYPE (node)), 1) == 32)
+ opcode = CIL_LDC_R4;
+ else
+ {
+ gcc_assert (tree_low_cst (TYPE_SIZE (TREE_TYPE (node)), 1) == 64);
+ opcode = CIL_LDC_R8;
+ }
+
+ stmt = cil_build_stmt_arg (opcode, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case COMPLEX_CST:
+ gen_complex (csi, TREE_TYPE (node),
+ TREE_REALPART (node),
+ TREE_IMAGPART (node));
+ break;
+
+ case VECTOR_CST:
+ {
+ unsigned int num_elt = 0;
+ tree elt;
+ tree vector_type = TREE_TYPE (node);
+ tree unit_type = TREE_TYPE (vector_type);
+
+ for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt))
+ {
+ tree elt_val = TREE_VALUE (elt);
+ gimple_to_cil_node (csi, elt_val);
+ ++num_elt;
+ }
+ /* Fill in the missing initializers, if any */
+ for ( ; num_elt < TYPE_VECTOR_SUBPARTS (vector_type); ++num_elt)
+ {
+ if (GET_MODE_CLASS (TYPE_MODE (unit_type)) == MODE_INT)
+ stmt = cil_build_stmt_arg (CIL_LDC_I4, integer_zero_node);
+ else if (GET_MODE_CLASS (TYPE_MODE (unit_type)) == MODE_FLOAT)
+ {
+ tree cst = build_real_from_int_cst (float_type_node,
+ integer_zero_node);
+
+ stmt = cil_build_stmt_arg (CIL_LDC_R4, cst);
+ }
+ else
+ gcc_unreachable ();
+
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ gen_vector_constructor (csi, vector_type);
+ break;
+ }
+
+ case LABEL_DECL:
+ gcc_unreachable ();
+ break;
+
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
+ op0 = GENERIC_TREE_OPERAND (node, 0);
+ op1 = GENERIC_TREE_OPERAND (node, 1);
+
+ if (TREE_CODE (op1) == CONSTRUCTOR || TREE_CODE (op1) == STRING_CST)
+ {
+ tree list = NULL_TREE;
+ tree_stmt_iterator tsi;
+
+ expand_init_to_stmt_list (op0, op1, &list);
+
+ for (tsi = tsi_start (list); !tsi_end_p (tsi); tsi_next (&tsi))
+ gimple_to_cil_node (csi, tsi_stmt (tsi));
+ }
+ else
+ gen_modify_expr (csi, op0, op1);
+
+ break;
+
+ case GOTO_EXPR:
+ internal_error ("GOTO_EXPRs shouldn't appear inside other trees or "
+ "before the end of a basic block\n");
+ break;
+
+ case COND_EXPR:
+ {
+ /* HACK: COND_EXPRs shouldn't appear here without proper vector
+ support, we should either implement proper vector support in
+ builtin-calls form or remove it alltogether. */
+ tree type = TREE_TYPE (node);
+ unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE (type), 1);
+ enum cil32_builtin builtin;
+
+ if (INTEGRAL_TYPE_P (type))
+ {
+ if (size <= 32)
+ builtin = CIL32_SELECTSI4;
+ else
+ builtin = CIL32_SELECTDI4;
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ if (size <= 32)
+ builtin = CIL32_SELECTSF4;
+ else
+ builtin = CIL32_SELECTDF4;
+ }
+ else
+ gcc_unreachable ();
+
+ gimple_to_cil_node (csi, COND_EXPR_COND (node));
+ gimple_to_cil_node (csi, COND_EXPR_THEN (node));
+ gimple_to_cil_node (csi, COND_EXPR_ELSE (node));
+ stmt = cil_build_call (cil32_builtins[builtin]);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ break;
+
+ case SWITCH_EXPR:
+ internal_error ("SWITCH_EXPRs shouldn't appear inside other trees or "
+ "before the end of a basic block\n");
+ break;
+
+ case CALL_EXPR:
+ gen_call_expr (csi, node);
+ break;
+
+ case MULT_EXPR:
+ case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
+ case MINUS_EXPR:
+ case RDIV_EXPR:
+ case LSHIFT_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gimple_to_cil_node (csi, op0);
+
+ if (TREE_CODE (node) == LSHIFT_EXPR)
+ gimple_to_cil_node (csi, fold_convert (intSI_type_node, op1));
+ else
+ gimple_to_cil_node (csi, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case MULT_EXPR: opcode = CIL_MUL; break;
+ case POINTER_PLUS_EXPR:
+ case PLUS_EXPR: opcode = CIL_ADD; break;
+ case MINUS_EXPR: opcode = CIL_SUB; break;
+ case RDIV_EXPR: opcode = CIL_DIV; break;
+ case LSHIFT_EXPR: opcode = CIL_SHL; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* Values with precision smaller than the one used
+ on the evaluation stack require an explicit conversion. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (node)))
+ gen_integral_conv (csi, TREE_TYPE (node), TREE_TYPE (node));
+ break;
+
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case BIT_IOR_EXPR: opcode = CIL_OR; break;
+ case BIT_XOR_EXPR: opcode = CIL_XOR; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* No need for conversions even in case of values with precision
+ smaller than the one used on the evaluation stack,
+ since for these operations the output is
+ always less or equal than both operands. */
+
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case BIT_AND_EXPR:
+ gen_bit_and_expr (csi, node);
+ break;
+
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
+ gen_compare_expr (csi, node);
+ 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);
+ uns = TYPE_UNSIGNED (TREE_TYPE (node));
+
+ gimple_to_cil_node (csi, op0);
+
+ if (TREE_CODE (node) == RSHIFT_EXPR)
+ gimple_to_cil_node (csi, fold_convert (intSI_type_node, op1));
+ else
+ gimple_to_cil_node (csi, op1);
+
+ switch (TREE_CODE (node))
+ {
+ case EXACT_DIV_EXPR:
+ case TRUNC_DIV_EXPR: opcode = uns ? CIL_DIV_UN : CIL_DIV; break;
+ case TRUNC_MOD_EXPR: opcode = uns ? CIL_REM_UN : CIL_REM; break;
+ case RSHIFT_EXPR: opcode = uns ? CIL_SHR_UN : CIL_SHR; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* No need for conversions even in case of values with precision
+ smaller than the one used on the evaluation stack,
+ since for these operations the output is
+ always less or equal than both operands. */
+ break;
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ gen_rotate (csi, node);
+ break;
+
+ case FLOOR_DIV_EXPR:
+ {
+ bool is_signed0, is_signed1;
+
+ op0 = TREE_OPERAND (node, 0);
+ op1 = TREE_OPERAND (node, 1);
+
+ gimple_to_cil_node (csi, op0);
+ gimple_to_cil_node (csi, 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)
+ {
+ stmt = cil_build_stmt (CIL_DIV_UN);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ else
+ internal_error ("\n\nFLOOR_DIV_EXPR is not completely supported\n");
+
+ /* No need for conversions even in case of values with precision
+ smaller than the one used on the evaluation stack,
+ since for these operations the output is
+ always less or equal than both operands. */
+ break;
+ }
+
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ gimple_to_cil_node (csi, TREE_OPERAND (node, 0));
+
+ opcode = (TREE_CODE (node) == NEGATE_EXPR) ? CIL_NEG : CIL_NOT;
+ stmt = cil_build_stmt (opcode);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+
+ /* Values with precision smaller than the one used
+ on the evaluation stack require an explicit conversion.
+ 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 (INTEGRAL_TYPE_P (TREE_TYPE (node)))
+ gen_integral_conv (csi, TREE_TYPE (node), TREE_TYPE (node));
+ break;
+
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ gen_addr_expr (csi, node);
+ gen_ldind (csi, TREE_TYPE (node), TREE_THIS_VOLATILE (node));
+ break;
+
+ case TARGET_MEM_REF:
+ gen_target_mem_ref (csi, node);
+ break;
+
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ /* TODO: if flag_trapv is set, we could generate the .ovf version? */
+ case FIX_TRUNC_EXPR:
+ case NOP_EXPR:
+ {
+ tree type;
+
+ op0 = GENERIC_TREE_OPERAND (node, 0);
+ gimple_to_cil_node (csi, op0);
+
+ /* Temporaries with weird types are handled correctly without need
+ for an explicit conversion as they have already been promoted. */
+ if ((TREE_CODE (node) == NOP_EXPR) && (TREE_CODE (op0) == VAR_DECL))
+ type = promote_local_var_type (op0);
+ else
+ type = TREE_TYPE (op0);
+
+ gen_conv (csi, TREE_CODE (node) == NOP_EXPR, TREE_TYPE (node), type);
+ }
+ break;
+
+ case LABEL_EXPR:
+ /* Skip this expression, labels are emitted later. TODO: Check that the
+ labels appear only at the beginning of a basic-block? */
+ break;
+
+ case RETURN_EXPR:
+ op0 = TREE_OPERAND (node, 0);
+
+ if (op0 != NULL_TREE)
+ {
+ if (TREE_CODE (op0) == MODIFY_EXPR
+ || TREE_CODE (op0) == GIMPLE_MODIFY_STMT)
+ op0 = GENERIC_TREE_OPERAND (op0, 1);
+
+ gimple_to_cil_node (csi, op0);
+ }
+ else if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ {
+ /* Pre-C99 code may contain void-returns for non-void functions.
+ In this case, return an artificially generated result variable. */
+ tree res_type = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+ if (TYPE_SIZE (res_type) != NULL_TREE
+ && TREE_CODE (TYPE_SIZE (res_type)) != INTEGER_CST)
+ {
+ internal_error ("Returned type cannot be a variable size array or"
+ " struct\n");
+ }
+
+ if (res_var == NULL_TREE)
+ res_var = create_tmp_var (res_type, "gimple2cil");
+
+ stmt = cil_build_stmt_arg (CIL_LDLOC, res_var);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ stmt = cil_build_stmt (CIL_RET);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case ASM_EXPR:
+ /* TODO: support just a simple string, no input/output/clober */
+ stmt = cil_build_stmt_arg (CIL_ASM, ASM_STRING (node));
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case MAX_EXPR:
+ case MIN_EXPR:
+ gen_minmax_expr (csi, node);
+ break;
+
+ case ABS_EXPR:
+ gen_abs_expr (csi, node);
+ break;
+
+ case SSA_NAME:
+ gcc_unreachable ();
+
+ case VAR_DECL:
+ case RESULT_DECL:
+ gen_var_decl (csi, node);
+ break;
+
+ case PARM_DECL:
+ mark_referenced_type (TREE_TYPE (node));
+ stmt = cil_build_stmt_arg (CIL_LDARG, node);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case FIELD_DECL:
+ case NAMESPACE_DECL:
+ internal_error ("CIL: Cannot handle FIELD_DECL or NAMESPACE_DECL");
+ break;
+
+ case TREE_LIST:
+ gcc_unreachable ();
+ break;
+
+ case FUNCTION_DECL:
+ case CONST_DECL:
+ gcc_unreachable ();
+ break;
+
+ case ADDR_EXPR:
+ gen_addr_expr (csi, TREE_OPERAND (node, 0));
+ break;
+
+ case COMPONENT_REF:
+ gen_comp_ref (csi, node);
+ break;
+
+ case TRUTH_NOT_EXPR:
+ gimple_to_cil_node (csi, TREE_OPERAND (node, 0));
+ gen_integer_cst (csi, integer_zero_node);
+ stmt = cil_build_stmt (CIL_CEQ);
+ csi_insert_after (csi, stmt, CSI_CONTINUE_LINKING);
+ break;
+
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ gen_truth_expr (csi, node);
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ gen_view_convert_expr (csi, node);
+ break;
+
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ gen_complex_part_expr (csi, node);
+ break;
+
+ case COMPLEX_EXPR:
+ gen_complex (csi, TREE_TYPE (node),
+ GENERIC_TREE_OPERAND (node, 0),
+ GENERIC_TREE_OPERAND (node, 1));
+ break;
+
+ case BIT_FIELD_REF:
+ if (TREE_CODE (TREE_TYPE (GENERIC_TREE_OPERAND (node, 0))) == VECTOR_TYPE)
+ gen_vector_bitfield_ref (csi, node);
+ else
+ gen_bit_field_ref (csi, node);
+
+ 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;
+ }
+}
+
+/* Records the addresses whose labels have been taken and generate the
+ appropriate switch labels to emulate computed GOTOs. Also ensure that all
+ basic blocks are properly labeled. */
+
+static void
+process_labels (void)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+ tree stmt;
+
+ /* Record all the labels whose address has been taken */
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ stmt = bsi_stmt (bsi);
+
+ /* Record the address taken labels. */
+ if (TREE_CODE (stmt) == LABEL_EXPR)
+ {
+ tree label = LABEL_EXPR_LABEL (stmt);
+ /* Check if the label has its address taken. */
+ if (FORCED_LABEL (label))
+ record_addr_taken_label (label);
+ }
+ }
+ }
+
+ /* Make sure that every bb has a label */
+ FOR_EACH_BB (bb)
+ {
+ tree_block_label (bb);
+ }
+}
+
+/* Looks for non structured types initializers specified as DECL_INIT
+ expressions attached to the declarations and turn them into a list of CIL
+ statements. The generated list is prepended to the instructions in the first
+ basic block of the current function. */
+
+static void
+process_initializers (void)
+{
+ cil_seq seq = cil_seq_alloc ();
+ cil_stmt_iterator csi = csi_start (seq);
+ cil_stmt_iterator bb_csi = csi_start_bb (single_succ (ENTRY_BLOCK_PTR));
+ tree cell;
+
+ for (cell = cfun->unexpanded_var_list; cell; cell = TREE_CHAIN (cell))
+ {
+ tree_stmt_iterator tsi;
+ tree var = TREE_VALUE (cell);
+ tree init = DECL_INITIAL (var);
+ tree list = NULL_TREE;
+
+ if (!TREE_STATIC (var) && init && init != error_mark_node)
+ {
+ expand_init_to_stmt_list (var, init, &list);
+
+ for (tsi = tsi_start (list); !tsi_end_p (tsi); tsi_next (&tsi))
+ gimple_to_cil_node (&csi, tsi_stmt (tsi));
+ }
+ }
+
+ csi_insert_seq_before (&bb_csi, seq, CSI_SAME_STMT);
+}
+
+/* Converts the GIMPLE/generic code of the current function in the CIL
+ intermediate representation */
+
+static unsigned int
+gimple_to_cil (void)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+ cil_stmt stmt;
+ cil_seq seq;
+ cil_stmt_iterator csi, prev_csi;
+ tree node = NULL_TREE;
+
+ /* Initialization */
+ res_var = NULL_TREE;
+
+ /* Preprocessing */
+ process_labels ();
+
+ FOR_EACH_BB (bb)
+ {
+ seq = cil_seq_alloc ();
+ cil_set_bb_seq (bb, seq);
+ csi = csi_start_bb (bb);
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ node = bsi_stmt (bsi);
+ prev_csi = csi;
+
+ switch (TREE_CODE (node))
+ {
+ case CALL_EXPR:
+ {
+ tree fun_expr = CALL_EXPR_FN (node);
+ tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr));
+
+ gen_call_expr (&csi, node);
+
+ if (!VOID_TYPE_P (TREE_TYPE (fun_type)))
+ {
+ csi_insert_after (&csi, cil_build_stmt (CIL_POP),
+ CSI_CONTINUE_LINKING);
+ }
+ }
+ break;
+
+ case GOTO_EXPR:
+ gcc_assert (bsi_stmt (bsi_last (bb)) == node);
+ gen_goto_expr (&csi, node);
+ break;
+
+ case COND_EXPR:
+ gcc_assert (bsi_stmt (bsi_last (bb)) == node);
+ gen_cond_expr (&csi, node);
+ break;
+
+ case SWITCH_EXPR:
+ gcc_assert (bsi_stmt (bsi_last (bb)) == node);
+ gen_switch_expr (&csi, node);
+ break;
+
+ default:
+ if (TREE_CODE (node) != NOP_EXPR
+ || TREE_CODE (TREE_OPERAND (node, 0)) != INTEGER_CST)
+ {
+ gimple_to_cil_node (&csi, node);
+ }
+ }
+
+ for (; !csi_end_p (prev_csi); csi_next (&prev_csi))
+ cil_set_locus (csi_stmt (prev_csi), EXPR_LOCUS (node));
+ }
+
+ if ((!node || (TREE_CODE (node) != 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. */
+ if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb))
+ {
+ tree label = tree_block_label (succ);
+
+ stmt = cil_build_stmt_arg (CIL_BR, label);
+ cil_set_locus (stmt, node ? EXPR_LOCUS (node) : NULL);
+ csi_insert_after (&csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+ else if (EDGE_COUNT (bb->succs) == 0)
+ {
+ bsi = bsi_last (bb);
+ node = bsi_stmt (bsi);
+
+ if (TREE_CODE (node) != RETURN_EXPR)
+ {
+ tree ret_type = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+ if (!VOID_TYPE_P (ret_type) && res_var == NULL_TREE)
+ res_var = create_tmp_var (ret_type, "gimple2cil");
+
+ if (res_var != NULL_TREE)
+ {
+ stmt = cil_build_stmt_arg (CIL_LDLOC, res_var);
+ csi_insert_after (&csi, stmt, CSI_CONTINUE_LINKING);
+ }
+
+ stmt = cil_build_stmt (CIL_RET);
+ csi_insert_after (&csi, stmt, CSI_CONTINUE_LINKING);
+ /* FIXME: Is this really needed? */
+ make_single_succ_edge (bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
+ }
+ }
+ }
+
+ /* Add the initializers to the entry block */
+ process_initializers ();
+
+ return 0;
+}
+
+/* Gate function of GIMPLE/generic-to-CIL conversion. */
+
+static bool
+gimple_to_cil_gate (void)
+{
+ return current_function_decl != NULL;
+}
+
+/* Define the parameters of the tree-final-simp-CIL pass. */
+
+struct tree_opt_pass pass_gimple_to_cil =
+{
+ "gimple2cil", /* name */
+ gimple_to_cil_gate, /* gate */
+ gimple_to_cil, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_GIMPLE_TO_CIL, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/missing-protos.c b/gcc/config/cil32/missing-protos.c
new file mode 100644
index 00000000000..5fbc62b5eaa
--- /dev/null
+++ b/gcc/config/cil32/missing-protos.c
@@ -0,0 +1,224 @@
+/* Function without prototype patching pass.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "errors.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "pointer-set.h"
+#include "cil-refs.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+#include "emit-cil.h"
+
+/******************************************************************************
+ * Globals *
+ ******************************************************************************/
+
+/* Pointer-map used to map parameters to their equivalent local variable. */
+static struct pointer_map_t *args_to_locals;
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static void create_replacement_args (void);
+static void replace_ldargs (void);
+static void replace_args (void);
+static unsigned int missing_protos (void);
+static bool missing_protos_gate (void);
+
+/******************************************************************************
+ * Pass implementation *
+ ******************************************************************************/
+
+/* Replaces the function arguments with local variables of the corresponding
+ type. Code is then injected for copying the arguments in the replacement
+ local variables. */
+
+static void
+create_replacement_args (void)
+{
+ tree args;
+ tree var;
+ void **slot;
+
+ args_to_locals = pointer_map_create ();
+
+ for (args = DECL_ARGUMENTS (current_function_decl);
+ args != NULL_TREE;
+ args = TREE_CHAIN (args))
+ {
+ tree type = TREE_TYPE (args);
+ tree promoted = DECL_ARG_TYPE (args);
+
+ if ((type != promoted) || cil_pointer_type_p (type))
+ {
+ var = create_tmp_var (type, IDENTIFIER_POINTER (DECL_NAME (args)));
+ slot = pointer_map_insert (args_to_locals, args);
+ gcc_assert (*slot == NULL);
+ *slot = var;
+ }
+ }
+}
+
+/* Replaces every instance of LDARG/LDARGA with a a LDLOC/LDLOCA to the
+ replacement argument. */
+
+static void
+replace_ldargs (void)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ basic_block bb;
+ enum cil_opcode opcode;
+ void **slot;
+
+ FOR_EACH_BB (bb)
+ {
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if (opcode == CIL_LDARG
+ || opcode == CIL_LDARGA
+ || opcode == CIL_STARG)
+ {
+ slot = pointer_map_contains (args_to_locals, cil_var (stmt));
+
+ if (slot)
+ {
+ switch (opcode)
+ {
+ case CIL_LDARG: opcode = CIL_LDLOC; break;
+ case CIL_LDARGA: opcode = CIL_LDLOCA; break;
+ case CIL_STARG: opcode = CIL_STLOC; break;
+ default:
+ gcc_unreachable ();
+ }
+
+ stmt = cil_build_stmt_arg (opcode, (tree) *slot);
+ csi_replace (&csi, stmt); /* Also updates the locus. */
+ }
+ }
+ }
+ }
+}
+
+/* Initialize the replacement variables. */
+
+static void
+replace_args (void)
+{
+ cil_seq seq = cil_seq_alloc ();
+ cil_stmt_iterator csi = csi_start (seq);
+ cil_stmt_iterator bb_csi = csi_start_bb (single_succ (ENTRY_BLOCK_PTR));
+ cil_stmt stmt;
+ tree args;
+ void **slot;
+
+ for (args = DECL_ARGUMENTS (current_function_decl);
+ args != NULL_TREE;
+ args = TREE_CHAIN (args))
+ {
+ slot = pointer_map_contains (args_to_locals, args);
+
+ if (slot != NULL)
+ {
+ stmt = cil_build_stmt_arg (CIL_LDARG, args);
+ csi_insert_after (&csi, stmt, CSI_CONTINUE_LINKING);
+ stmt = cil_build_stmt_arg (CIL_STLOC, (tree) *slot);
+ csi_insert_after (&csi, stmt, CSI_CONTINUE_LINKING);
+ }
+ }
+
+ csi_insert_seq_before (&bb_csi, seq, CSI_SAME_STMT);
+}
+
+
+/* Main function of this pass. Looks for functions w/o a prototype and replaces
+ their arguments with local variables of the correct types. All instances of
+ LDARG are replaced with LDLOCs except for the ones used for initializing the
+ replacement locals. Once the prototypeless function reaches the emission
+ point it's prototype is then printed using the 'promoted' argument types. */
+
+static unsigned int
+missing_protos (void)
+{
+ if (TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)) == NULL_TREE)
+ {
+ create_replacement_args ();
+ replace_ldargs ();
+ replace_args ();
+ pointer_map_destroy (args_to_locals);
+ }
+
+ return 0;
+}
+
+/* Gate function of the missing prototype functions patch pass. */
+
+static bool
+missing_protos_gate (void)
+{
+ return 1;
+}
+
+/* Define the parameters of the missing-protos pass. */
+
+struct tree_opt_pass pass_missing_protos =
+{
+ "missing_protos", /* name */
+ missing_protos_gate, /* gate */
+ missing_protos, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_MISSING_PROTOS, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/peephole.c b/gcc/config/cil32/peephole.c
new file mode 100644
index 00000000000..68bb337004c
--- /dev/null
+++ b/gcc/config/cil32/peephole.c
@@ -0,0 +1,149 @@
+/* This pass applies a few simple peephole optimizations.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static unsigned int cil_peephole (void);
+static bool cil_peephole_gate (void);
+
+/******************************************************************************
+ * Pass implementation *
+ ******************************************************************************/
+
+/* Main function of this pass, do some peephole optimizations:
+ LDLOCA/LDIND -> LDLOC
+ LDARGA/LDIND -> LDARG
+ LDLOCA/<instr>/STIND -> <instr>/STLOC
+ LDARGA/<instr>/STIND -> <instr>/STLOC */
+
+static unsigned int
+cil_peephole (void)
+{
+ basic_block bb;
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ tree var;
+ bool loc;
+
+ FOR_EACH_BB (bb)
+ {
+ csi = csi_start_bb (bb);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if (((opcode == CIL_LDLOCA) || (opcode == CIL_LDARGA))
+ && !csi_one_before_end_p (csi))
+ {
+ var = cil_var (stmt);
+ loc = (opcode == CIL_LDLOCA);
+ csi_next (&csi);
+ stmt = csi_stmt (csi);
+
+ if (cil_ldind_p (stmt) && !cil_prefix_volatile (stmt))
+ {
+ csi_prev (&csi);
+ csi_remove (&csi);
+ opcode = loc ? CIL_LDLOC : CIL_LDARG;
+ csi_replace (&csi, cil_build_stmt_arg (opcode, var));
+ }
+ else if (cil_push_p (stmt) && !csi_one_before_end_p (csi))
+ {
+ csi_next (&csi);
+ stmt = csi_stmt (csi);
+
+ if (cil_stind_p (stmt) && !cil_prefix_volatile (stmt))
+ {
+ csi_prev (&csi);
+ csi_prev (&csi);
+ csi_remove (&csi);
+ csi_next (&csi);
+ opcode = loc ? CIL_STLOC : CIL_STARG;
+ csi_replace (&csi, cil_build_stmt_arg (opcode, var));
+ }
+ }
+ }
+ else
+ csi_next (&csi);
+ }
+ }
+
+ return 0;
+}
+
+/* Gate function of the peephole-optimizations pass. */
+
+static bool
+cil_peephole_gate (void)
+{
+ return true;
+}
+
+/* Define the parameters of the peephole-optimizations pass. */
+
+struct tree_opt_pass pass_cil_peephole =
+{
+ "cil_peephole", /* name */
+ cil_peephole_gate, /* gate */
+ cil_peephole, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_CIL_PEEPHOLE, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/remove-convs.c b/gcc/config/cil32/remove-convs.c
new file mode 100644
index 00000000000..9aa52b6ee33
--- /dev/null
+++ b/gcc/config/cil32/remove-convs.c
@@ -0,0 +1,329 @@
+/* This pass tries to remove redundant conversions which may have been
+ introduced during GIMPLE-to-CIL expansion. This pass is currently
+ implemented as a somewhat elaborate peephole optimizer, to make it
+ optimal however it should be reimplemented using proper DFA.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "errors.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "pointer-set.h"
+#include "cil-refs.h"
+#include "cil-stack.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static bool cil_store_p (const_cil_stmt);
+static bool fold_store_conversion (const_cil_stmt, enum cil_opcode, cil_type_t);
+static bool fold_conversion (enum cil_opcode, cil_type_t);
+static unsigned int remove_convs (void);
+static bool remove_convs_gate (void);
+
+/******************************************************************************
+ * Pass implementation *
+ ******************************************************************************/
+
+/* Return TRUE if OPCODE is a store (either indirect, to a field or to a
+ variable), FALSE otherwise. */
+
+static bool
+cil_store_p (const_cil_stmt stmt)
+{
+ switch (cil_opcode (stmt))
+ {
+ case CIL_STARG:
+ case CIL_STFLD:
+ case CIL_STIND_I1:
+ case CIL_STIND_I2:
+ case CIL_STIND_I4:
+ case CIL_STIND_I8:
+ case CIL_STIND_R4:
+ case CIL_STIND_R8:
+ case CIL_STIND_I:
+ case CIL_STLOC:
+ case CIL_STOBJ:
+ case CIL_STSFLD:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if the conversion from type SRC by CONV before executing the
+ store STORE is redundant, false otherwise. */
+
+static bool
+fold_store_conversion (const_cil_stmt store, enum cil_opcode conv,
+ cil_type_t src)
+{
+ cil_type_t dst;
+ tree type;
+
+ if (!cil_int_or_smaller_p (src))
+ return false;
+
+ switch (cil_opcode (store))
+ {
+ case CIL_STARG:
+ case CIL_STLOC:
+ type = TREE_TYPE (cil_var (store));
+
+ if (INTEGRAL_TYPE_P (type))
+ dst = scalar_to_cil (type);
+ else
+ return false;
+
+ break;
+
+ case CIL_STFLD:
+ case CIL_STSFLD:
+ type = TREE_TYPE (cil_field (store));
+
+ if (INTEGRAL_TYPE_P (type))
+ dst = scalar_to_cil (type);
+ else
+ return false;
+
+ break;
+
+ case CIL_STIND_I1:
+ dst = CIL_INT8;
+ break;
+
+ case CIL_STIND_I2:
+ dst = CIL_INT16;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (dst)
+ {
+ case CIL_INT8:
+ case CIL_UNSIGNED_INT8:
+ return true;
+
+ case CIL_INT16:
+ case CIL_UNSIGNED_INT16:
+ if ((conv == CIL_CONV_I1) || (conv == CIL_CONV_U1))
+ return false;
+ else
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Fold the conversion specified by OP with an input of type TYPE. If the
+ converion can be folded return TRUE, otherwise return FALSE. */
+
+static bool
+fold_conversion (enum cil_opcode op, cil_type_t type)
+{
+ switch (op)
+ {
+ case CIL_CONV_U1:
+ if (type == CIL_UNSIGNED_INT8)
+ return true;
+
+ break;
+
+ case CIL_CONV_I2:
+ if (type == CIL_UNSIGNED_INT8)
+ return true;
+
+ break;
+
+ case CIL_CONV_U2:
+ if ((type == CIL_UNSIGNED_INT8) || (type == CIL_UNSIGNED_INT16))
+ return true;
+
+ break;
+
+ case CIL_CONV_I4:
+ case CIL_CONV_U4:
+ if ((type == CIL_INT8) || (type == CIL_UNSIGNED_INT8)
+ || (type == CIL_INT16) || (type == CIL_UNSIGNED_INT16)
+ || (type == CIL_INT32) || (type == CIL_UNSIGNED_INT32))
+ {
+ return true;
+ }
+
+ break;
+
+ case CIL_CONV_I8:
+ case CIL_CONV_U8:
+ if ((type == CIL_INT64) || (type == CIL_UNSIGNED_INT64))
+ return true;
+
+ break;
+
+ case CIL_CONV_R4:
+ if (type == CIL_FLOAT32)
+ return true;
+
+ break;
+
+ case CIL_CONV_R8:
+ if (type == CIL_FLOAT64)
+ return true;
+
+ break;
+
+ case CIL_CONV_I:
+ case CIL_CONV_U:
+ if (cil_native_integer_p (type))
+ return true;
+
+ break;
+
+ default:
+ ;
+ }
+
+ return false;
+}
+
+/* Main function of this pass. */
+
+static unsigned int
+remove_convs (void)
+{
+ basic_block bb;
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ edge_iterator ei;
+ edge e;
+ cil_bb_stacks bbs;
+ cil_stack stack;
+ cil_type_t type;
+
+ bbs = cil_bb_stacks_create ();
+
+ FOR_EACH_BB (bb)
+ {
+ stack = cil_stack_for_bb (bbs, bb);
+ csi = csi_start_bb (bb);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if (cil_conversion_p (stmt))
+ {
+ type = cil_stack_top (stack);
+
+ if (fold_conversion (opcode, type))
+ {
+ csi_remove (&csi);
+ continue;
+ }
+ else if (!csi_one_before_end_p (csi))
+ {
+ csi_next (&csi);
+
+ if (cil_store_p (csi_stmt (csi))
+ && fold_store_conversion (csi_stmt (csi), opcode, type))
+ {
+ csi_prev (&csi);
+ csi_remove (&csi);
+ continue;
+ }
+ else
+ csi_prev (&csi);
+ }
+ }
+
+ cil_stack_after_stmt (stack, stmt);
+ csi_next (&csi);
+ }
+
+ /* We're done with this basic block. Copy the stack at the end of the
+ block into the successors so that they will be able to access it and
+ then free the current stack as we're done with it. */
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ cil_set_stack_for_bb (bbs, e->dest, stack);
+ }
+ }
+
+ cil_bb_stacks_destroy (bbs);
+ return 0;
+}
+
+/* Gate function of the remove-convs pass. */
+
+static bool
+remove_convs_gate (void)
+{
+ return true;
+}
+
+/* Define the parameters of the remove-temps pass. */
+
+struct tree_opt_pass pass_remove_convs =
+{
+ "remove_convs", /* name */
+ remove_convs_gate, /* gate */
+ remove_convs, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REMOVE_CONVS, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/remove-temps.c b/gcc/config/cil32/remove-temps.c
new file mode 100644
index 00000000000..f8314d471e8
--- /dev/null
+++ b/gcc/config/cil32/remove-temps.c
@@ -0,0 +1,841 @@
+/* This pass is made of two different optimization steps which try to
+ remove redundant local variables which have been generated during the
+ GIMPLE-to-CIL expansion.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "errors.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "pointer-set.h"
+#include "cil-refs.h"
+#include "cil-stack.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+
+/******************************************************************************
+ * Globals *
+ ******************************************************************************/
+
+/* Holds all the local variables and arguments whose argument was taken. */
+static struct pointer_set_t *address_taken_vars;
+
+/* Dummy variable used as a marker when flagging visited basic blocks. */
+static int marker = 0;
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static void visit_bb (basic_block);
+static bool visited_p (basic_block);
+
+static void record_address_taken_vars (void);
+static cil_stmt build_conversion (cil_type_t, cil_type_t);
+static bool remove_matching_ldloc (cil_stmt_iterator, cil_stack, tree, bool);
+static void stloc_ldloc_to_dup (void);
+static bool compatible_vars_p (tree, tree);
+static void propagate_copy_1 (basic_block, tree, tree, bool);
+static void propagate_copy (cil_stmt, tree, tree, bool);
+static void simple_copy_propagation (void);
+static bool dead_store_1 (basic_block, tree);
+static bool dead_store_p (cil_stmt);
+static void remove_dead_stores (void);
+static unsigned int remove_temps (void);
+static bool remove_temps_gate (void);
+
+/******************************************************************************
+ * Pass implementation *
+ ******************************************************************************/
+
+/* Flag a basic block as visited. */
+
+static void
+visit_bb (basic_block bb)
+{
+ bb->aux = (void *) &marker;
+}
+
+/* Return TRUE if the basic block BB has already been visited, FALSE otherwise.
+ */
+
+static bool
+visited_p (basic_block bb)
+{
+ return (bb->aux != NULL);
+}
+
+/* Records in a pointer set all the variables and arguments whose address was
+ taken. */
+
+static void
+record_address_taken_vars (void)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+
+ switch (cil_opcode (stmt))
+ {
+ case CIL_LDLOCA:
+ case CIL_LDARGA:
+ pointer_set_insert (address_taken_vars, cil_var (stmt));
+ break;
+
+ default:
+ ;
+ }
+ }
+ }
+}
+
+/* Creates a conversion from type SRC to type DST if it is needed, return the
+ conversion or NULL if it is not needed. This function works only on 32-bit
+ or smaller integer types, conversions between other types are not considered
+ as there are no assignment with implicit conversions between variables of
+ those types. */
+
+static cil_stmt
+build_conversion (cil_type_t dst, cil_type_t src)
+{
+ enum cil_opcode opcode;
+
+ switch (dst)
+ {
+ case CIL_INT8:
+ switch (src)
+ {
+ case CIL_INT16:
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT8:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ opcode = CIL_CONV_I1;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ case CIL_INT16:
+ switch (src)
+ {
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT8:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ opcode = CIL_CONV_I2;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ case CIL_UNSIGNED_INT8:
+ switch (src)
+ {
+ case CIL_INT8:
+ case CIL_INT16:
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT16:
+ case CIL_UNSIGNED_INT32:
+ opcode = CIL_CONV_U1;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ case CIL_UNSIGNED_INT16:
+ switch (src)
+ {
+ case CIL_INT8:
+ case CIL_INT16:
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT32:
+ opcode = CIL_CONV_U2;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ default:
+ /* Nothing to do */
+ return NULL;
+ }
+
+ return cil_build_stmt (opcode);
+}
+
+/* Looks for a LDLOC instruction operating on variable VAR using the CSI
+ iterator and tries to remove it. STACK is a copy of the stack
+ representation right after the matching STLOC was executed. A matching
+ LDLOC instruction can be removed if the stack depth never shrinks below the
+ initial depth of STACK and the depth before executing the LDLOC is the same
+ as STACK's and VAR was not altered in the meantime. If ADDRESS_TAKEN is
+ true the address of VAR was taken, in this case a LDLOC will be removed only
+ if it follows immediately the corresponding STLOC. */
+
+static bool
+remove_matching_ldloc (cil_stmt_iterator csi, cil_stack stack, tree var,
+ bool address_taken)
+{
+ size_t min_depth = cil_stack_depth (stack);
+ size_t nargs;
+ cil_stmt stmt;
+
+ for (csi_next (&csi); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+
+ if ((cil_opcode (stmt) == CIL_STLOC) && (cil_var (stmt) == var))
+ break;
+ else if ((cil_opcode (stmt) == CIL_LDLOC)
+ && (cil_var (stmt) == var)
+ && (cil_stack_depth (stack) == min_depth))
+ {
+ csi_remove (&csi);
+ return true;
+ }
+ else if (address_taken)
+ return false;
+
+ switch (cil_opcode (stmt))
+ {
+ case CIL_ADD:
+ case CIL_AND:
+ case CIL_CEQ:
+ case CIL_CGT:
+ case CIL_CGT_UN:
+ case CIL_CLT:
+ case CIL_CLT_UN:
+ case CIL_DIV:
+ case CIL_DIV_UN:
+ case CIL_MUL:
+ case CIL_OR:
+ case CIL_REM:
+ case CIL_REM_UN:
+ case CIL_SHL:
+ case CIL_SHR:
+ case CIL_SHR_UN:
+ case CIL_SUB:
+ case CIL_XOR:
+ if (cil_stack_depth (stack) - 2 < min_depth)
+ return false;
+
+ break;
+
+ case CIL_ARGLIST:
+ case CIL_CKFINITE:
+ case CIL_CONV_I1:
+ case CIL_CONV_I2:
+ case CIL_CONV_I4:
+ case CIL_CONV_I8:
+ case CIL_CONV_R4:
+ case CIL_CONV_R8:
+ case CIL_CONV_U1:
+ case CIL_CONV_U2:
+ case CIL_CONV_U4:
+ case CIL_CONV_U8:
+ case CIL_CONV_I:
+ case CIL_CONV_U:
+ case CIL_CONV_R_UN:
+ case CIL_DUP:
+ case CIL_LDFLD:
+ case CIL_LDFLDA:
+ case CIL_LDIND_I1:
+ case CIL_LDIND_I2:
+ case CIL_LDIND_I4:
+ case CIL_LDIND_I8:
+ case CIL_LDIND_U1:
+ case CIL_LDIND_U2:
+ case CIL_LDIND_U4:
+ case CIL_LDIND_U8:
+ case CIL_LDIND_R4:
+ case CIL_LDIND_R8:
+ case CIL_LDIND_I:
+ case CIL_LDOBJ:
+ case CIL_NEG:
+ case CIL_NOT:
+ if (cil_stack_depth (stack) == min_depth)
+ return false;
+
+ break;
+
+ case CIL_CALL:
+ case CIL_JMP:
+ nargs = cil_call_nargs (stmt)
+ + (cil_call_static_chain (stmt) ? 1 : 0);
+
+ if (cil_stack_depth (stack) - nargs < min_depth)
+ return false;
+
+ break;
+
+ case CIL_CALLI:
+ nargs = cil_call_nargs (stmt) + 1
+ + (cil_call_static_chain (stmt) ? 1 : 0);
+
+ if (cil_stack_depth (stack) - nargs < min_depth)
+ return false;
+
+ break;
+
+ case CIL_ASM:
+ case CIL_LOCALLOC:
+ /* localloc instructions must be executed with an empty stack. */
+ return false;
+
+ default:
+ ;
+ }
+
+ cil_stack_after_stmt (stack, stmt);
+
+ if (cil_stack_depth (stack) < min_depth)
+ return false;
+ }
+
+ return false;
+}
+
+/* Replaces STLOC/LDLOC instruction couples accessing the same variable with
+ DUP/STLOC couples. */
+
+static void
+stloc_ldloc_to_dup (void)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt, conv, dup;
+ basic_block bb;
+ edge_iterator ei;
+ edge e;
+ tree var;
+ cil_stack stack, tstack;
+ cil_bb_stacks bbs;
+ cil_type_t type;
+ bool addr_taken;
+
+ bbs = cil_bb_stacks_create ();
+
+ FOR_EACH_BB (bb)
+ {
+ stack = cil_stack_for_bb (bbs, bb);
+
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+
+ if (cil_opcode (stmt) == CIL_STLOC)
+ {
+ var = cil_var (stmt);
+ addr_taken = pointer_set_contains (address_taken_vars, var);
+ tstack = cil_stack_copy (stack);
+ cil_stack_after_stmt (tstack, stmt);
+
+ if (remove_matching_ldloc (csi, tstack, var, addr_taken))
+ {
+ if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
+ {
+ /* Writing an integral type from the stack to a variable
+ of smaller size may cause an implicit conversion,
+ reproduce this conversion on the stack if needed. This
+ a win anyway as a CONV/DUP couple is in the worst case
+ as large as the STLOC/LDLOC couple it replaces but
+ allows for the variable to be removed. */
+ type = scalar_to_cil (TREE_TYPE (var));
+ conv = build_conversion (type, cil_stack_top (stack));
+
+ if (conv)
+ {
+ csi_insert_before (&csi, conv, CSI_SAME_STMT);
+ cil_stack_after_stmt (stack, conv);
+ }
+ }
+
+ dup = cil_build_stmt (CIL_DUP);
+ csi_insert_before (&csi, dup, CSI_SAME_STMT);
+ cil_stack_after_stmt (stack, dup);
+ }
+
+ cil_stack_free (tstack);
+ }
+
+ cil_stack_after_stmt (stack, stmt);
+ }
+
+ /* We're done with this basic block. Copy the stack at the end of the
+ block into the successors so that they will be able to access it and
+ then free the current stack as we're done with it. */
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ cil_set_stack_for_bb (bbs, e->dest, stack);
+ }
+ }
+
+ cil_bb_stacks_destroy (bbs);
+}
+
+/* Return true if DST and SRC have compatible types for replacement. */
+
+static bool
+compatible_vars_p (tree dst, tree src)
+{
+ tree dst_type = TYPE_MAIN_VARIANT (TREE_TYPE (dst));
+ tree src_type = TYPE_MAIN_VARIANT (TREE_TYPE (src));
+ cil_type_t dst_cil, src_cil;
+
+ if (dst_type == src_type)
+ return true;
+ else
+ {
+ if (INTEGRAL_TYPE_P (dst_type) && INTEGRAL_TYPE_P (src_type))
+ {
+ dst_cil = scalar_to_cil (dst_type);
+ src_cil = scalar_to_cil (src_type);
+
+ if (src_cil == dst_cil)
+ return true;
+
+ switch (dst_cil)
+ {
+ case CIL_INT16:
+ case CIL_UNSIGNED_INT16:
+ if ((src_cil == CIL_INT8) || (src_cil == CIL_UNSIGNED_INT8))
+ return true;
+
+ break;
+
+ case CIL_INT32:
+ case CIL_UNSIGNED_INT32:
+ return true; /* No loss of precision from smaller types. */
+
+ case CIL_INT64:
+ case CIL_UNSIGNED_INT64:
+ return true; /* Always explicitely converted. */
+
+ break;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* Helper function used for implementing the recursive call of the
+ propagate_copy() function. */
+
+static void
+propagate_copy_1 (basic_block bb, tree dst, tree src, bool arg)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ edge e;
+ edge_iterator ei;
+
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if ((opcode == CIL_LDLOC) && (cil_var (stmt) == dst))
+ {
+ stmt = cil_build_stmt_arg (arg ? CIL_LDARG : CIL_LDLOC, src);
+ csi_replace (&csi, stmt);
+ }
+ else if (((opcode == CIL_STLOC) || (opcode == CIL_STARG))
+ && ((cil_var (stmt) == src) || (cil_var (stmt) == dst)))
+ {
+ return;
+ }
+ else if (opcode == CIL_RET)
+ return;
+ }
+
+ visit_bb (bb);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (!visited_p (e->dest))
+ {
+ visit_bb (e->dest);
+
+ if (single_pred_p (e->dest))
+ propagate_copy_1 (e->dest, dst, src, arg);
+ }
+ }
+}
+
+/* Propagate the copy of variable SRC into variable DST starting from the
+ statement STMT. If ARG is true then SRC is an argument, if it is false
+ then SRC is a local variable. */
+
+static void
+propagate_copy (cil_stmt store, tree dst, tree src, bool arg)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ basic_block bb = cil_bb (store);
+ edge e;
+ edge_iterator ei;
+
+ csi = csi_for_stmt (store);
+ csi_next (&csi);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if ((opcode == CIL_LDLOC) && (cil_var (stmt) == dst))
+ {
+ stmt = cil_build_stmt_arg (arg ? CIL_LDARG : CIL_LDLOC, src);
+ csi_replace (&csi, stmt);
+ }
+ else if (((opcode == CIL_STLOC) || (opcode == CIL_STARG))
+ && ((cil_var (stmt) == src) || (cil_var (stmt) == dst)))
+ {
+ return;
+ }
+ else if (opcode == CIL_RET)
+ return;
+
+ csi_next (&csi);
+ }
+
+ visit_bb (bb);
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (!visited_p (e->dest))
+ {
+ visit_bb (e->dest);
+
+ if (single_pred_p (e->dest))
+ propagate_copy_1 (e->dest, dst, src, arg);
+ }
+ }
+
+ clear_aux_for_blocks ();
+}
+
+/* Does a simple copy propagation trying to replace copies of a local variable
+ or argument with the original definition. Stores to the temporary copy are
+ left in the code as they will be removed - if they are dead - by a later
+ pass. */
+
+static void
+simple_copy_propagation (void)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ basic_block bb;
+ tree src;
+
+ FOR_EACH_BB (bb)
+ {
+ csi = csi_start_bb (bb);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if (((opcode == CIL_LDLOC) || (opcode == CIL_LDARG))
+ && !pointer_set_contains (address_taken_vars, cil_var (stmt))
+ && !csi_one_before_end_p (csi))
+ {
+ src = cil_var (stmt);
+ csi_next (&csi);
+ stmt = csi_stmt (csi);
+
+ if (cil_opcode (stmt) == CIL_STLOC
+ && compatible_vars_p (cil_var (stmt), src))
+ {
+ propagate_copy (stmt, cil_var (stmt), src,
+ opcode == CIL_LDARG);
+ }
+ }
+ else
+ csi_next (&csi);
+ }
+ }
+}
+
+/* Helper function used for implementing dead_store_p(). Scans the basic block
+ BB and its non visited successors for loads from the variable VAR. */
+
+static bool
+dead_store_1 (basic_block bb, tree var)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ edge e;
+ edge_iterator ei;
+
+ for (csi = csi_start_bb (bb); !csi_end_p (csi); csi_next (&csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if ((opcode == CIL_LDLOC) && (cil_var (stmt) == var))
+ return false;
+ else if ((opcode == CIL_STLOC) && (cil_var (stmt) == var))
+ return true;
+ else if (opcode == CIL_RET)
+ return true;
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (!visited_p (e->dest))
+ {
+ visit_bb (e->dest);
+
+ if (!dead_store_1 (e->dest, var))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Returns TRUE if the target local variable of the store specified by STORE is
+ never read from, FALSE otherwise. */
+
+static bool
+dead_store_p (cil_stmt store)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ tree var = cil_var (store);
+ basic_block bb = cil_bb (store);
+ edge e;
+ edge_iterator ei;
+
+ csi = csi_for_stmt (store);
+ csi_next (&csi);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if ((opcode == CIL_LDLOC) && (cil_var (stmt) == var))
+ return false;
+ else if ((opcode == CIL_STLOC) && (cil_var (stmt) == var))
+ return true;
+ else if (opcode == CIL_RET)
+ return true;
+
+ csi_next (&csi);
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (!visited_p (e->dest))
+ {
+ visit_bb (e->dest);
+
+ if (!dead_store_1 (e->dest, var))
+ {
+ clear_aux_for_blocks ();
+ return false;
+ }
+ }
+ }
+
+ clear_aux_for_blocks ();
+ return true;
+}
+
+/* Looks for stores to variables which are never read, remove those stores and
+ mark the related variables as written to assembly, this will prevent the
+ compiler from emitting them later. */
+
+static void
+remove_dead_stores (void)
+{
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ basic_block bb;
+
+ /* Remove all stores to variables which haven't been read back. The
+ instructions used to load the value written on the stack should also be
+ removed but doing it under complex conditions might be tricky so we only
+ catch simple cases for now. The algorythm may be improved in the future
+ by using DFA. */
+
+ FOR_EACH_BB (bb)
+ {
+ csi = csi_start_bb (bb);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+
+ if ((cil_opcode (stmt) == CIL_STLOC)
+ && !pointer_set_contains (address_taken_vars, cil_var (stmt))
+ && dead_store_p (stmt))
+ {
+ /* We found a dead store, we'll remove or replace it. */
+
+ if (!csi_first_p (csi))
+ {
+ csi_prev (&csi);
+ stmt = csi_stmt (csi);
+
+ if (cil_push_p (stmt))
+ {
+ /* We remove the store and the instruction feeding it. */
+ csi_remove (&csi);
+ csi_remove (&csi);
+ continue;
+ }
+ else if (cil_conversion_p (stmt) && !csi_first_p (csi))
+ {
+ csi_prev (&csi);
+ stmt = csi_stmt (csi);
+
+ if (cil_push_p (stmt))
+ {
+ /* We remove the store, the conversion and the
+ instruction feeding it. */
+ csi_remove (&csi);
+ csi_remove (&csi);
+ csi_remove (&csi);
+ continue;
+ }
+ else
+ csi_next (&csi);
+ }
+
+ /* We cannot remove the instruction feeding this store,
+ instead we replace the store with a pop. */
+ csi_next (&csi);
+ csi_replace (&csi, cil_build_stmt (CIL_POP));
+ csi_next (&csi);
+ }
+ else
+ {
+ /* This is the first instruction in the block, we transform
+ it into a pop. */
+ csi_replace (&csi, cil_build_stmt (CIL_POP));
+ csi_next (&csi);
+ }
+ }
+ else
+ csi_next (&csi);
+ }
+ }
+}
+
+/* Main function of this pass. */
+
+static unsigned int
+remove_temps (void)
+{
+ /* Create pass-specific data. */
+ address_taken_vars = pointer_set_create ();
+
+ /* Pass processing. */
+ record_address_taken_vars ();
+ stloc_ldloc_to_dup ();
+ simple_copy_propagation ();
+ remove_dead_stores ();
+
+ /* Dispose of pass-specific data. */
+ pointer_set_destroy (address_taken_vars);
+
+ return 0;
+}
+
+/* Gate function of the remove-temps pass. */
+
+static bool
+remove_temps_gate (void)
+{
+ return true;
+}
+
+/* Define the parameters of the remove-temps pass. */
+
+struct tree_opt_pass pass_remove_temps =
+{
+ "remove_temps", /* name */
+ remove_temps_gate, /* gate */
+ remove_temps, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REMOVE_TEMPS, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/rm-ldloc.c b/gcc/config/cil32/rm-ldloc.c
deleted file mode 100644
index 0272084dc9c..00000000000
--- a/gcc/config/cil32/rm-ldloc.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
-
- Copyright (C) 2006, 2007 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:
-Andrea C. Ornstein <andrea.ornstein@st.com>
-Erven Rohou <erven.rohou@st.com>
-*/
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "diagnostic.h"
-#include "tree-flow.h"
-#include "pointer-set.h"
-#include "gen-cil.h"
-
-/* Local functions, macros and variables. */
-static void mark_var_defs_uses (tree);
-static void remove_stloc_ldloc_1 (block_stmt_iterator, tree *, bool *);
-
-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;
-
-
-/* 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 || node == error_mark_node)
- return;
-
- 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 arg;
- call_expr_arg_iterator iter;
-
- mark_var_defs_uses (CALL_EXPR_FN (node));
-
- FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
- mark_var_defs_uses (arg);
- }
- break;
-
- case MULT_EXPR:
- case PLUS_EXPR:
- case POINTER_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:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case COMPLEX_EXPR:
- mark_var_defs_uses (TREE_OPERAND (node, 0));
- mark_var_defs_uses (TREE_OPERAND (node, 1));
- break;
-
- case INIT_EXPR:
- case MODIFY_EXPR:
- case GIMPLE_MODIFY_STMT:
- {
- tree lhs = GENERIC_TREE_OPERAND (node, 0);
- tree rhs = GENERIC_TREE_OPERAND (node, 1);
-
- if (TREE_CODE (lhs) == VAR_DECL)
- {
- if (! TREE_ADDRESSABLE (lhs)
- && ! TREE_STATIC (lhs)
- && ! TREE_SIDE_EFFECTS (lhs)
- && ! DECL_FILE_SCOPE_P (lhs))
- {
- TREE_LANG_FLAG_0 (lhs) = false;
-
- 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
- TREE_LANG_FLAG_0 (lhs) = true;
- }
- else
- mark_var_defs_uses (lhs);
-
- mark_var_defs_uses (rhs);
-
- if (AGGREGATE_TYPE_P (TREE_TYPE (lhs)) && TREE_CODE (rhs) == VAR_DECL)
- TREE_LANG_FLAG_0 (rhs) = true;
-
- 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 ABS_EXPR:
- case WITH_SIZE_EXPR:
- case VIEW_CONVERT_EXPR:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- mark_var_defs_uses (TREE_OPERAND (node, 0));
- break;
-
- case RETURN_EXPR:
- {
- tree op = TREE_OPERAND (node, 0);
-
- if (op)
- {
- if (TREE_CODE (op) == MODIFY_EXPR
- || TREE_CODE (op) == GIMPLE_MODIFY_STMT)
- op = GENERIC_TREE_OPERAND (op, 1);
-
- mark_var_defs_uses (op);
- }
- }
- break;
-
- case ARRAY_REF:
- gcc_assert (integer_zerop (TREE_OPERAND (node, 1)));
- case ADDR_EXPR:
- case COMPONENT_REF:
- case INDIRECT_REF:
- {
- tree op = TREE_OPERAND (node, 0);
-
- mark_var_defs_uses (op);
- if (AGGREGATE_TYPE_P (TREE_TYPE (op)) && TREE_CODE (op) == VAR_DECL)
- TREE_LANG_FLAG_0 (op) = true;
- }
- break;
-
- case COMPLEX_CST:
- 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))
- {
- TREE_LANG_FLAG_0 (node) = false;
-
- 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);
- }
- else
- TREE_LANG_FLAG_0 (node) = true;
- break;
-
- default:
- fprintf (stderr, "mark_var_defs_uses: Cannot handle '%s' ",
- tree_code_name [TREE_CODE (node)]);
- 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_1 (block_stmt_iterator bsi, tree *node_ptr, bool *mod)
-{
- tree node = *node_ptr;
- block_stmt_iterator prev_bsi;
-
- if (node == NULL_TREE || node == error_mark_node)
- return;
-
- /* 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_1 (bsi, &COND_EXPR_COND (node), mod);
- break;
-
- case SWITCH_EXPR:
- remove_stloc_ldloc_1 (bsi, &SWITCH_COND (node), mod);
- break;
-
- case CALL_EXPR:
- {
- unsigned int aidx = 0;
- unsigned int nargs = call_expr_nargs(node);
-
- for (;aidx<nargs;++aidx)
- remove_stloc_ldloc_1 (bsi, &CALL_EXPR_ARG (node, aidx), mod);
-
- }
- break;
-
- case MULT_EXPR:
- case PLUS_EXPR:
- case POINTER_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:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- remove_stloc_ldloc_1 (bsi, &TREE_OPERAND (node, 0), mod);
- remove_stloc_ldloc_1 (bsi, &TREE_OPERAND (node, 1), mod);
- break;
-
- case INIT_EXPR:
- case MODIFY_EXPR:
- case GIMPLE_MODIFY_STMT:
- if (TREE_CODE (GENERIC_TREE_OPERAND (node, 0)) != VAR_DECL)
- remove_stloc_ldloc_1 (bsi, &GENERIC_TREE_OPERAND (node, 0), mod);
- remove_stloc_ldloc_1 (bsi, &GENERIC_TREE_OPERAND (node, 1), mod);
- gcc_assert (TREE_CODE (GENERIC_TREE_OPERAND (node, 1)) != CONSTRUCTOR
- && TREE_CODE (GENERIC_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 ADDR_EXPR:
- case COMPONENT_REF:
- case INDIRECT_REF:
- case ARRAY_REF:
- case ABS_EXPR:
- case WITH_SIZE_EXPR:
- remove_stloc_ldloc_1 (bsi, &TREE_OPERAND (node, 0), mod);
- break;
-
- case RETURN_EXPR:
- {
- tree op = TREE_OPERAND (node, 0);
-
- if (op)
- {
- if (TREE_CODE (op) == MODIFY_EXPR || TREE_CODE (op) == GIMPLE_MODIFY_STMT)
- remove_stloc_ldloc_1 (bsi, &GENERIC_TREE_OPERAND (op, 1), mod);
- else
- remove_stloc_ldloc_1 (bsi, &TREE_OPERAND (node, 0), mod);
- }
- }
- break;
-
- case VAR_DECL:
- /* mark_var_defs_uses (...) function sets TREE_LANG_FLAG_0
- for some variables that shouldn't be removed. */
- if (! TREE_LANG_FLAG_0 (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_CODE (prev_stmt) == GIMPLE_MODIFY_STMT)
- && GENERIC_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 = GENERIC_TREE_OPERAND (prev_stmt, 1);
-
- /* Remove the previous statement */
- bsi_remove (&prev_bsi, true);
-
- /* Set that the function changed something */
- *mod = true;
- }
- }
- break;
-
- default:
- ;
- }
-}
-
-void
-remove_stloc_ldloc (void)
-{
- basic_block bb;
- block_stmt_iterator bsi;
-
- /* 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))
- {
- tree stmt = bsi_stmt (bsi);
-
- mark_var_defs_uses (stmt);
- }
- }
- 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_1 (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);
-}
-
-/*
- * Local variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/gcc/config/cil32/simp-cond.c b/gcc/config/cil32/simp-cond.c
new file mode 100644
index 00000000000..e40c44fdc31
--- /dev/null
+++ b/gcc/config/cil32/simp-cond.c
@@ -0,0 +1,197 @@
+/* This pass tries to simplify conditional expression made of a couple of
+ conditional/unconditional branches if one of the two outgoing paths falls
+ through to the next basic block.
+
+ Copyright (C) 2006-2008 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 Ornstein
+ Erven Rohou
+ Gabriele Svelto
+
+Contact information at STMicroelectronics:
+Andrea C. Ornstein <andrea.ornstein@st.com>
+Erven Rohou <erven.rohou@st.com>
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "timevar.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "cil-stack.h"
+#include "cil-stmt.h"
+#include "cil-types.h"
+
+/******************************************************************************
+ * Local functions prototypes *
+ ******************************************************************************/
+
+static void simplify_cond_branch (cil_stmt_iterator *, cil_stack);
+static unsigned int simp_cond (void);
+static bool simp_cond_gate (void);
+
+/******************************************************************************
+ * Pass implementation *
+ ******************************************************************************/
+
+static void
+simplify_cond_branch (cil_stmt_iterator *csi, cil_stack stack)
+{
+ cil_stmt stmt;
+ cil_type_t type;
+ enum cil_opcode opcode;
+ tree label_then, label_else;
+ basic_block then_bb;
+ edge true_edge, false_edge;
+
+ /* Extract the condition's edges. */
+ extract_true_false_edges_from_block (csi_bb (*csi), &true_edge, &false_edge);
+ label_then = tree_block_label (true_edge->dest);
+ label_else = tree_block_label (false_edge->dest);
+
+ then_bb = label_to_block (label_then);
+
+ /* Simplify the condition only if the 'then' edge can be turned into a
+ fall through to the next basic block. */
+ if (csi_bb (*csi)->next_bb == then_bb)
+ {
+ type = cil_stack_top (stack);
+
+ if (cil_integer_p (type) || cil_pointer_p (type))
+ {
+ switch (cil_opcode (csi_stmt (*csi)))
+ {
+ case CIL_BEQ: opcode = CIL_BNE_UN; break;
+ case CIL_BGE: opcode = CIL_BLT; break;
+ case CIL_BGE_UN: opcode = CIL_BLT_UN; break;
+ case CIL_BGT: opcode = CIL_BLE; break;
+ case CIL_BGT_UN: opcode = CIL_BLE_UN; break;
+ case CIL_BLE: opcode = CIL_BGT; break;
+ case CIL_BLE_UN: opcode = CIL_BGT_UN; break;
+ case CIL_BLT: opcode = CIL_BGE; break;
+ case CIL_BLT_UN: opcode = CIL_BGE_UN; break;
+ case CIL_BNE_UN: opcode = CIL_BEQ; break;
+ default:
+ return; /* Do nothing, we cannot change this branch. */
+ }
+
+ stmt = cil_build_stmt_arg (opcode, label_else);
+ csi_replace (csi, stmt);
+ csi_next (csi);
+ csi_remove (csi);
+
+ /* Invert the out-going edges */
+ true_edge->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ false_edge->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ }
+ }
+}
+
+/* Main function of this pass. Looks for conditional expressions and
+ inverts their condition if it allows removing the unconditional branch
+ following it. */
+
+static unsigned int
+simp_cond (void)
+{
+ basic_block bb;
+ cil_stmt_iterator csi;
+ cil_stmt stmt;
+ enum cil_opcode opcode;
+ cil_bb_stacks bbs;
+ cil_stack stack;
+ edge_iterator ei;
+ edge e;
+
+ bbs = cil_bb_stacks_create ();
+
+ FOR_EACH_BB (bb)
+ {
+ stack = cil_stack_for_bb (bbs, bb);
+ csi = csi_start_bb (bb);
+
+ while (!csi_end_p (csi))
+ {
+ stmt = csi_stmt (csi);
+ opcode = cil_opcode (stmt);
+
+ if (cil_cond_branch_p (stmt) && !csi_one_before_end_p (csi))
+ {
+ csi_next (&csi);
+
+ if (cil_opcode (csi_stmt (csi)) == CIL_BR)
+ {
+ csi_prev (&csi);
+ simplify_cond_branch (&csi, stack);
+ break;
+ }
+ }
+
+ cil_stack_after_stmt (stack, stmt);
+ csi_next (&csi);
+ }
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ cil_set_stack_for_bb (bbs, e->dest, stack);
+ }
+ }
+
+ cil_bb_stacks_destroy (bbs);
+ return 0;
+}
+
+/* Gate function of the peephole-optimizations pass. */
+
+static bool
+simp_cond_gate (void)
+{
+ return true;
+}
+
+/* Define the parameters of the cond-simp pass. */
+
+struct tree_opt_pass pass_simp_cond =
+{
+ "cond_simp", /* name */
+ simp_cond_gate, /* gate */
+ simp_cond, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_SIMP_COND, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0,
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/gcc/config/cil32/t-cil32 b/gcc/config/cil32/t-cil32
index 9c07fa97813..9c4129d5283 100644
--- a/gcc/config/cil32/t-cil32
+++ b/gcc/config/cil32/t-cil32
@@ -1,6 +1,6 @@
# Hi emacs, use Makefile syntax mode. -*-mode: Makefile; -*-
-# Copyright (C) 2006-2007 Free Software Foundation, Inc.
+# Copyright (C) 2006-2008 Free Software Foundation, Inc.
#
# This file is part of GCC.
#
@@ -36,8 +36,9 @@ bit-stream.o: $(srcdir)/config/cil32/bit-stream.c \
cil-refs.o : $(srcdir)/config/cil32/cil-refs.c \
$(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-types.h \
- $(CONFIG_H) $(GGC_H) $(HASHTAB_H) $(SYSTEM_H) $(TM_H) $(TREE_H) coretypes.h \
- debug.h errors.h gt-cil-refs.h vec.h
+ $(CONFIG_H) $(FUNCTION_H) $(GGC_H) $(HASHTAB_H) $(SYSTEM_H) $(TM_H) \
+ $(TREE_H) $(TREE_GIMPLE_H) $(TREE_PASS_H) coretypes.h debug.h errors.h \
+ gt-cil-refs.h toplev.h vec.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
$(srcdir)/config/cil32/cil-builtins.h: $(srcdir)/config/cil32/cil-builtins.def
@@ -45,44 +46,87 @@ $(srcdir)/config/cil32/cil-builtins.h: $(srcdir)/config/cil32/cil-builtins.def
cil-builtins.o : $(srcdir)/config/cil32/cil-builtins.c \
$(srcdir)/config/cil32/cil-builtins.h $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
- $(srcdir)/config/cil32/cil-builtins.def coretypes.h langhooks.h
+ $(srcdir)/config/cil32/cil-builtins.def coretypes.h gt-cil-builtins.h \
+ langhooks.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
emit-hints.o: $(srcdir)/config/cil32/emit-hints.c \
$(srcdir)/config/cil32/emit-hints.h $(srcdir)/config/cil32/bit-stream.h \
- $(srcdir)/config/cil32/gen-cil.h $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) \
- $(TREE_FLOW_H) coretypes.h
+ $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) coretypes.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
-gen-cil.o: $(srcdir)/config/cil32/gen-cil.c $(srcdir)/config/cil32/gen-cil.h \
- $(srcdir)/config/cil32/emit-hints.h $(srcdir)/config/cil32/tree-simp-cil.h \
- $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-types.h \
- $(CONFIG_H) $(DIAGNOSTIC_H) $(HASHTAB_H) $(SYSTEM_H) \
- $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) coretypes.h ggc.h langhooks.h \
- output.h pointer-set.h real.h toplev.h tree-iterator.h tree-pass.h varray.h
+cil-stack.o : $(srcdir)/config/cil32/cil-stack.c \
+ $(srcdir)/config/cil32/cil-stack.c $(srcdir)/config/cil32/cil-stack.h \
+ $(srcdir)/config/cil32/cil-stmt.h $(srcdir)/config/cil32/cil-types.h \
+ $(CONFIG_H) $(GGC_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) \
+ coretypes.h errors.h vec.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
-rm-ldloc.o: $(srcdir)/config/cil32/rm-ldloc.c $(srcdir)/config/cil32/gen-cil.h \
- $(CONFIG_H) $(DIAGNOSTIC_H) $(SYSTEM_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) \
- coretypes.h pointer-set.h
+cil-stmt.o : $(srcdir)/config/cil32/cil-stmt.c \
+ $(srcdir)/config/cil32/cil-stmt.h $(srcdir)/config/cil32/cil-stmt-inline.h \
+ $(srcdir)/config/cil32/cil-types.h $(CONFIG_H) $(GGC_H) $(SYSTEM_H) $(TM_H) \
+ $(TREE_H) $(TREE_FLOW_H) coretypes.h errors.h gt-cil-stmt.h input.h \
+ pointer-set.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 $(srcdir)/config/cil32/cil-refs.h \
- $(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) \
- coretypes.h toplev.h tree-pass.h
+gimple-to-cil.o : $(srcdir)/config/cil32/gimple-to-cil.c \
+ $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-stmt.h \
+ $(srcdir)/config/cil32/cil-types.h $(CONFIG_H) $(FLAGS_H) $(GGC_H) \
+ $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_PASS_H) \
+ coretypes.h errors.h pointer-set.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
-tree-simp-cil-early.o: $(srcdir)/config/cil32/tree-simp-cil-early.c \
- $(srcdir)/config/cil32/tree-simp-cil.h $(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) \
- $(TM_H) $(TREE_H) coretypes.h toplev.h tree-gimple.h tree-pass.h \
+emit-cil.o : $(srcdir)/config/cil32/emit-cil.c \
+ $(srcdir)/config/cil32/emit-cil.h $(srcdir)/config/cil32/emit-hints.h \
+ $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-stmt.h \
+ $(srcdir)/config/cil32/cil-types.h $(CONFIG_H) $(GGC_H) $(SYSTEM_H) \
+ $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_PASS_H) coretypes.h \
+ ebitmap.h errors.h langhooks.h output.h varray.h pointer-set.h real.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+missing-protos.o : $(srcdir)/config/cil32/missing-protos.c \
+ $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-stmt.h \
+ $(srcdir)/config/cil32/cil-types.h $(CONFIG_H) $(FLAGS_H) $(SYSTEM_H) \
+ $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_PASS_H) coretypes.h errors.h \
pointer-set.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+peephole.o : $(srcdir)/config/cil32/peephole.c \
+ $(srcdir)/config/cil32/cil-stmt.h $(srcdir)/config/cil32/cil-types.h \
+ $(CONFIG_H) $(FLAGS_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) \
+ $(TREE_PASS_H) coretypes.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+remove-convs.o : $(srcdir)/config/cil32/remove-convs.c \
+ $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-stack.h \
+ $(srcdir)/config/cil32/cil-stmt.h $(srcdir)/config/cil32/cil-types.h \
+ $(CONFIG_H) $(FLAGS_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) \
+ $(TREE_PASS_H) coretypes.h errors.h pointer-set.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+remove-temps.o : $(srcdir)/config/cil32/remove-temps.c \
+ $(srcdir)/config/cil32/cil-refs.h $(srcdir)/config/cil32/cil-stack.h \
+ $(srcdir)/config/cil32/cil-stmt.h $(srcdir)/config/cil32/cil-types.h \
+ $(CONFIG_H) $(FLAGS_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) \
+ $(TREE_PASS_H) coretypes.h errors.h pointer-set.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+simp-cond.o : $(srcdir)/config/cil32/simp-cond.c \
+ $(srcdir)/config/cil32/cil-stack.h $(srcdir)/config/cil32/cil-stmt.h \
+ $(srcdir)/config/cil32/cil-types.h $(CONFIG_H) $(FLAGS_H) $(SYSTEM_H) \
+ $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_PASS_H) coretypes.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
+tree-simp-cil-early.o: $(srcdir)/config/cil32/tree-simp-cil-early.c \
+ $(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) coretypes.h \
+ toplev.h tree-gimple.h tree-pass.h pointer-set.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
+
bb-layout.o: $(srcdir)/config/cil32/bb-layout.c \
$(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) $(TREE_FLOW_H) \
coretypes.h tree-pass.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
-$(out_object_file): gt-cil-refs.h
gt-cil-refs.h : s-gtype ; @true
+gt-cil-stmt.h : s-gtype ; @true
+gt-cil-builtins.h : s-gtype ; @true
diff --git a/gcc/config/cil32/tree-simp-cil-early.c b/gcc/config/cil32/tree-simp-cil-early.c
index 845cb12d340..aa57e030471 100644
--- a/gcc/config/cil32/tree-simp-cil-early.c
+++ b/gcc/config/cil32/tree-simp-cil-early.c
@@ -21,6 +21,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
Authors:
+ Andrea Ornstein
+ Erven Rohou
Gabriele Svelto
Contact information at STMicroelectronics:
@@ -32,13 +34,12 @@ Erven Rohou <erven.rohou@st.com>
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "timevar.h"
#include "tree.h"
#include "tree-gimple.h"
#include "tree-iterator.h"
#include "tree-pass.h"
-#include "timevar.h"
#include "pointer-set.h"
-#include "tree-simp-cil.h"
/******************************************************************************
* Type definitions *
@@ -67,11 +68,9 @@ static void case_range_to_cond_expr (tree, tree, tree *);
static void cases_to_switch (tree, unsigned int, unsigned int, tree *);
static tree simp_cil_switch (tree);
-/* Bit-field conversion functions */
-static tree bf_vector_container_address (tree, unsigned HOST_WIDE_INT, tree,
- tree *);
-static tree simp_lhs_vector_bitfield_ref (tree);
-static tree simp_rhs_vector_bitfield_ref (tree);
+/* Misc functionality */
+static void set_statement_list_location (tree, location_t);
+static bool is_copy_required (tree);
/* Top-level functionality */
static tree simp_cil_stmt (tree);
@@ -96,7 +95,7 @@ static struct pointer_map_t *eqv_labels = NULL;
/* Set the location of the statements in the statement list pointed by LIST to
the location passed in LOCUS */
-void
+static void
set_statement_list_location (tree list, location_t locus)
{
tree_stmt_iterator tsi = tsi_start (list);
@@ -108,6 +107,32 @@ set_statement_list_location (tree list, location_t locus)
}
}
+/* 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;
+ }
+}
+
/******************************************************************************
* Label manipulation functions *
******************************************************************************/
@@ -536,115 +561,6 @@ simp_cil_switch (tree switch_stmt)
}
/******************************************************************************
- * Bit-field access modes information *
- ******************************************************************************/
-
-/* Get the address of the container suitable for replacing a BIT_FIELD_REF
- expression used for accessing the element of a vector. The container type is
- pointed by CONT_TYPE, BIT_OFFSET holds the offset of the element from the
- base address of the vector pointed by OBJ. Put the calculated address in the
- location pointed by DST_PTR. */
-
-static tree
-bf_vector_container_address (tree cont_type, unsigned HOST_WIDE_INT bit_offset,
- tree obj, tree *dst_ptr)
-{
- tree stmt;
- tree obj_ptr, cont_ptr;
- tree obj_ptr_type, cont_ptr_type;
- tree list = NULL_TREE;
-
- cont_ptr_type = build_pointer_type (cont_type);
- cont_ptr = create_tmp_var (cont_ptr_type, "cilsimp");
- *dst_ptr = cont_ptr;
- obj_ptr_type = build_pointer_type (TREE_TYPE (obj));
- obj_ptr = create_tmp_var (obj_ptr_type, "cilsimp");
-
- stmt = build_gimple_modify_stmt (obj_ptr,
- build_fold_addr_expr (obj));
- append_to_statement_list (stmt, &list);
-
- stmt = build_gimple_modify_stmt(cont_ptr,
- build1 (NOP_EXPR, cont_ptr_type, obj_ptr));
- append_to_statement_list (stmt, &list);
-
- if (bit_offset > 0)
- {
- tree offset_tree = build_int_cst (long_unsigned_type_node,
- bit_offset / BITS_PER_UNIT);
-
- stmt = build_gimple_modify_stmt (cont_ptr,
- build2 (POINTER_PLUS_EXPR, cont_ptr_type,
- cont_ptr,
- offset_tree));
- append_to_statement_list (stmt, &list);
- }
-
- return list;
-}
-
-/* Simplify a GIMPLE_MODIFY_STMT pointed by BF_STMT with a BIT_FIELD_REF as its
- right hand side operand used to extract a component from a vector. Return a
- statement list holding the replacement code. */
-
-static tree
-simp_rhs_vector_bitfield_ref (tree bf_stmt)
-{
- tree op_rhs = GIMPLE_STMT_OPERAND (bf_stmt, 1);
- tree obj = TREE_OPERAND (op_rhs, 0);
- unsigned HOST_WIDE_INT bit_offset;
- tree list = NULL_TREE;
- tree cont_type;
- tree cont_ptr;
- tree stmt;
-
- /* Create the necessary types and temp variables */
- cont_type = TREE_TYPE (TREE_TYPE (obj));
-
- /* Compute the element address and store it in CONT_PTR */
- bit_offset = tree_low_cst (TREE_OPERAND (op_rhs, 2), 1);
- list = bf_vector_container_address (cont_type, bit_offset, obj, &cont_ptr);
-
- /* Load the element from the vector and store it in the left hand side
- variable */
- stmt = build_gimple_modify_stmt (GIMPLE_STMT_OPERAND (bf_stmt, 0),
- build1 (INDIRECT_REF, cont_type, cont_ptr));
- append_to_statement_list (stmt, &list);
-
- return list;
-}
-
-/* Simplify a GIMPLE_MODIFY_STMT pointed by BF_STMT with a BIT_FIELD_REF as its
- left hand side operand used to insert a component inside a vector. Return a
- statement list holding the replacement code. */
-
-static tree
-simp_lhs_vector_bitfield_ref (tree bf_stmt)
-{
- tree op_lhs = GIMPLE_STMT_OPERAND (bf_stmt, 0);
- tree obj = TREE_OPERAND (op_lhs, 0);
- unsigned HOST_WIDE_INT bit_offset;
- tree list = NULL_TREE;
- tree cont_type;
- tree cont_ptr;
- tree stmt;
-
- /* Create the necessary types and temp variables */
- cont_type = TREE_TYPE (TREE_TYPE (obj));
-
- /* Compute the element address and store it in CONT_PTR */
- bit_offset = tree_low_cst (TREE_OPERAND (op_lhs, 2), 1);
- list = bf_vector_container_address (cont_type, bit_offset, obj, &cont_ptr);
-
- /* Store the value inside the vector */
- stmt = build_gimple_modify_stmt (build1 (INDIRECT_REF, cont_type, cont_ptr),
- GIMPLE_STMT_OPERAND (bf_stmt, 1));
- append_to_statement_list (stmt, &list);
-
- return list;
-}
-
-/******************************************************************************
* Top-level functionality *
******************************************************************************/
@@ -661,25 +577,6 @@ simp_cil_stmt (tree stmt)
list = simp_cil_switch (stmt);
break;
- case GIMPLE_MODIFY_STMT:
- {
- tree op_lhs = GIMPLE_STMT_OPERAND (stmt, 0);
- tree op_rhs = GIMPLE_STMT_OPERAND (stmt, 1);
-
- if (TREE_CODE (op_lhs) == BIT_FIELD_REF)
- {
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (op_lhs, 0))) == VECTOR_TYPE)
- list = simp_lhs_vector_bitfield_ref (stmt);
- }
- else if (TREE_CODE (op_rhs) == BIT_FIELD_REF)
- {
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (op_rhs, 0))) == VECTOR_TYPE)
- list = simp_rhs_vector_bitfield_ref (stmt);
- }
-
- break;
- }
-
default:
break;
}
diff --git a/gcc/config/cil32/tree-simp-cil.c b/gcc/config/cil32/tree-simp-cil.c
deleted file mode 100644
index f8f9fe58000..00000000000
--- a/gcc/config/cil32/tree-simp-cil.c
+++ /dev/null
@@ -1,2286 +0,0 @@
-/* Simplify GENERIC trees before CIL emission.
-
- Copyright (C) 2006-2007 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
- Gabriele Svelto
-
-Contact information at STMicroelectronics:
-Andrea C. Ornstein <andrea.ornstein@st.com>
-Erven Rohou <erven.rohou@st.com>
-*/
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "tree-flow.h"
-#include "tree-pass.h"
-#include "timevar.h"
-#include "toplev.h"
-#include "tree-simp-cil.h"
-#include "cil-refs.h"
-#include "cil-builtins.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 COND_EXPR nodes used as expressions (not statements).
- 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 BIT_FIELD_REF nodes.
- 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.
-
- *) 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 with non-zero indexes into
- ARRAY_REF with zero indexes.
- 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).
- Remark that such a simplification must keep ARRAY_REFs,
- they cannot be replaced by INDIRECT_REF nodes in order
- not to break strict aliasing.
-
- *) 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.
-
- *) 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.
-
- *) Forcing arguments of CALL_EXPRs to be local variables, only for
- specific built-in functions.
- A few built-in functions require special simplifications
- in order to make their emission easier; in particular:
- *) the 1st argument of BUILT_IN_VA_START, BUILT_IN_VA_END and
- CIL32_BUILT_IN_VA_ARG has to be a variable or an ADDR_EXPR node.
- More in general, this is true any time va_list is passed
- as a parameter.
- *) the 1st argument of BUILT_IN_VA_COPY has to be a local variable
- (the emitted CIL uses a 'stloc' to store its value).
- To force arguments of calls to be local variables, new local
- variables are generated.
-
- *) Expansion of UNEQ_EXPR, UNLE_EXPR and UNGE_EXPR nodes.
- CIL instruction set has some support for unordered comparisons,
- but it is not orthogonal. Whenever an unordered comparison
- is difficult to be translated in CIL, it is expanded by this pass.
- While this always happens for UNEQ_EXPRs, there is a case in which
- UNLE_EXPRs and UNGE_EXPRs are kept.
-
- *) Expansion of LTGT_EXPR nodes.
- There is no equivalent in CIL instruction set and it is more
- convenient not to require the CIL emission pass to handle it.
-
- *) Inversion of targets for statements with COND_EXPR nodes
- in which the goto target is fallthru.
- This isn't strictly necessary, but it helps the CIL emission pass
- to avoid the generation of a branch opcode.
-
- *) 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.
-
- *) Ensure that there is always a return statement
- Even in case the block ends with a call to a noreturn function
-*/
-
-/* Local functions, macros and variables. */
-static void simp_cond_stmt (block_stmt_iterator, tree);
-static void simp_builtin_call (block_stmt_iterator, tree *);
-static void simp_abs (block_stmt_iterator *, tree *);
-static void simp_min_max (block_stmt_iterator *, tree *);
-static void simp_cond_expr (block_stmt_iterator *, tree *);
-static void simp_unordered_comp_expr (block_stmt_iterator *, tree *);
-static void simp_ltgt_expr (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 compute_array_ref_base_disp (tree, tree *, 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 simp_bitfield_ref (block_stmt_iterator *, tree *);
-static void pre_simp_init (block_stmt_iterator *, tree, tree, tree);
-static void simp_cil_node (block_stmt_iterator *, tree *);
-static void split_use (block_stmt_iterator, tree *, bool);
-static void rename_var (tree, const char*, unsigned long);
-static void simp_vars (void);
-static unsigned int simp_cil_final (void);
-static bool simp_cil_gate (void);
-
-#define UPDATE_ADDRESSABLE(NODE) \
-do { tree _node = (NODE); \
- for (; handled_component_p (_node); _node = TREE_OPERAND (_node, 0)) \
- ; \
- if (TREE_CODE (_node) == VAR_DECL || TREE_CODE (_node) == PARM_DECL) \
- TREE_ADDRESSABLE (_node) = 1; } while (0)
-
-static bool simp_final;
-static tree res_var;
-
-static GTY(()) tree two = NULL_TREE;
-static GTY(()) tree bits_per_unit = NULL_TREE;
-
-/* Return the integer type with size BITS bits.
- The type is unsigned or signed depending on UNS. */
-
-tree
-get_integer_type (int bits, bool uns)
-{
- if (uns)
- {
- switch (bits)
- {
- case 8: return unsigned_intQI_type_node;
- case 16: return unsigned_intHI_type_node;
- case 32: return unsigned_intSI_type_node;
- case 64: return unsigned_intDI_type_node;
- case 128: return unsigned_intTI_type_node;
- default:
- gcc_assert (0);
- return NULL_TREE;
- }
- }
- else
- {
- switch (bits)
- {
- case 8: return intQI_type_node;
- case 16: return intHI_type_node;
- case 32: return intSI_type_node;
- case 64: return intDI_type_node;
- case 128: return intTI_type_node;
- default:
- 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). */
-
-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;
-
- switch (TREE_CODE (node))
- {
- case COND_EXPR:
- if (bsi_stmt (*bsi) == node)
- {
- tree cond = COND_EXPR_COND (node);
-
- /* UNLE_EXPR and UNGE_EXPR nodes are usually simplified.
- This is the exception, in this case it is better
- to keep them, since there is a convenient CIL translation. */
- if (TREE_CODE (cond) == UNLE_EXPR || TREE_CODE (cond) == UNGE_EXPR)
- {
- simp_cil_node (bsi, &TREE_OPERAND (cond, 0));
- simp_cil_node (bsi, &TREE_OPERAND (cond, 1));
- }
- else
- simp_cil_node (bsi, &COND_EXPR_COND (node));
-
- if (simp_final)
- simp_cond_stmt (*bsi, node);
- }
- else
- {
- simp_cil_node (bsi, &COND_EXPR_COND (node));
- simp_cil_node (bsi, &COND_EXPR_THEN (node));
- simp_cil_node (bsi, &COND_EXPR_ELSE (node));
- if (simp_final)
- simp_cond_expr (bsi, node_ptr);
- }
- break;
-
- case SWITCH_EXPR:
- simp_cil_node (bsi, &SWITCH_COND (node));
- break;
-
- case CALL_EXPR:
- {
- unsigned int aidx = 0;
- unsigned int nargs = call_expr_nargs(node);
-
- simp_cil_node (bsi, &CALL_EXPR_FN (node));
-
- for (;aidx<nargs;++aidx)
- simp_cil_node (bsi, &CALL_EXPR_ARG (node, aidx));
-
- if (simp_final)
- {
- tree fun_expr = CALL_EXPR_FN (node);
- tree dfun = NULL_TREE;
-
- if (TREE_CODE (fun_expr) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (fun_expr, 0)) == FUNCTION_DECL)
- dfun = TREE_OPERAND (fun_expr, 0);
-
- /* Calls to some built-in funs require ad-hoc simplifications */
- if (dfun && DECL_BUILT_IN (dfun))
- simp_builtin_call (*bsi, node_ptr);
- }
- }
- break;
-
- case MULT_EXPR:
- case PLUS_EXPR:
- case POINTER_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 UNLT_EXPR:
- case UNGT_EXPR:
- case UNORDERED_EXPR:
- case ORDERED_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 LTGT_EXPR:
- simp_cil_node (bsi, &TREE_OPERAND (node, 0));
- simp_cil_node (bsi, &TREE_OPERAND (node, 1));
- simp_ltgt_expr (bsi, node_ptr);
- break;
-
- case UNLE_EXPR:
- case UNGE_EXPR:
- case UNEQ_EXPR:
- simp_cil_node (bsi, &TREE_OPERAND (node, 0));
- simp_cil_node (bsi, &TREE_OPERAND (node, 1));
- simp_unordered_comp_expr (bsi, node_ptr);
- 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:
- case GIMPLE_MODIFY_STMT:
- simp_cil_node (bsi, &GENERIC_TREE_OPERAND (node, 0));
- simp_cil_node (bsi, &GENERIC_TREE_OPERAND (node, 1));
- gcc_assert (TREE_CODE (GENERIC_TREE_OPERAND (node, 1)) != CONSTRUCTOR
- && TREE_CODE (GENERIC_TREE_OPERAND (node, 1)) != STRING_CST);
- if (AGGREGATE_TYPE_P (TREE_TYPE (GENERIC_TREE_OPERAND (node, 1)))
- && TREE_CODE (GENERIC_TREE_OPERAND (node, 0)) == INDIRECT_REF
- && TREE_CODE (GENERIC_TREE_OPERAND (node, 1)) == CALL_EXPR)
- split_use (*bsi, &GENERIC_TREE_OPERAND (node, 1), false);
- 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 REALPART_EXPR:
- case IMAGPART_EXPR:
- simp_cil_node (bsi, &TREE_OPERAND (node, 0));
- break;
-
- case ADDR_EXPR:
- if (TREE_CODE (TREE_OPERAND (node, 0)) == ARRAY_REF)
- {
- tree *t = &TREE_OPERAND (node, 0);
- bool non_zero_indexes = false;
-
- /* Simplify operands (of nested ARRAY_REFs as well) */
- do {
- simp_cil_node (bsi, &TREE_OPERAND (*t, 1));
- if (! integer_zerop (TREE_OPERAND (*t, 1)))
- non_zero_indexes = true;
- t = &TREE_OPERAND (*t, 0);
- } while (TREE_CODE (*t) == ARRAY_REF);
- simp_cil_node (bsi, t);
-
- /* Reduce the ARRAY_REF to a zero-index array access */
- if (non_zero_indexes)
- {
- simp_array_ref (bsi, &TREE_OPERAND (node, 0));
- *node_ptr = TREE_OPERAND (node, 0);
- /* The current node may require further simplification */
- simp_cil_node (bsi, node_ptr);
- }
- else
- recompute_tree_invariant_for_addr_expr (node);
- }
- else
- {
- 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), false);
- recompute_tree_invariant_for_addr_expr (node);
- }
- 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), false);
- 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), false);
- if (simp_final && DECL_BIT_FIELD (TREE_OPERAND (node, 1)))
- {
- tree stmt = bsi_stmt (*bsi);
-
- if ((TREE_CODE (stmt) == MODIFY_EXPR
- || TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
- && GENERIC_TREE_OPERAND (stmt, 0) == node)
- simp_lhs_bitfield_component_ref (bsi, node_ptr);
- else
- simp_rhs_bitfield_component_ref (bsi, node_ptr);
- }
- break;
-
- case BIT_FIELD_REF:
- 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), false);
- gcc_assert (TREE_CODE (bsi_stmt (*bsi)) != MODIFY_EXPR
- || TREE_OPERAND (bsi_stmt (*bsi), 0) != node);
- if (simp_final)
- simp_bitfield_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);
- /* The current node may require further simplification */
- simp_cil_node (bsi, node_ptr);
- break;
-
- case ARRAY_REF:
- {
- tree *t = node_ptr;
- bool non_zero_indexes = false;
-
- /* Simplify operands (of nested ARRAY_REFs as well) */
- do {
- simp_cil_node (bsi, &TREE_OPERAND (*t, 1));
- if (! integer_zerop (TREE_OPERAND (*t, 1)))
- non_zero_indexes = true;
- t = &TREE_OPERAND (*t, 0);
- } while (TREE_CODE (*t) == ARRAY_REF);
- simp_cil_node (bsi, t);
-
- /* Reduce the ARRAY_REF to a zero-index array access */
- if (non_zero_indexes)
- {
- simp_array_ref (bsi, node_ptr);
- *node_ptr = build1 (INDIRECT_REF, TREE_TYPE (node), *node_ptr);
- /* The current node may require further simplification */
- simp_cil_node (bsi, node_ptr);
- }
- }
- break;
-
- case RETURN_EXPR:
- if (simp_final
- && !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. */
-
- tree res_type = TREE_TYPE (DECL_RESULT (current_function_decl));
- if (TYPE_SIZE (res_type) != NULL_TREE
- && TREE_CODE (TYPE_SIZE (res_type)) != INTEGER_CST)
- internal_error ("Returned type cannot be a variable size array or struct\n");
-
- 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 (simp_final
- && (TREE_CODE (bsi_stmt (*bsi)) != RETURN_EXPR
- || (TREE_CODE (TREE_OPERAND (bsi_stmt (*bsi), 0)) != MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (bsi_stmt (*bsi), 0)) != GIMPLE_MODIFY_STMT)))
- {
- tree res_type = TREE_TYPE (node);
- if (TYPE_SIZE (res_type) != NULL_TREE
- && TREE_CODE (TYPE_SIZE (res_type)) != INTEGER_CST)
- internal_error ("Returned type cannot be a variable size array or struct\n");
-
- 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:
- 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;
-
- case GOTO_EXPR:
- if (TREE_CODE (GOTO_DESTINATION (node)) != LABEL_DECL)
- simp_cil_node (bsi, &GOTO_DESTINATION (node));
- break;
-
- default:
- ;
- }
-}
-
-/* Invert the targets of the COND_EXPR pointed by NODE, when
- it is legal and there is a benefit in doing so.
- The only case in which this is currently done is when
- there is a comparison between integral or pointer types and
- the goto target is fallthough.
- BSI is an iterator of the statement that contains NODE. */
-
-static void
-simp_cond_stmt (block_stmt_iterator bsi, tree node)
-{
- basic_block bb = bb_for_stmt (bsi_stmt (bsi));
- tree cond_expr, then_expr;
- enum tree_code cond_code, rev_code;
- tree cond_type;
-
- gcc_assert (bsi_stmt (bsi) == node);
- gcc_assert (TREE_CODE (node) == COND_EXPR);
- cond_expr = COND_EXPR_COND (node);
- then_expr = COND_EXPR_THEN (node);
-
- /* Skip the optimization if then and else are not GOTO_EXPR */
- if (then_expr == NULL_TREE || !simple_goto_p (then_expr))
- {
- return;
- }
-
- gcc_assert (COND_EXPR_ELSE (node) && simple_goto_p (COND_EXPR_ELSE (node)));
-
- /* Nothing to do if the condition is not a comparison */
- if (! COMPARISON_CLASS_P (cond_expr))
- return;
-
- /* Do something only when the condition can be inverted */
- cond_code = TREE_CODE (cond_expr);
- cond_type = TREE_TYPE (TREE_OPERAND (cond_expr, 0));
- rev_code = invert_tree_comparison (cond_code, FLOAT_TYPE_P (cond_type));
- if (rev_code != ERROR_MARK
- && label_to_block (GOTO_DESTINATION (then_expr)) == bb->next_bb)
- {
- edge e;
-
- /* Invert the targets of the COND_EXPR */
- TREE_SET_CODE (COND_EXPR_COND (node), rev_code);
- COND_EXPR_THEN (node) = COND_EXPR_ELSE (node);
- COND_EXPR_ELSE (node) = then_expr;
-
- /* Invert the out-going edges */
- e = EDGE_SUCC (bb, 0);
- e->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
- e = EDGE_SUCC (bb, 1);
- e->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
- }
-}
-
-/* Force specific arguments of the CALL_EXPR to a built-in function
- pointed by NODE_PTR to be local variables.
- Which arguments are forced depend on the built-in function.
- BSI is the iterator of the statement that contains *NODE_PTR
- (in order to allow insertion of new statements). */
-
-static void
-simp_builtin_call (block_stmt_iterator bsi, tree *node_ptr)
-{
- tree node = *node_ptr;
- location_t locus = EXPR_LOCATION (bsi_stmt (bsi));
- tree fun_expr;
- tree dfun;
-
- gcc_assert (TREE_CODE (node) == CALL_EXPR);
-
- fun_expr = CALL_EXPR_FN (node);
- gcc_assert (TREE_CODE (fun_expr) == ADDR_EXPR);
-
- dfun = TREE_OPERAND (fun_expr, 0);
- gcc_assert (TREE_CODE (dfun) == FUNCTION_DECL);
- gcc_assert (DECL_BUILT_IN (dfun));
-
- if (DECL_BUILT_IN_CLASS (dfun) != BUILT_IN_MD)
- {
- switch (DECL_FUNCTION_CODE (dfun))
- {
- case BUILT_IN_VA_START:
- {
- tree va_ref = CALL_EXPR_ARG (node, 0);
- tree va;
-
- switch (TREE_CODE (va_ref)) {
- case INDIRECT_REF:
- case ADDR_EXPR:
- va = TREE_OPERAND (va_ref, 0);
- break;
-
- case VAR_DECL:
- va = build1 (INDIRECT_REF, cil32_va_list_type, va_ref);
- break;
-
- default:
- gcc_assert(0);
- break;
- }
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va)))
- == cil32_arg_iterator_type);
-
- {
- tree argiter = create_tmp_var (cil32_arg_iterator_type, "arg_iterator");
- location_t locus = EXPR_LOCATION (bsi_stmt (bsi));
- tree stmt = build_gimple_modify_stmt(va, build1 (ADDR_EXPR, cil32_va_list_type, argiter));
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
- }
-
- {
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, va, NULL);
-
- stmt = build_function_call_expr (cil32_builtins[CIL32_BUILT_IN_VA_START],
- new_args);
- bsi_replace (&bsi, stmt, true);
- }
-
- }
- break;
-
- case BUILT_IN_VA_END:
- {
- tree va_ref = CALL_EXPR_ARG (node, 0);
- tree va;
-
- switch (TREE_CODE (va_ref)) {
- case INDIRECT_REF:
- case ADDR_EXPR:
- va = TREE_OPERAND (va_ref, 0);
- break;
-
- case VAR_DECL:
- va = build1 (INDIRECT_REF, cil32_va_list_type, va_ref);
- break;
-
- default:
- gcc_assert(0);
- break;
- }
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va)))
- == cil32_arg_iterator_type);
-
- {
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, va, NULL);
-
- stmt = build_function_call_expr (cil32_builtins[CIL32_BUILT_IN_VA_END],
- new_args);
- bsi_replace (&bsi, stmt, true);
- }
- }
- break;
-
- case BUILT_IN_VA_COPY:
- {
- tree va_dest_ref = CALL_EXPR_ARG (node, 0);
- tree va_dest;
- tree va_src = CALL_EXPR_ARG (node, 1);
-
- switch (TREE_CODE (va_dest_ref)) {
- case INDIRECT_REF:
- case ADDR_EXPR:
- va_dest = TREE_OPERAND (va_dest_ref, 0);
- break;
-
- case VAR_DECL:
- va_dest = build1 (INDIRECT_REF, cil32_va_list_type, va_dest_ref);
- break;
-
- default:
- gcc_assert(0);
- break;
- }
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va_dest))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va_dest)))
- == cil32_arg_iterator_type);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (va_src))
- && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va_src)))
- == cil32_arg_iterator_type);
-
- {
- tree argiter = create_tmp_var (cil32_arg_iterator_type, "arg_iterator");
- location_t locus = EXPR_LOCATION (bsi_stmt (bsi));
- tree stmt = build_gimple_modify_stmt(va_dest, build1 (ADDR_EXPR, cil32_va_list_type, argiter));
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
- }
-
- {
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, va_src, NULL);
- new_args = tree_cons (NULL, va_dest, new_args);
-
- stmt = build_function_call_expr (cil32_builtins[CIL32_BUILT_IN_VA_COPY],
- new_args);
- bsi_replace (&bsi, stmt, true);
- }
- }
- break;
-
- case BUILT_IN_OBJECT_SIZE:
- {
- /* Inspired from 'expand_builtin_object_size' in builtins.c. We
- return -1 for types 0 and 1, and 0 for types 2 and 3. */
- tree arg2 = CALL_EXPR_ARG (node, 1);
- int obj_type;
-
- STRIP_NOPS (arg2);
- gcc_assert (TREE_CODE (arg2) == INTEGER_CST);
-
- obj_type = tree_low_cst (arg2, 0);
- switch (obj_type)
- {
- case 0:
- case 1:
- *node_ptr = integer_zero_node;
- break;
-
- case 2:
- case 3:
- *node_ptr = integer_minus_one_node;
- break;
-
- default:
- gcc_assert (0);
- }
- }
- break;
-
- case BUILT_IN_PREFETCH:
- {
- tree exp = CALL_EXPR_ARG (node, 0);
-
- gcc_assert (bsi_stmt (bsi) == node);
-
- /* For a target that does not support data prefetch,
- evaluate the memory address argument in case it has
- side effects. */
-
- if (! TREE_SIDE_EFFECTS (exp))
- exp = build1 (NOP_EXPR, void_type_node, integer_zero_node);
-
- SET_EXPR_LOCATION (exp, locus);
- *node_ptr = exp;
- }
- break;
-
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_RETURN_ADDRESS:
- {
- /* Supported (sort of) only for non-zero parameter, when it is ok
- to return NULL. */
- tree arg = CALL_EXPR_ARG (node, 0);
- int int_arg;
- gcc_assert (TREE_CODE (arg) == INTEGER_CST);
- int_arg = TREE_INT_CST_LOW (arg);
- if (int_arg == 0)
- {
- internal_error ("__builtin_{return,frame}_address not implemented\n");
- }
- else
- {
- *node_ptr = integer_zero_node;
- }
- }
- break;
-
- case BUILT_IN_BCMP:
- {
- tree src1 = CALL_EXPR_ARG (node, 0);
- tree src2 = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, fold_convert(sizetype, size), NULL);
- new_args = tree_cons (NULL, src2, new_args);
- new_args = tree_cons (NULL, src1, new_args);
-
- stmt = build_function_call_expr (built_in_decls[BUILT_IN_MEMCMP], new_args);
- bsi_replace (&bsi, stmt, true);
- }
- break;
-
- case BUILT_IN_BZERO:
- {
- tree src1 = CALL_EXPR_ARG (node, 0);
- tree size = CALL_EXPR_ARG (node, 1);
-
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, fold_convert(sizetype, size), NULL);
- new_args = tree_cons (NULL, integer_zero_node, new_args);
- new_args = tree_cons (NULL, src1, new_args);
-
- stmt = build_function_call_expr (built_in_decls[BUILT_IN_MEMSET], new_args);
- bsi_replace (&bsi, stmt, true);
- }
- break;
-
- case BUILT_IN_BCOPY:
- {
- tree src1 = CALL_EXPR_ARG (node, 0);
- tree dst1 = CALL_EXPR_ARG (node, 1);
- tree size = CALL_EXPR_ARG (node, 2);
-
- tree stmt;
- tree new_args;
-
- new_args = tree_cons (NULL, fold_convert(sizetype, size), NULL);
- new_args = tree_cons (NULL, src1, new_args);
- new_args = tree_cons (NULL, dst1, new_args);
-
- stmt = build_function_call_expr (built_in_decls[BUILT_IN_MEMMOVE], new_args);
- bsi_replace (&bsi, stmt, true);
- }
- break;
-
- default:
- ;
- }
- }
-}
-
-/* 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, edge_comp_neg, edge_comp_sel;
- 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 = build_gimple_modify_stmt(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;
- bb_sel->frequency = bb_comp->frequency;
- remove_edge (tmp_edge);
- bb_neg = create_empty_bb (bb_comp);
- bb_neg->count = count / 2;
- edge_comp_neg = unchecked_make_edge (bb_comp, bb_neg, EDGE_FALSE_VALUE);
- edge_comp_neg->probability = REG_BR_PROB_BASE / 2;
- edge_comp_sel = unchecked_make_edge (bb_comp, bb_sel, EDGE_TRUE_VALUE);
- edge_comp_sel->probability = REG_BR_PROB_BASE - edge_comp_neg->probability;
- make_single_succ_edge (bb_neg, bb_sel, EDGE_FALLTHRU);
- bb_neg->frequency = EDGE_FREQUENCY (edge_comp_neg);
-
- /* Insert labels and statements into neg bb */
- label_neg = build1 (LABEL_EXPR, void_type_node, label_decl_neg);
- asn_neg_stmt = build_gimple_modify_stmt(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, edge_comp_op0, edge_comp_op1;
- 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 = build_gimple_modify_stmt(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 = build_gimple_modify_stmt(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;
- bb_sel->frequency = bb_comp->frequency;
- 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;
- edge_comp_op0 = unchecked_make_edge (bb_comp, bb_op0, EDGE_TRUE_VALUE);
- edge_comp_op0->probability = REG_BR_PROB_BASE / 2;
- make_single_succ_edge (bb_op0, bb_sel, EDGE_FALLTHRU);
- edge_comp_op1 = unchecked_make_edge (bb_comp, bb_op1, EDGE_FALSE_VALUE);
- edge_comp_op1->probability = REG_BR_PROB_BASE - edge_comp_op0->probability;
- make_single_succ_edge (bb_op1, bb_sel, EDGE_FALLTHRU);
- bb_op0->frequency = EDGE_FREQUENCY (edge_comp_op0);
- bb_op1->frequency = EDGE_FREQUENCY (edge_comp_op1);
-
- /* 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 = build_gimple_modify_stmt(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 = build_gimple_modify_stmt(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 COND_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_cond_expr (block_stmt_iterator *bsi, tree *node_ptr)
-{
- tree node = *node_ptr;
- location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
- tree then_op, else_op;
- tree label_decl_then = create_artificial_label ();
- tree label_decl_else = create_artificial_label ();
- tree label_then, label_else;
- tree sel_var;
- tree orig_stmt, cmp_stmt, asn_then_stmt, asn_else_stmt;
- basic_block bb_comp, bb_then, bb_else, bb_sel;
- edge tmp_edge, edge_comp_then, edge_comp_else;
- block_stmt_iterator tmp_bsi;
- gcov_type count;
-
- gcc_assert (TREE_CODE (node) == COND_EXPR);
- gcc_assert (node != bsi_stmt (*bsi));
-
- /* Make sure that the two operands have no side effects */
- then_op = COND_EXPR_THEN (node);
- if (is_copy_required (then_op))
- {
- tree var = create_tmp_var (TREE_TYPE (then_op), "cilsimp");
- tree stmt = build_gimple_modify_stmt(var, then_op);
-
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
- COND_EXPR_THEN (node) = var;
- then_op = var;
- }
- else_op = COND_EXPR_ELSE (node);
- if (is_copy_required (else_op))
- {
- tree var = create_tmp_var (TREE_TYPE (else_op), "cilsimp");
- tree stmt = build_gimple_modify_stmt(var, else_op);
-
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
- COND_EXPR_ELSE (node) = var;
- else_op = var;
- }
-
- /* Insert the comparison statement */
- cmp_stmt = build3 (COND_EXPR, void_type_node,
- COND_EXPR_COND (node),
- build1 (GOTO_EXPR, void_type_node, label_decl_then),
- build1 (GOTO_EXPR, void_type_node, label_decl_else));
- 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;
- bb_sel->frequency = bb_comp->frequency;
- remove_edge (tmp_edge);
- bb_then = create_empty_bb (bb_comp);
- bb_else = create_empty_bb (bb_then);
- bb_then->count = count / 2;
- bb_else->count = count - bb_then->count;
- edge_comp_then = unchecked_make_edge (bb_comp, bb_then, EDGE_TRUE_VALUE);
- edge_comp_then->probability = REG_BR_PROB_BASE / 2;
- make_single_succ_edge (bb_then, bb_sel, EDGE_FALLTHRU);
- edge_comp_else = unchecked_make_edge (bb_comp, bb_else, EDGE_FALSE_VALUE);
- edge_comp_else->probability = REG_BR_PROB_BASE - edge_comp_then->probability;
- make_single_succ_edge (bb_else, bb_sel, EDGE_FALLTHRU);
- bb_then->frequency = EDGE_FREQUENCY (edge_comp_then);
- bb_else->frequency = EDGE_FREQUENCY (edge_comp_else);
-
- /* Insert labels and statements into then bb */
- sel_var = create_tmp_var (TREE_TYPE (node), "cilsimp");
- label_then = build1 (LABEL_EXPR, void_type_node, label_decl_then);
- asn_then_stmt = build_gimple_modify_stmt(sel_var, then_op);
- SET_EXPR_LOCATION (asn_then_stmt, locus);
- tmp_bsi = bsi_start (bb_then);
- bsi_insert_after (&tmp_bsi, label_then, BSI_NEW_STMT);
- bsi_insert_after (&tmp_bsi, asn_then_stmt, BSI_SAME_STMT);
-
- /* Insert labels and statements into else bb */
- label_else = build1 (LABEL_EXPR, void_type_node, label_decl_else);
- asn_else_stmt = build_gimple_modify_stmt(sel_var, else_op);
- SET_EXPR_LOCATION (asn_else_stmt, locus);
- tmp_bsi = bsi_start (bb_else);
- bsi_insert_after (&tmp_bsi, label_else, BSI_NEW_STMT);
- bsi_insert_after (&tmp_bsi, asn_else_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);
-}
-
-/* Simplify the unordered comparison expression pointed by NODE_PTR
- by expanding it with an equivalent expression based on UNORDERED_EXPR
- and TRUTH_OR_EXPR nodes.
- 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_unordered_comp_expr (block_stmt_iterator *bsi, tree *node_ptr)
-{
- tree node = *node_ptr;
- location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
- tree op0, op1;
- enum tree_code comp_code;
- tree t;
-
- gcc_assert (TREE_CODE (node) == UNEQ_EXPR
- || TREE_CODE (node) == UNLE_EXPR
- || TREE_CODE (node) == UNGE_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 = build_gimple_modify_stmt(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 = build_gimple_modify_stmt(var, op1);
-
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
- TREE_OPERAND (node, 1) = var;
- op1 = var;
- }
-
- switch (TREE_CODE (node))
- {
- case UNEQ_EXPR: comp_code = EQ_EXPR; break;
- case UNLE_EXPR: comp_code = LE_EXPR; break;
- case UNGE_EXPR: comp_code = GE_EXPR; break;
- default:
- gcc_unreachable ();
- }
-
- /* Build and gimplify the equivalent expression */
- t = build2 (TRUTH_OR_EXPR, TREE_TYPE (node),
- fold_build2 (comp_code, TREE_TYPE (node),
- op0,
- op1),
- fold_build2 (UNORDERED_EXPR, TREE_TYPE (node),
- op0,
- op1));
- t = force_gimple_operand_bsi (bsi, t, TRUE, NULL, TRUE, BSI_SAME_STMT);
-
- /* Update the current node */
- *node_ptr = t;
-}
-
-/* Simplify the LTGT_EXPR pointed by NODE_PTR by expanding it with
- the equivalent expression based on LT_EXPR, GT_EXPR and
- TRUTH_OR_EXPR nodes.
- 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_ltgt_expr (block_stmt_iterator *bsi, tree *node_ptr)
-{
- tree node = *node_ptr;
- location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
- tree op0, op1;
- tree t;
-
- gcc_assert (TREE_CODE (node) == LTGT_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 = build_gimple_modify_stmt(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 = build_gimple_modify_stmt(var, op1);
-
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
- TREE_OPERAND (node, 1) = var;
- op1 = var;
- }
-
- /* Build and gimplify the equivalent expression */
- t = build2 (TRUTH_OR_EXPR, TREE_TYPE (node),
- fold_build2 (LT_EXPR, TREE_TYPE (node),
- op0,
- op1),
- fold_build2 (GT_EXPR, TREE_TYPE (node),
- op0,
- op1));
- t = force_gimple_operand_bsi (bsi, t, TRUE, NULL, TRUE, BSI_SAME_STMT);
-
- /* Update the current node */
- *node_ptr = t;
-}
-
-/* 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.
- 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 (unsigned_intSI_type_node, 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 = build_gimple_modify_stmt(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 = build_gimple_modify_stmt(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,
- fold_build2 (MINUS_EXPR, unsigned_intSI_type_node,
- fold_convert (unsigned_intSI_type_node,
- TYPE_SIZE (TREE_TYPE (op0))),
- op1));
-
- /* Gimplify the two shifts */
- t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL, TRUE, BSI_SAME_STMT);
- t2 = force_gimple_operand_bsi (bsi, t2, TRUE, NULL, TRUE, BSI_SAME_STMT);
-
- /* 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, TRUE, BSI_SAME_STMT);
-
- /* 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
- (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 (unsigned_intSI_type_node, 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, TRUE, BSI_SAME_STMT);
-}
-
-/* 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, TRUE, BSI_SAME_STMT);
-}
-
-/* Given NODE of code ARRAY_REF:
- -) in BASE, return a tree of the ARRAY_REF that accesses
- the element of the array with all zero indexes;
- -) in DISP, return a tree with the computation of the
- displacement from the element with all zero indexes
- to that accessed by NODE. */
-
-static void
-compute_array_ref_base_disp (tree node, tree *base, tree *disp)
-{
- tree op0 = TREE_OPERAND (node, 0);
- tree op1 = TREE_OPERAND (node, 1);
- tree t1, t2;
- tree inner_base, inner_disp = NULL;
-
- gcc_assert (TREE_CODE (node) == ARRAY_REF);
-
- if (TREE_CODE (op0) == ARRAY_REF)
- compute_array_ref_base_disp (op0, &inner_base, &inner_disp);
- else
- inner_base = op0;
-
- *base = build4 (ARRAY_REF, TREE_TYPE (node),
- inner_base, integer_zero_node, NULL, NULL);
-
- t1 = fold_convert (long_integer_type_node, op1);
- t2 = fold_convert (long_integer_type_node, array_ref_element_size (node));
- /* Folding a multiplication having a comparison as first operand
- may result into a COND_EXPR node, which must not be reintroduced. */
- if (COMPARISON_CLASS_P (op1))
- *disp = build2 (MULT_EXPR, long_integer_type_node, t1, t2);
- else
- *disp = fold_build2 (MULT_EXPR, long_integer_type_node, t1, t2);
-
- if (inner_disp)
- *disp = fold_build2 (PLUS_EXPR, long_integer_type_node,
- inner_disp,
- *disp);
-}
-
-/* Simplify the ARRAY_REF pointed by NODE_PTR with the adress accesed
- by an equivalent ARRAY_REF with zero-indexes and the necessary
- sums and multiplications.
- 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 array_start, array_disp;
- tree ptr_type;
- tree t1, t2, stmt;
-
- gcc_assert (TREE_CODE (node) == ARRAY_REF);
-
- /* Compute the first element of the array being accessed and
- the displacement of the element being accessed from it. */
- compute_array_ref_base_disp (node, &array_start, &array_disp);
-
- /* Update addressable information */
- UPDATE_ADDRESSABLE (array_start);
-
- /* Build type pointer to the array element */
- ptr_type = build_pointer_type (TREE_TYPE (node));
-
- /* Build the expression for the adress of the first array element */
- t1 = build1 (ADDR_EXPR, ptr_type, array_start);
- recompute_tree_invariant_for_addr_expr (t1);
- t1 = force_gimple_operand_bsi (bsi, t1, FALSE, NULL, TRUE, BSI_SAME_STMT);
- t2 = create_tmp_var (ptr_type, "cilsimp");
- stmt = build_gimple_modify_stmt(t2, t1);
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (bsi, stmt, BSI_SAME_STMT);
-
- /* Build the expression for the access to the array element */
- t1 = fold_build2 (POINTER_PLUS_EXPR, ptr_type,
- t2,
- fold_convert (long_unsigned_type_node, array_disp));
- t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL, TRUE, BSI_SAME_STMT);
-
- /* Update the current node */
- *node_ptr = 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;
- tree stmt = bsi_stmt (*bsi);
- location_t locus = EXPR_LOCATION (stmt);
- tree obj = TREE_OPERAND (node, 0);
- tree fld = TREE_OPERAND (node, 1);
- tree fld_type, cont_type, cont_type_ptr, obj_ptr_type;
- tree fld_off, fld_size, cont_size, diff;
- tree lshift_cst, rshift_cst, ptr_off_cst;
- tree obj_addr, addr, cont_var;
- tree new_stmt, list = NULL_TREE;
- tree two = build_int_cst_type (size_type_node, 2);
- tree bits_per_unit = fold_convert (size_type_node, bitsize_unit_node);
-
- /* Extract bit field layout */
- fld_type = TREE_TYPE (fld);
- fld_off = size_binop (MULT_EXPR, DECL_FIELD_OFFSET (fld), bits_per_unit);
- fld_off = size_binop (PLUS_EXPR, fld_off,
- fold_convert (size_type_node,
- DECL_FIELD_BIT_OFFSET (fld)));
- fld_size = build_int_cst_type (size_type_node, TYPE_PRECISION (fld_type));
- cont_size = size_binop (TRUNC_DIV_EXPR, bits_per_unit, two);
-
- do {
- cont_size = size_binop (MULT_EXPR, cont_size, two);
- diff = size_binop (TRUNC_MOD_EXPR, fld_off, cont_size);
- diff = size_binop (PLUS_EXPR, diff, fld_size);
- } while (tree_int_cst_lt (cont_size, diff));
-
- /* lshift_cst = cont_size - ((fld_off % cont_size) + fld_size) */
- lshift_cst = size_binop (TRUNC_MOD_EXPR, fld_off, cont_size);
- lshift_cst = size_binop (PLUS_EXPR, lshift_cst, fld_size);
- lshift_cst = size_binop (MINUS_EXPR, cont_size, lshift_cst);
-
- /* rshift_cst = cont_size - fld_size */
- rshift_cst = size_binop (MINUS_EXPR, cont_size, fld_size);
-
- /* Build the new type for the equivalent access (and a pointer type to it) */
- cont_type = get_integer_type (tree_low_cst (cont_size, true), true);
- cont_type_ptr = build_pointer_type (cont_type);
-
- /* Build the type corresponding of a pointer to the object */
- obj_ptr_type = build_pointer_type (TREE_TYPE (obj));
-
- /* Build expression to compute the address to be accessed */
- obj_addr = create_tmp_var (obj_ptr_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt (obj_addr,
- build_fold_addr_expr (obj));
- gcc_assert (TREE_CODE (obj) != CALL_EXPR);
- append_to_statement_list (new_stmt, &list);
-
- addr = create_tmp_var (cont_type_ptr, "cilsimp");
- new_stmt = build_gimple_modify_stmt (addr,
- fold_convert (cont_type_ptr, obj_addr));
- append_to_statement_list (new_stmt, &list);
-
- /* ptr_off_cst = ((fld_off / cont_size) * cont_size) / 8 */
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, fld_off, cont_size);
- ptr_off_cst = size_binop (MULT_EXPR, ptr_off_cst, cont_size);
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, ptr_off_cst, bits_per_unit);
-
- if (!tree_int_cst_equal (ptr_off_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (addr,
- build2 (POINTER_PLUS_EXPR,
- cont_type_ptr, addr,
- ptr_off_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Read the value at the address just computed */
- cont_var = create_tmp_var (cont_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt(cont_var,
- build_fold_indirect_ref (addr));
- append_to_statement_list (new_stmt, &list);
-
- /* Shift the bit-field into position, clearing the upper bits */
- if (! tree_int_cst_equal (lshift_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (LSHIFT_EXPR, cont_type,
- cont_var, lshift_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- if (! tree_int_cst_equal (rshift_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (RSHIFT_EXPR, cont_type,
- cont_var, rshift_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Update the current statement (and the current node) */
- set_statement_list_location (list, locus);
- bsi_insert_before (bsi, list, BSI_SAME_STMT);
- *node_ptr = fold_convert (TREE_TYPE (node), cont_var);
-}
-
-/* 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;
- tree stmt = bsi_stmt (*bsi);
- location_t locus = EXPR_LOCATION (stmt);
- tree obj = TREE_OPERAND (node, 0);
- tree fld = TREE_OPERAND (node, 1);
- tree fld_type, cont_type, cont_type_ptr, obj_ptr_type;
- tree fld_off, fld_size, cont_size, diff;
- tree shift_cst, mask_cst, ptr_off_cst;
- tree obj_addr, addr, rhs, folded_rhs, cont_var;
- tree new_stmt, list = NULL_TREE;
- tree two = build_int_cst_type (size_type_node, 2);
- tree bits_per_unit = fold_convert (size_type_node, bitsize_unit_node);
-
- gcc_assert (TREE_CODE (node) == COMPONENT_REF);
- gcc_assert ((TREE_CODE (stmt) == MODIFY_EXPR
- || TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
- && GENERIC_TREE_OPERAND (stmt, 0) == node);
-
- /* Extract bit field layout */
- fld_type = TREE_TYPE (fld);
- fld_off = size_binop (MULT_EXPR, DECL_FIELD_OFFSET (fld), bits_per_unit);
- fld_off = size_binop (PLUS_EXPR, fld_off,
- fold_convert (size_type_node,
- DECL_FIELD_BIT_OFFSET (fld)));
- fld_size = build_int_cst_type (size_type_node, TYPE_PRECISION (fld_type));
- cont_size = size_binop (TRUNC_DIV_EXPR, bits_per_unit, two);
-
- do {
- cont_size = size_binop (MULT_EXPR, cont_size, two);
- diff = size_binop (TRUNC_MOD_EXPR, fld_off, cont_size);
- diff = size_binop (PLUS_EXPR, diff, fld_size);
- } while (tree_int_cst_lt (cont_size, diff));
-
- shift_cst = size_binop (TRUNC_MOD_EXPR, fld_off, cont_size);
-
- /* Build the new type for the equivalent access (and a pointer type to it) */
- cont_type = get_integer_type (tree_low_cst (cont_size, true), true);
- cont_type_ptr = build_pointer_type (cont_type);
-
- /* Build the type corresponding of a pointer to the object */
- obj_ptr_type = build_pointer_type (TREE_TYPE (obj));
-
- /* Create the mask */
- mask_cst = build_int_cst_type (cont_type, 1);
- mask_cst = size_binop (LSHIFT_EXPR, mask_cst, fld_size);
- mask_cst = size_binop (MINUS_EXPR, mask_cst,
- build_int_cst_type (cont_type, 1));
- mask_cst = size_binop (LSHIFT_EXPR, mask_cst, shift_cst);
-
- /* If the rhs is a constant fold the shift & mask operations, if it is not
- copy it and convert it in the container type */
- rhs = fold_convert (cont_type, GENERIC_TREE_OPERAND (stmt, 1));
- folded_rhs = fold_binary_to_constant (LSHIFT_EXPR, cont_type, rhs, shift_cst);
-
- if (folded_rhs != NULL_TREE)
- {
- folded_rhs = fold_binary_to_constant (BIT_AND_EXPR, cont_type, folded_rhs,
- mask_cst);
- }
-
- if (folded_rhs != NULL_TREE)
- rhs = folded_rhs;
- else
- {
- rhs = create_tmp_var (cont_type, "cilsimp");
- new_stmt = fold_convert (cont_type, GENERIC_TREE_OPERAND (stmt, 1));
- new_stmt = build_gimple_modify_stmt (rhs, new_stmt);
- append_to_statement_list (new_stmt, &list);
-
- new_stmt = build_gimple_modify_stmt (rhs,
- build2 (LSHIFT_EXPR, cont_type,
- rhs, shift_cst));
- append_to_statement_list (new_stmt, &list);
-
- new_stmt = build_gimple_modify_stmt (rhs,
- build2 (BIT_AND_EXPR, cont_type,
- rhs, mask_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Build expression to compute the address to be accessed */
- obj_addr = create_tmp_var (obj_ptr_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt (obj_addr,
- build_fold_addr_expr (obj));
- gcc_assert (TREE_CODE (obj) != CALL_EXPR);
- append_to_statement_list (new_stmt, &list);
-
- addr = create_tmp_var (cont_type_ptr, "cilsimp");
- new_stmt = build_gimple_modify_stmt (addr,
- fold_convert (cont_type_ptr, obj_addr));
- append_to_statement_list (new_stmt, &list);
-
- /* ptr_off_cst = ((fld_off / cont_size) * cont_size) / 8 */
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, fld_off, cont_size);
- ptr_off_cst = size_binop (MULT_EXPR, ptr_off_cst, cont_size);
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, ptr_off_cst, bits_per_unit);
-
- if (tree_int_cst_compare (ptr_off_cst, size_zero_node) != 0)
- {
- new_stmt = build_gimple_modify_stmt (addr,
- build2 (POINTER_PLUS_EXPR,
- cont_type_ptr, addr,
- ptr_off_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Read existing value at the address just computed */
- cont_var = create_tmp_var (cont_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt(cont_var,
- build_fold_indirect_ref (addr));
- append_to_statement_list (new_stmt, &list);
-
- /* Compute the mask to be applied to the existing value */
- mask_cst = size_binop (BIT_XOR_EXPR, mask_cst,
- build_int_cst_type (cont_type, -1));
- mask_cst = fold_convert (cont_type, mask_cst);
-
- /* Apply the mask to the existing value */
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (BIT_AND_EXPR, cont_type,
- cont_var, mask_cst));
- append_to_statement_list (new_stmt, &list);
-
- /* Compute the new value for the rhs of the current statement */
- if (!((TREE_CODE (rhs) == INTEGER_CST)
- && tree_int_cst_equal (rhs, size_zero_node)))
- {
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (BIT_IOR_EXPR, cont_type,
- cont_var, rhs));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Update the current statement (and the current node) */
- set_statement_list_location (list, locus);
- bsi_insert_before (bsi, list, BSI_SAME_STMT);
- *node_ptr = build_fold_indirect_ref (addr);
- GENERIC_TREE_OPERAND (stmt, 1) = cont_var;
-}
-
-/* Expand the BIT_FIELD_REF (pointed by NODE_PTR) 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_bitfield_ref (block_stmt_iterator *bsi, tree *node_ptr)
-{
- tree node = *node_ptr;
- tree stmt = bsi_stmt (*bsi);
- location_t locus = EXPR_LOCATION (stmt);
- tree obj = TREE_OPERAND (node, 0);
- tree type, cont_type, cont_type_ptr, obj_ptr_type;
- tree obj_addr, addr, cont_var;
- tree off, size, cont_size, diff;
- tree lshift_cst, rshift_cst, ptr_off_cst;
- tree new_stmt, list = NULL_TREE;
-
- /* Extract bit field layout */
- size = fold_convert (size_type_node, TREE_OPERAND (node, 1));
- off = fold_convert (size_type_node, TREE_OPERAND (node, 2));
- type = TREE_TYPE (node);
- cont_size = size_binop (TRUNC_DIV_EXPR, bits_per_unit, two);
-
- do {
- cont_size = size_binop (MULT_EXPR, cont_size, two);
- diff = size_binop (TRUNC_MOD_EXPR, off, cont_size);
- diff = size_binop (PLUS_EXPR, diff, size);
- } while (tree_int_cst_lt (cont_size, diff));
-
- /* lshift_cst = cont_size + ((fld_off % cont_size) + fld_size) */
- lshift_cst = size_binop (TRUNC_MOD_EXPR, off, cont_size);
- lshift_cst = size_binop (PLUS_EXPR, lshift_cst, size);
- lshift_cst = size_binop (MINUS_EXPR, cont_size, lshift_cst);
-
- /* rshift_cst = cont_size - fld_size */
- rshift_cst = size_binop (MINUS_EXPR, cont_size, size);
-
- /* Build the new type for the equivalent access (and a pointer type to it) */
- cont_type = get_integer_type (tree_low_cst (cont_size, true), true);
- cont_type_ptr = build_pointer_type (cont_type);
-
- /* Build the type corresponding of a pointer to the object */
- obj_ptr_type = build_pointer_type (TREE_TYPE (obj));
-
- /* Build expression to compute the address to be accessed */
- obj_addr = create_tmp_var (obj_ptr_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt (obj_addr,
- build_fold_addr_expr (obj));
- gcc_assert (TREE_CODE (obj) != CALL_EXPR);
- append_to_statement_list (new_stmt, &list);
-
- addr = create_tmp_var (cont_type_ptr, "cilsimp");
- new_stmt = build_gimple_modify_stmt (addr,
- fold_convert (cont_type_ptr, obj_addr));
- append_to_statement_list (new_stmt, &list);
-
- /* ptr_off_cst = ((fld_off / cont_size) * cont_size) / 8 */
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, off, cont_size);
- ptr_off_cst = size_binop (MULT_EXPR, ptr_off_cst, cont_size);
- ptr_off_cst = size_binop (TRUNC_DIV_EXPR, ptr_off_cst, bits_per_unit);
-
- if (!tree_int_cst_equal (ptr_off_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (addr,
- build2 (POINTER_PLUS_EXPR,
- cont_type_ptr, addr,
- ptr_off_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Read the value at the address just computed */
- cont_var = create_tmp_var (cont_type, "cilsimp");
- new_stmt = build_gimple_modify_stmt(cont_var,
- build_fold_indirect_ref (addr));
- append_to_statement_list (new_stmt, &list);
-
- /* Shift the bit-field into position, clearing the upper bits */
- if (! tree_int_cst_equal (lshift_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (LSHIFT_EXPR, cont_type,
- cont_var, lshift_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- if (! tree_int_cst_equal (rshift_cst, size_zero_node))
- {
- new_stmt = build_gimple_modify_stmt (cont_var,
- build2 (RSHIFT_EXPR, cont_type,
- cont_var, rshift_cst));
- append_to_statement_list (new_stmt, &list);
- }
-
- /* Update the current statement (and the current node) */
- set_statement_list_location (list, locus);
- bsi_insert_before (bsi, list, BSI_SAME_STMT);
- *node_ptr = fold_convert (TREE_TYPE (node), cont_var);
-}
-
-/* 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, tree lhs, tree rhs)
-{
- location_t locus = EXPR_LOCATION (bsi_stmt (*bsi));
- 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
- || TREE_CODE (node) == GIMPLE_MODIFY_STMT);
- 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);
- 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, true);
-
- /* Update the basic block statement iterator */
- *bsi = tmp_bsi;
-}
-
-/* Make sure that the tree pointed by NODE_PTR is a VAR_DECL;
- if LOCAL is true, then the VAR_DECL must be a local variable.
- 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, bool local)
-{
- 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
- && (!local || !DECL_FILE_SCOPE_P (node)))
- return;
-
- /* Split the current statement by creating a new local variable */
- var = create_tmp_var (type, "cilsimp");
- stmt = build_gimple_modify_stmt(var, node);
- SET_EXPR_LOCATION (stmt, locus);
- bsi_insert_before (&bsi, stmt, BSI_SAME_STMT);
- *node_ptr = var;
-}
-
-/* Rename a single variable using the specified suffix */
-
-static void
-rename_var (tree var, const char* suffix, unsigned long index)
-{
- 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,
- index));
-}
-
-/* Simplify variables: rename inlined variables
- rename and globalize function static variables
- inline init for local variables. */
-
-static void
-simp_vars (void)
-{
- basic_block new_bb = 0;
- block_stmt_iterator bsi;
- tree *p = &cfun->unexpanded_var_list;
- unsigned long num_loc = 0;
-
- for (; *p; p = &TREE_CHAIN (*p))
- {
- tree var = TREE_VALUE (*p);
- tree init = DECL_INITIAL (var);
-
- if (TREE_STATIC (var) && DECL_CONTEXT (var) != 0)
- {
- rename_var (var, "?fs", DECL_UID (var));
- DECL_CONTEXT (var) = 0;
- }
-
- if (DECL_NAME (var) != NULL && ! TREE_STATIC (var))
- {
- if (DECL_FROM_INLINE (var))
- rename_var (var, "?in", num_loc);
- else
- rename_var (var, "?", num_loc);
-
- ++num_loc;
- }
-
- if (!TREE_STATIC (var) && init && init != error_mark_node)
- {
- /* Generate empty basic block after the entry bb, if not done yet */
- if (!new_bb)
- {
- basic_block entry_succ = single_succ (ENTRY_BLOCK_PTR);
- edge e = find_edge (ENTRY_BLOCK_PTR, entry_succ);
- edge new_e;
-
- new_bb = create_empty_bb (ENTRY_BLOCK_PTR);
- new_bb->count = ENTRY_BLOCK_PTR->count;
- new_bb->frequency = ENTRY_BLOCK_PTR->frequency;
- redirect_edge_pred (e, new_bb);
- new_e = make_single_succ_edge (ENTRY_BLOCK_PTR, new_bb, e->flags);
- new_e->count = e->count;
- new_e->probability = e->probability;
- bsi = bsi_start (new_bb);
- }
-
- DECL_INITIAL (var) = NULL_TREE;
- bsi_insert_before (&bsi,
- build_gimple_modify_stmt(var, init),
- BSI_SAME_STMT);
- }
- }
-}
-
-/* Simplify pass that makes CIL emission easier. */
-
-static unsigned int
-simp_cil_final (void)
-{
- basic_block bb;
- block_stmt_iterator bsi;
-
- two = build_int_cst_type (size_type_node, 2);
- bits_per_unit = fold_convert (size_type_node, bitsize_unit_node);
- simp_final = true;
- push_gimplify_context ();
- res_var = NULL_TREE;
-
- 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_CODE (stmt) == GIMPLE_MODIFY_STMT)
- {
- tree lhs = GENERIC_TREE_OPERAND (stmt, 0);
- tree rhs = GENERIC_TREE_OPERAND (stmt, 1);
-
- if (TREE_CODE (rhs) == CONSTRUCTOR
- || TREE_CODE (rhs) == STRING_CST)
- pre_simp_init (&bsi, stmt, lhs, rhs);
- else if (TREE_CODE (lhs) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND (lhs, 1))
- && (TREE_CODE (GENERIC_TREE_OPERAND (stmt, 1))
- != INTEGER_CST))
- {
- split_use (bsi, &GENERIC_TREE_OPERAND (stmt, 1), false);
- }
- }
- }
- }
-
- /* 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 (EDGE_COUNT (bb->succs) == 0)
- {
- tree stmt;
- bsi = bsi_last (bb);
- stmt = bsi_stmt (bsi);
-
- if (simp_final && TREE_CODE (stmt) != RETURN_EXPR)
- {
- tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl));
- tree ret_stmt;
-
- if (TREE_CODE (ret_type) != VOID_TYPE && res_var == NULL_TREE)
- res_var = create_tmp_var (ret_type, "cilsimp");
-
- ret_stmt = build1 (RETURN_EXPR, ret_type, res_var);
- bsi_insert_after (&bsi, ret_stmt, BSI_NEW_STMT);
- make_single_succ_edge (bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
- }
- }
- }
-
- pop_gimplify_context (NULL);
- two = NULL_TREE;
- bits_per_unit = NULL_TREE;
-
- 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-final-simp-CIL pass. */
-
-struct tree_opt_pass pass_simp_cil_final =
-{
- "finsimpcil", /* name */
- simp_cil_gate, /* gate */
- simp_cil_final, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_SIMP_CIL, /* tv_id */
- PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- /* ??? If TER is enabled, we also kill gimple. */
- 0, /* properties_destroyed */
- 0,
- TODO_ggc_collect | TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
-};
-
-/*
- * Local variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/gcc/passes.c b/gcc/passes.c
index 5fd0fdeb232..02fbdbd9ce8 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -690,9 +690,16 @@ init_optimization_passes (void)
NEXT_PASS (pass_free_datastructures);
#if defined(DISABLE_RTL_PASSES)
NEXT_PASS (pass_bb_layout);
- NEXT_PASS (pass_simp_cil_final);
- NEXT_PASS (pass_gen_cil); /* <--- CIL */
- NEXT_PASS (pass_cil_vcg);
+ NEXT_PASS (pass_gimple_to_cil);
+ NEXT_PASS (pass_missing_protos);
+ NEXT_PASS (pass_cil_peephole);
+ NEXT_PASS (pass_remove_convs);
+ NEXT_PASS (pass_remove_temps);
+ NEXT_PASS (pass_remove_convs);
+ NEXT_PASS (pass_remove_temps);
+ NEXT_PASS (pass_simp_cond);
+ NEXT_PASS (pass_emit_cil_vcg);
+ NEXT_PASS (pass_emit_cil);
#else /* !defined(DISABLE_RTL_PASSES) */
NEXT_PASS (pass_mudflap_2);
NEXT_PASS (pass_free_cfg_annotations);
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 55f1c2ea700..4044ed61209 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -188,6 +188,14 @@ DEFTIMEVAR (TV_SYMOUT , "symout")
DEFTIMEVAR (TV_VAR_TRACKING , "variable tracking")
DEFTIMEVAR (TV_TREE_IFCOMBINE , "tree if-combine")
DEFTIMEVAR (TV_SIMP_CIL , "CIL simplification")
+DEFTIMEVAR (TV_GIMPLE_TO_CIL , "GIMPLE/generic to CIL conversion")
+DEFTIMEVAR (TV_MISSING_PROTOS , "missing prototype functions patch")
+DEFTIMEVAR (TV_CIL_PEEPHOLE , "CIL specific peephole optimizations")
+DEFTIMEVAR (TV_REMOVE_CONVS , "remove unnecessary conversions")
+DEFTIMEVAR (TV_REMOVE_TEMPS , "remove unnecessary temporaries")
+DEFTIMEVAR (TV_SIMP_COND , "simplify conditional branches")
+DEFTIMEVAR (TV_EMIT_CIL_VCG , "emit the VCG for CIL code")
+DEFTIMEVAR (TV_EMIT_CIL , "CIL assembly emission")
/* Everything else in rest_of_compilation not included above. */
DEFTIMEVAR (TV_REST_OF_COMPILATION , "rest of compilation")
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 6becc8703d9..e7a2a97b788 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2122,7 +2122,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
globalize_decl (decl);
#if defined(TARGET_DECLARE_VARIABLE)
- TARGET_DECLARE_VARIABLE(asm_out_file,decl);
+ TARGET_DECLARE_VARIABLE(asm_out_file, decl);
#else /* !defined(TARGET_DECLARE_VARIABLE) */
/* Output any data that we will need to use the address of. */
diff --git a/libgcc4net/gcc4net.cs b/libgcc4net/gcc4net.cs
index c37fa99bbab..c2faf7eeb0c 100644
--- a/libgcc4net/gcc4net.cs
+++ b/libgcc4net/gcc4net.cs
@@ -1,6 +1,6 @@
/* Run-time support required by CIL binaries.
- Copyright (C) 2006-2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2008 Free Software Foundation, Inc.
Contributed by STMicroelectronics
This program is free software; you can redistribute it and/or
@@ -20,9 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Authors:
Andrea Bona
+ Roberto Costa
Andrea Ornstein
Erven Rohou
- Roberto Costa
+ Gabriele Svelto
Contact information at STMicroelectronics:
Andrea C. Ornstein <andrea.ornstein@st.com>
@@ -128,6 +129,11 @@ namespace gcc4net {
public static float __abssf2(float a) { return (a>=0) ? a : -a; }
public static double __absdf2(double a) { return (a>=0) ? a : -a; }
+ public static int __selectsi4(int a, int b, int c) { return (a != 0) ? b : c; }
+ public static long __selectdi4(int a, long b, long c) { return (a != 0) ? b : c; }
+ public static float __selectsf4(int a, float b, float c) { return (a != 0) ? b : c; }
+ public static double __selectdf4(int a, double b, double c) { return (a != 0) ? b : c; }
+
// Returns the number of leading 0-bits in a, starting at the most
// significant bit position. If a is 0, the result is undefined.
public static int __clzsi2(uint a)
@@ -381,7 +387,7 @@ namespace gcc4net {
// signed integers
public struct complex_char {
- private sbyte re, im;
+ public sbyte re, im;
public static complex_char complex_char_ctor(sbyte the_re, sbyte the_im)
{
@@ -390,16 +396,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static sbyte complex_char_Re(complex_char c) { return c.re; }
- public static sbyte complex_char_Im(complex_char c) { return c.im; }
- public void complex_char_set_Re(sbyte val) { re = val; }
- public void complex_char_set_Im(sbyte val) { im = val; }
}
public struct complex_short {
- private short re, im;
+ public short re, im;
public static complex_short complex_short_ctor(short the_re, short the_im)
{
@@ -408,16 +409,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static short complex_short_Re(complex_short c) { return c.re; }
- public static short complex_short_Im(complex_short c) { return c.im; }
- public void complex_short_set_Re(short val) { re = val; }
- public void complex_short_set_Im(short val) { im = val; }
}
public struct complex_int {
- private int re, im;
+ public int re, im;
public static complex_int complex_int_ctor(int the_re, int the_im)
{
@@ -426,16 +422,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static int complex_int_Re(complex_int c) { return c.re; }
- public static int complex_int_Im(complex_int c) { return c.im; }
- public void complex_int_set_Re(int val) { re = val; }
- public void complex_int_set_Im(int val) { im = val; }
}
public struct complex_long {
- private long re, im;
+ public long re, im;
public static complex_long complex_long_ctor(long the_re, long the_im)
{
@@ -444,18 +435,13 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static long complex_long_Re(complex_long c) { return c.re; }
- public static long complex_long_Im(complex_long c) { return c.im; }
- public void complex_long_set_Re(long val) { re = val; }
- public void complex_long_set_Im(long val) { im = val; }
}
// unsigned signed integers
public struct complex_uchar {
- private byte re, im;
+ public byte re, im;
public static complex_uchar complex_uchar_ctor(byte the_re, byte the_im)
{
@@ -464,16 +450,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static byte complex_uchar_Re(complex_uchar c) { return c.re; }
- public static byte complex_uchar_Im(complex_uchar c) { return c.im; }
- public void complex_uchar_set_Re(byte val) { re = val; }
- public void complex_uchar_set_Im(byte val) { im = val; }
}
public struct complex_ushort {
- private ushort re, im;
+ public ushort re, im;
public static complex_ushort complex_ushort_ctor(ushort the_re, ushort the_im)
{
@@ -482,16 +463,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static ushort complex_ushort_Re(complex_ushort c) { return c.re; }
- public static ushort complex_ushort_Im(complex_ushort c) { return c.im; }
- public void complex_ushort_set_Re(ushort val) { re = val; }
- public void complex_ushort_set_Im(ushort val) { im = val; }
}
public struct complex_uint {
- private uint re, im;
+ public uint re, im;
public static complex_uint complex_uint_ctor(uint the_re, uint the_im)
{
@@ -500,16 +476,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static uint complex_uint_Re(complex_uint c) { return c.re; }
- public static uint complex_uint_Im(complex_uint c) { return c.im; }
- public void complex_uint_set_Re(uint val) { re = val; }
- public void complex_uint_set_Im(uint val) { im = val; }
}
public struct complex_ulong {
- private ulong re, im;
+ public ulong re, im;
public static complex_ulong complex_ulong_ctor(ulong the_re, ulong the_im)
{
@@ -518,18 +489,13 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static ulong complex_ulong_Re(complex_ulong c) { return c.re; }
- public static ulong complex_ulong_Im(complex_ulong c) { return c.im; }
- public void complex_ulong_set_Re(ulong val) { re = val; }
- public void complex_ulong_set_Im(ulong val) { im = val; }
}
// floating point
public struct complex_float {
- private float re, im;
+ public float re, im;
public static complex_float complex_float_ctor(float the_re,
float the_im)
@@ -539,16 +505,11 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static float complex_float_Re(complex_float c) { return c.re; }
- public static float complex_float_Im(complex_float c) { return c.im; }
- public void complex_float_set_Re(float val) { re = val; }
- public void complex_float_set_Im(float val) { im = val; }
}
public struct complex_double {
- private double re, im;
+ public double re, im;
public static complex_double complex_double_ctor(double the_re,
double the_im)
@@ -558,11 +519,6 @@ namespace gcc4net {
result.im = the_im;
return result;
}
-
- public static double complex_double_Re(complex_double c) { return c.re; }
- public static double complex_double_Im(complex_double c) { return c.im; }
- public void complex_double_set_Re(double val) { re = val; }
- public void complex_double_set_Im(double val) { im = val; }
}
@@ -629,6 +585,7 @@ namespace gcc4net {
{
return (uint) ((v.f0 << 16) | v.f1);
}
+
public static int V2HI_to_si(V2HI v)
{
return (int)((v.f0 << 16) | v.f1);
@@ -764,6 +721,12 @@ namespace gcc4net {
result.f3 = b3;
return result;
}
+
+ public unsafe static V4SF V4SI_to_V4SF(V4SI v)
+ {
+ return V4SF.V4SF_ctor1(*(float*)&v.f0, *(float*)&v.f1,
+ *(float*)&v.f2, *(float*)&v.f3);
+ }
}
public struct V8HI {
diff --git a/libstd/Makefile.in b/libstd/Makefile.in
index d4e58432688..64755c8c66a 100644
--- a/libstd/Makefile.in
+++ b/libstd/Makefile.in
@@ -107,7 +107,6 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
-GCC4NET = @GCC4NET@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/libstd/configure b/libstd/configure
index 2a6c09a677e..241e72c5ee3 100755
--- a/libstd/configure
+++ b/libstd/configure
@@ -883,7 +883,6 @@ FFLAGS
ac_ct_F77
LIBTOOL
MCS
-GCC4NET
LIBOBJS
LTLIBOBJS'
ac_subst_files=''
@@ -1501,8 +1500,6 @@ Optional Packages:
--with-tags[=TAGS] include additional configurations [automatic]
--with-mcs=mcs_binary_path
use this mcs
- --with-gcc4NET=gcc4NET_binary_path
- use this cil32-gcc
Some influential environment variables:
CC C compiler command
@@ -4661,7 +4658,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 4664 "configure"' > conftest.$ac_ext
+ echo '#line 4661 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -7393,11 +7390,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7396: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7393: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7400: \$? = $ac_status" >&5
+ echo "$as_me:7397: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7661,11 +7658,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7664: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7661: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7668: \$? = $ac_status" >&5
+ echo "$as_me:7665: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7765,11 +7762,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7768: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7765: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7772: \$? = $ac_status" >&5
+ echo "$as_me:7769: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -10062,7 +10059,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10065 "configure"
+#line 10062 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10162,7 +10159,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10165 "configure"
+#line 10162 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12498,11 +12495,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:12501: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12498: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:12505: \$? = $ac_status" >&5
+ echo "$as_me:12502: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -12602,11 +12599,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:12605: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12602: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:12609: \$? = $ac_status" >&5
+ echo "$as_me:12606: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -14163,11 +14160,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14166: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14163: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14170: \$? = $ac_status" >&5
+ echo "$as_me:14167: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -14267,11 +14264,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14270: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14267: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:14274: \$? = $ac_status" >&5
+ echo "$as_me:14271: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -16454,11 +16451,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16457: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16454: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:16461: \$? = $ac_status" >&5
+ echo "$as_me:16458: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -16722,11 +16719,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16725: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16722: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:16729: \$? = $ac_status" >&5
+ echo "$as_me:16726: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -16826,11 +16823,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16829: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:16826: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:16833: \$? = $ac_status" >&5
+ echo "$as_me:16830: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -19523,51 +19520,6 @@ fi
-
-# Check whether --with-gcc4NET was given.
-if test "${with_gcc4NET+set}" = set; then
- withval=$with_gcc4NET; GCC4NET=$withval
-fi
-
-# Extract the first word of "cil32-gcc", so it can be a program name with args.
-set dummy cil32-gcc; ac_word=$2
-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
-if test "${ac_cv_prog_GCC4NET+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$GCC4NET"; then
- ac_cv_prog_GCC4NET="$GCC4NET" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
- ac_cv_prog_GCC4NET="cil32-gcc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_prog_GCC4NET" && ac_cv_prog_GCC4NET="cil32-gcc-not-found"
-fi
-fi
-GCC4NET=$ac_cv_prog_GCC4NET
-if test -n "$GCC4NET"; then
- { echo "$as_me:$LINENO: result: $GCC4NET" >&5
-echo "${ECHO_T}$GCC4NET" >&6; }
-else
- { echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-
-
ac_config_files="$ac_config_files Makefile include/Makefile src/Makefile src_opt/Makefile"
@@ -20398,12 +20350,11 @@ FFLAGS!$FFLAGS$ac_delim
ac_ct_F77!$ac_ct_F77$ac_delim
LIBTOOL!$LIBTOOL$ac_delim
MCS!$MCS$ac_delim
-GCC4NET!$GCC4NET$ac_delim
LIBOBJS!$LIBOBJS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 20; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 19; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/libstd/configure.ac b/libstd/configure.ac
index aea7e074bc7..fa60c7b36b6 100644
--- a/libstd/configure.ac
+++ b/libstd/configure.ac
@@ -75,11 +75,6 @@ AC_ARG_WITH(mcs,
MCS=$withval)
AC_CHECK_PROG(MCS,mcs,mcs,mcs-not-found)
-AC_ARG_WITH(gcc4NET,
- AS_HELP_STRING([--with-gcc4NET=gcc4NET_binary_path], [use this cil32-gcc]),
- GCC4NET=$withval)
-AC_CHECK_PROG(GCC4NET,cil32-gcc,cil32-gcc,cil32-gcc-not-found)
-
AC_CONFIG_FILES([Makefile include/Makefile src/Makefile src_opt/Makefile])
AC_OUTPUT
diff --git a/libstd/include/Makefile.am b/libstd/include/Makefile.am
index ec94add528d..53251298296 100644
--- a/libstd/include/Makefile.am
+++ b/libstd/include/Makefile.am
@@ -49,7 +49,6 @@ includesys_HEADERS = \
sys/stat.h
noinst_HEADERS = \
- __OPT_MSCorlibWrapper.h \
__cdefs_build.h \
__ctype.h \
__host.h \
diff --git a/libstd/include/Makefile.in b/libstd/include/Makefile.in
index 3628ee86a87..8cdd5ef856f 100644
--- a/libstd/include/Makefile.in
+++ b/libstd/include/Makefile.in
@@ -97,7 +97,6 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
-GCC4NET = @GCC4NET@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -231,7 +230,6 @@ includesys_HEADERS = \
sys/stat.h
noinst_HEADERS = \
- __OPT_MSCorlibWrapper.h \
__cdefs_build.h \
__ctype.h \
__host.h \
diff --git a/libstd/include/__OPT_MSCorlibWrapper.h b/libstd/include/__OPT_MSCorlibWrapper.h
deleted file mode 100644
index 5d8cfc50f74..00000000000
--- a/libstd/include/__OPT_MSCorlibWrapper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-
- Copyright (C) 2007-2008 Free Software Foundation, Inc.
- Contributed by STMicroelectronics
-
-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. */
-
-#define __BEGIN_EXTERN_C
-#define __END_EXTERN_C
-#define LIBSTD_HPROTO(rettype, fname, ...) \
- rettype __host__##fname(__VA_ARGS__)
-
-#define PINVOKE_RENAME_HOST_ATTR(rettype, fname, ...) \
- rettype fname(__VA_ARGS__) __attribute__((pinvoke("MSCorelibWrapper_support.so","__host__"#fname)))
-
-#define LIBSTD_HPROTO_IMPL(rettype, fname, ...) \
- rettype __host__##fname(__VA_ARGS__)
diff --git a/libstd/src/Makefile.in b/libstd/src/Makefile.in
index 059b7cb9732..056491ed0e1 100644
--- a/libstd/src/Makefile.in
+++ b/libstd/src/Makefile.in
@@ -228,7 +228,6 @@ EGREP = @EGREP@
EXEEXT =
F77 = @F77@
FFLAGS = @FFLAGS@
-GCC4NET = @GCC4NET@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/libstd/src/math.c b/libstd/src/math.c
index d11d0d8bb0a..6e22a6289ee 100644
--- a/libstd/src/math.c
+++ b/libstd/src/math.c
@@ -203,7 +203,7 @@ LIBSTD_LPROTO_IMPL(double, frexp, double num, int* exp)
double res;
double pos_num;
- if (isnan(num)) {
+ if (LIBSTD_HNAME(fpclassify)(num) == FP_NAN) {
return num;
}
@@ -219,12 +219,12 @@ LIBSTD_LPROTO_IMPL(double, frexp, double num, int* exp)
}
/* compute e = 1+floor(log2(num)) */
else if (pos_num >= 1.0) {
- int e = (int)log2(pos_num) + 1;
+ int e = (int)LIBSTD_HNAME(log2)(pos_num) + 1;
*exp = e;
res = num / (double)(1 << e);
}
else {
- int e = 1 + (int)floor(log2(pos_num));
+ int e = 1 + (int)LIBSTD_HNAME(floor)(LIBSTD_HNAME(log2)(pos_num));
*exp = e;
res = num * (double)(1 << -e);
}
@@ -236,7 +236,7 @@ LIBSTD_LPROTO_IMPL(float, frexpf, float num, int* exp)
float res;
float pos_num;
- if (isnan(num)) {
+ if (LIBSTD_HNAME(fpclassify)(num) == FP_NAN) {
return num;
}
@@ -252,12 +252,12 @@ LIBSTD_LPROTO_IMPL(float, frexpf, float num, int* exp)
}
/* compute e = 1+floor(log2f(num)) */
else if (pos_num >= 1.0) {
- int e = (int)log2f(pos_num) + 1;
+ int e = (int)LIBSTD_HNAME(log2f)(pos_num) + 1;
*exp = e;
res = num / (double)(1 << e);
}
else {
- int e = 1 + (int)floor(log2f(pos_num));
+ int e = 1 + (int)LIBSTD_HNAME(floor)(LIBSTD_HNAME(log2f)(pos_num));
*exp = e;
res = num * (double)(1 << -e);
}
diff --git a/libstd/src_opt/MSCorelibWrapper.c b/libstd/src_opt/MSCorelibWrapper.c
deleted file mode 100644
index c8cc28815a4..00000000000
--- a/libstd/src_opt/MSCorelibWrapper.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-
- Copyright (C) 2007-2008 Free Software Foundation, Inc.
- Contributed by STMicroelectronics
-
-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. */
-
-#define __LIBSTD_CRT_BUILD
-
-#include "include/__OPT_MSCorlibWrapper.h"
-
-#include "include/__host.h"
-
-
-PINVOKE_RENAME_HOST_ATTR(int, open, char *path, int oflag);
-PINVOKE_RENAME_HOST_ATTR(int, write, int fildes, void *buf, int nbytes);
-PINVOKE_RENAME_HOST_ATTR(int, read, int fildes, void *buf, int nbytes);
-PINVOKE_RENAME_HOST_ATTR(int, close, int fildes);
-PINVOKE_RENAME_HOST_ATTR(long, lseek, int fildes, long offset, int whence);
-PINVOKE_RENAME_HOST_ATTR(int, fcntl, int fildes, int cmd, int arg);
-PINVOKE_RENAME_HOST_ATTR(int, rename, char *oldname, char *newname);
-PINVOKE_RENAME_HOST_ATTR(int, remove, char *filename);
-PINVOKE_RENAME_HOST_ATTR(int, link, char *existing, char *anew);
-PINVOKE_RENAME_HOST_ATTR(int, unlink, char *path);
-
-
-PINVOKE_RENAME_HOST_ATTR(void *, malloc, unsigned int size);
-PINVOKE_RENAME_HOST_ATTR(void, free, void *ptr);
-PINVOKE_RENAME_HOST_ATTR(void *, realloc, void *ptr, unsigned int size);
-
-PINVOKE_RENAME_HOST_ATTR(int *, errno, void);
-
-PINVOKE_RENAME_HOST_ATTR(int, clock, void);
-PINVOKE_RENAME_HOST_ATTR(void, exit, int status);
-
-PINVOKE_RENAME_HOST_ATTR(char *, getenv, char *name);
-
-PINVOKE_RENAME_HOST_ATTR(unsigned long, time, void *tptr);
-
-PINVOKE_RENAME_HOST_ATTR(void, gmtime, void *timer,
- int *tm_sec, int *tm_min, int *tm_hour,
- int *tm_mday, int *tm_mon, int *tm_year,
- int *tm_wday, int *tm_yday, int *tm_isdst);
-
-PINVOKE_RENAME_HOST_ATTR(void, gettimeofday, void *tv_sec, void *tv_usec);
-
-///////////////////////////////////////////////////////////////////////////////////////
-/// MATH SECTION /////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////
-// These functions maybe implemented as macros (e.g. the arm softfloat toolchain).
-// Therefore in order to be portable we cannot call it directly. We use the
-// mscoreliwrapper_support as a portability layer and pay the cost of an extra call
-
-PINVOKE_RENAME_HOST_ATTR(int, fpclassify, double p0);
-
-PINVOKE_RENAME_HOST_ATTR(double, dbl_epsilon, void);
-PINVOKE_RENAME_HOST_ATTR(double, dbl_minval, void);
-PINVOKE_RENAME_HOST_ATTR(double, dbl_maxval, void);
-PINVOKE_RENAME_HOST_ATTR(double, dbl_hugeval, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_epsilon, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_minval, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_maxval, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_hugeval, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_nan, void);
-PINVOKE_RENAME_HOST_ATTR(float, flt_infinity, void);
-
-PINVOKE_RENAME_HOST_ATTR(double, acos, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, acosf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, asin, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, asinf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, atan, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, atanf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, atan2, double p0, double p1);
-PINVOKE_RENAME_HOST_ATTR(float, atan2f, float p0, float p1);
-PINVOKE_RENAME_HOST_ATTR(double, cos, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, cosf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, sin, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, sinf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, tan, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, tanf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, cosh, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, coshf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, sinh, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, sinhf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, tanh, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, tanhf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, exp, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, expf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, exp2, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, exp2f, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, expm1, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, expm1f, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, ldexp, double p0, int p1);
-PINVOKE_RENAME_HOST_ATTR(float, ldexpf, float p0, int p1);
-PINVOKE_RENAME_HOST_ATTR(double, log, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, logf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, log10, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, log10f, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, log1p, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, log1pf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, log2, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, log2f, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, scalbn, double p0, int p1);
-PINVOKE_RENAME_HOST_ATTR(float, scalbnf, float p0, int p1);
-PINVOKE_RENAME_HOST_ATTR(double, scalbln, double p0, long p1);
-PINVOKE_RENAME_HOST_ATTR(float, scalblnf, float p0, long p1);
-PINVOKE_RENAME_HOST_ATTR(double, fabs, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, fabsf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, hypot, double p0, double p1);
-PINVOKE_RENAME_HOST_ATTR(float, hypotf, float p0, float p1);
-PINVOKE_RENAME_HOST_ATTR(double, pow, double p0, double p1);
-PINVOKE_RENAME_HOST_ATTR(float, powf, float p0, float p1);
-PINVOKE_RENAME_HOST_ATTR(double, ceil, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, ceilf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, cbrt, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, cbrtf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, sqrt, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, sqrtf, float p0);
-PINVOKE_RENAME_HOST_ATTR(double, floor, double p0);
-PINVOKE_RENAME_HOST_ATTR(float, floorf, float p0);
-PINVOKE_RENAME_HOST_ATTR(long, lround, double p0);
-PINVOKE_RENAME_HOST_ATTR(long, lroundf, float p0);
diff --git a/libstd/src_opt/MSCorelibWrapper.cs b/libstd/src_opt/MSCorelibWrapper.cs
new file mode 100644
index 00000000000..a26d0721705
--- /dev/null
+++ b/libstd/src_opt/MSCorelibWrapper.cs
@@ -0,0 +1,282 @@
+//
+// Copyright (C) 2008, Free Software Foundation, Inc.
+// Contributed by STMicroelectronics
+//
+
+using System.Runtime.InteropServices;
+
+public class MSCorelibWrapper
+{
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__open")]
+ unsafe public static extern int open(sbyte* path, int oflag);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__write")]
+ unsafe public static extern int write(int filedes, void* buf, int nbytes);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__read")]
+ unsafe public static extern int read(int filedes, void* buf, int nbytes);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__close")]
+ unsafe public static extern int close(int filedes);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__filesize")]
+ unsafe public static extern int filesize(sbyte* path);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__lseek")]
+ unsafe public static extern int lseek(int filedes, int offset, int whence);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__fcntl")]
+ unsafe public static extern int fcntl(int filedes, int cmd, int arg);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__getenv")]
+ unsafe public static extern sbyte* getenv(sbyte* name);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__malloc")]
+ unsafe public static extern void* malloc(uint size);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__free")]
+ unsafe public static extern void free(void* ptr);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__realloc")]
+ unsafe public static extern void* realloc(void* ptr, uint size);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__fpclassify")]
+ unsafe public static extern int fpclassify(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__clock")]
+ unsafe public static extern int clock();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__time")]
+ unsafe public static extern uint time(void* timer);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__gmtime")]
+ unsafe public static extern void gmtime(void* timer,
+ int* tm_sec, int* tm_min, int* tm_hour,
+ int* tm_mday, int* tm_mon, int* tm_year,
+ int* tm_wday, int* tm_yday, int* tm_isdst);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__gettimeofday")]
+ unsafe public static extern void gettimeofday (void *_tv_sec, void *_tv_usec);
+
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__exit")]
+ unsafe public static extern void exit(int status);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__rename")]
+ unsafe public static extern int rename(sbyte* oldname, sbyte* newname);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__remove")]
+ unsafe public static extern int remove(sbyte* filename);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__link")]
+ unsafe public static extern int link(sbyte* oldname, sbyte* newname);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__unlink")]
+ unsafe public static extern int unlink(sbyte* name);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__errno")]
+ unsafe public static extern int* errno();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__dbl_epsilon")]
+ unsafe public static extern double dbl_epsilon();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__dbl_minval")]
+ unsafe public static extern double dbl_minval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__dbl_maxval")]
+ unsafe public static extern double dbl_maxval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__dbl_hugeval")]
+ unsafe public static extern double dbl_hugeval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_epsilon")]
+ unsafe public static extern float flt_epsilon();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_minval")]
+ unsafe public static extern float flt_minval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_maxval")]
+ unsafe public static extern float flt_maxval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_hugeval")]
+ unsafe public static extern float flt_hugeval();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_nan")]
+ unsafe public static extern float flt_nan();
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__flt_infinity")]
+ unsafe public static extern float flt_infinity();
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ /// MATH SECTION /////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__acos")]
+ unsafe public static extern double acos(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__acosf")]
+ unsafe public static extern float acosf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__asin")]
+ unsafe public static extern double asin(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__asinf")]
+ unsafe public static extern float asinf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__atan")]
+ unsafe public static extern double atan(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__atanf")]
+ unsafe public static extern float atanf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__atan2")]
+ unsafe public static extern double atan2(double p0, double p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__atan2f")]
+ unsafe public static extern float atan2f(float p0, float p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__cos")]
+ unsafe public static extern double cos(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__cosf")]
+ unsafe public static extern float cosf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sin")]
+ unsafe public static extern double sin(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sinf")]
+ unsafe public static extern float sinf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__tan")]
+ unsafe public static extern double tan(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__tanf")]
+ unsafe public static extern float tanf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__cosh")]
+ unsafe public static extern double cosh(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__coshf")]
+ unsafe public static extern float coshf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sinh")]
+ unsafe public static extern double sinh(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sinhf")]
+ unsafe public static extern float sinhf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__tanh")]
+ unsafe public static extern double tanh(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__tanhf")]
+ unsafe public static extern float tanhf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__exp")]
+ unsafe public static extern double exp(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__expf")]
+ unsafe public static extern float expf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__exp2")]
+ unsafe public static extern double exp2(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__exp2f")]
+ unsafe public static extern float exp2f(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__expm1")]
+ unsafe public static extern double expm1(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__expm1f")]
+ unsafe public static extern float expm1f(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log")]
+ unsafe public static extern double log(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__logf")]
+ unsafe public static extern float logf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log10")]
+ unsafe public static extern double log10(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log10f")]
+ unsafe public static extern float log10f(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log1p")]
+ unsafe public static extern double log1p(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log1pf")]
+ unsafe public static extern float log1pf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log2")]
+ unsafe public static extern double log2(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__log2f")]
+ unsafe public static extern float log2f(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__fabs")]
+ unsafe public static extern double fabs(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__fabsf")]
+ unsafe public static extern float fabsf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__pow")]
+ unsafe public static extern double pow(double p0, double p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__powf")]
+ unsafe public static extern float powf(float f0, float f1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__ceil")]
+ unsafe public static extern double ceil(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__ceilf")]
+ unsafe public static extern float ceilf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__cbrt")]
+ unsafe public static extern double cbrt(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__cbrtf")]
+ unsafe public static extern float cbrtf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sqrt")]
+ unsafe public static extern double sqrt(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__sqrtf")]
+ unsafe public static extern float sqrtf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__floor")]
+ unsafe public static extern double floor(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__floorf")]
+ unsafe public static extern float floorf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__lround")]
+ unsafe public static extern int lround(double d);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__lroundf")]
+ unsafe public static extern int lroundf(float f);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__ldexp")]
+ unsafe public static extern double ldexp(double p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__ldexpf")]
+ unsafe public static extern float ldexpf(float p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__scalbn")]
+ unsafe public static extern double scalbn(double p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__scalbnf")]
+ unsafe public static extern float scalbnf(float p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__scalbln")]
+ unsafe public static extern double scalbln(double p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__scalblnf")]
+ unsafe public static extern float scalblnf(float p0, int p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__hypot")]
+ unsafe public static extern double hypot(double p0, double p1);
+
+ [DllImport("MSCorelibWrapper_support.so", EntryPoint="__host__hypotf")]
+ unsafe public static extern float hypotf(float p0, float p1);
+
+};
+
diff --git a/libstd/src_opt/MSCorelibWrapper_support.c b/libstd/src_opt/MSCorelibWrapper_support.c
index 61fe01e6ba8..4f952b14d93 100644
--- a/libstd/src_opt/MSCorelibWrapper_support.c
+++ b/libstd/src_opt/MSCorelibWrapper_support.c
@@ -24,6 +24,14 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#define OPT_MSCORLIB_WRAPPER
-#include "include/__OPT_MSCorlibWrapper.h"
+#define __BEGIN_EXTERN_C
+#define __END_EXTERN_C
+
+#define LIBSTD_HPROTO(rettype, fname, ...) \
+ rettype __host__##fname(__VA_ARGS__)
+
+#define LIBSTD_HPROTO_IMPL(rettype, fname, ...) \
+ rettype __host__##fname(__VA_ARGS__)
+
#include "src/__host.c"
diff --git a/libstd/src_opt/Makefile.am b/libstd/src_opt/Makefile.am
index c14c1a71e34..2b6212d158e 100644
--- a/libstd/src_opt/Makefile.am
+++ b/libstd/src_opt/Makefile.am
@@ -7,8 +7,8 @@ libnative_PROGRAMS = MSCorelibWrapper_support.so
MSCorelibWrapper_support.so: MSCorelibWrapper_support.c
$(COMPILE) -std=c99 -fpic -shared -I$(top_srcdir) -o $@ $<
-MSCorelibWrapper.dll: MSCorelibWrapper.c
- $(GCC4NET) -nostdlib -l gcc4net.dll -I$(top_srcdir) $< -o $@
+MSCorelibWrapper.dll: MSCorelibWrapper.cs MSCorelibWrapper_support.so
+ $(MCS) $< -unsafe -target:library -out:$@
install-libciloptPROGRAMS: $(libcilopt_PROGRAMS)
test -z "$(libciloptdir)" || $(mkdir_p) "$(DESTDIR)$(libciloptdir)"
diff --git a/libstd/src_opt/Makefile.in b/libstd/src_opt/Makefile.in
index 9e897b796fc..3ff111982b0 100644
--- a/libstd/src_opt/Makefile.in
+++ b/libstd/src_opt/Makefile.in
@@ -107,7 +107,6 @@ EGREP = @EGREP@
EXEEXT =
F77 = @F77@
FFLAGS = @FFLAGS@
-GCC4NET = @GCC4NET@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -456,8 +455,8 @@ uninstall-am: uninstall-info-am uninstall-libciloptPROGRAMS \
MSCorelibWrapper_support.so: MSCorelibWrapper_support.c
$(COMPILE) -std=c99 -fpic -shared -I$(top_srcdir) -o $@ $<
-MSCorelibWrapper.dll: MSCorelibWrapper.c
- $(GCC4NET) -nostdlib -l gcc4net.dll -I$(top_srcdir) $< -o $@
+MSCorelibWrapper.dll: MSCorelibWrapper.cs MSCorelibWrapper_support.so
+ $(MCS) $< -unsafe -target:library -out:$@
install-libciloptPROGRAMS: $(libcilopt_PROGRAMS)
test -z "$(libciloptdir)" || $(mkdir_p) "$(DESTDIR)$(libciloptdir)"