From 3fda9d86d679e905aff77fbb5f18fd8c117d4ba8 Mon Sep 17 00:00:00 2001 From: Roberto Costa Date: Fri, 10 Nov 2006 09:56:10 +0000 Subject: Merge from ST 20061110 git-svn-id: https://gcc.gnu.org/svn/gcc/branches/st/cli@118651 138bc75d-0d04-0410-961f-82ee72b054a4 --- cil32-crosstool.sh | 45 ++- configure | 2 +- configure.in | 2 +- gcc/config/cil32/cil32.c | 56 ++- gcc/config/cil32/cil32.h | 7 +- gcc/config/cil32/cil32.opt | 8 + gcc/config/cil32/gcc4net.cs | 21 +- gcc/config/cil32/gen-cil.c | 784 +++++++++++++++++++++++++++++++------ gcc/config/cil32/tree-simp-cil.c | 826 +++++++++++++++++++++++++++++++-------- gcc/config/cil32/tree-simp-cil.h | 2 +- 10 files changed, 1416 insertions(+), 337 deletions(-) diff --git a/cil32-crosstool.sh b/cil32-crosstool.sh index 40f587e062c..73b53eb30d9 100755 --- a/cil32-crosstool.sh +++ b/cil32-crosstool.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash INSTALL_BINUTILS=yes @@ -8,20 +8,15 @@ TARGET=cil32 BUILD_DIR=${BUILD_DIR-`pwd`} SOURCE_DIR=${SOURCE_DIR-`dirname $0`} -SOURCE_DIR=`cd $SOURCE_DIR; pwd` PREFIX=${PREFIX-`pwd`/newbuild} -SYSROOT=${PREFIX}/${TARGET} LANGUAGES=c -echo "DIRECTORIES:" -echo " BUILD_DIR: " ${BUILD_DIR} -echo " SOURCE_DIR: " ${SOURCE_DIR} -echo " SYSROOT: " ${SYSROOT} -echo " PREFIX: " ${PREFIX} - _help() { echo "Options:" + echo " -src : dir with the sources (default ${SOURCE_DIR})" + echo " -build : dir where to the the build (default ${BUILD_DIR})" + echo " -prefix : dir where to install (default ${PREFIX})" echo " -binutils : install of binutils (default)" echo " -nobinutils : skip install of binutils" echo " -gcc : gcc build and installation (default)" @@ -54,7 +49,7 @@ _binutils() echo " CIL ASSEMBLER: " ${CIL_AS} echo " CIL LINKER: " ${CIL_LD} - echo + echo "" echo "Installing Bin Utils" cat > ${SYSROOT}/bin/tool_not_exist <<_EOF_ @@ -83,6 +78,9 @@ for i in "\$@" ; do /tmp*) PARAM="\${PARAM} /\${i}"; ;; + /exchange*) + PARAM="\${PARAM} /\${i}"; + ;; *) PARAM="\${PARAM} \${i}"; ;; @@ -119,7 +117,7 @@ _EOF_ cp ${SYSROOT}/bin/strings ${PREFIX}/bin/${TARGET}-strings cp ${SYSROOT}/bin/strip ${PREFIX}/bin/${TARGET}-strip - echo + echo "" echo "Installing vm wrappers" cat > ${PREFIX}/bin/${TARGET}-ilrun <<_EOF_ @@ -147,7 +145,7 @@ _EOF_ _gcc() { - echo + echo "" echo "Configuring GCC" mkdir -p ${BUILD_DIR}/build-gcc @@ -159,11 +157,11 @@ _gcc() --prefix=${PREFIX} \ --with-local-prefix=${SYSROOT} - echo + echo "" echo "Building GCC" make all - echo + echo "" echo "Installing GCC" make install } @@ -183,6 +181,15 @@ elif [ "x$1" == x-binutils ] ; then INSTALL_BINUTILS=yes elif [ "x$1" == x-gcc ] ; then INSTALL_GCC=yes +elif [ "x$1" == x-src ] ; then + SOURCE_DIR=$2 + shift 1 +elif [ "x$1" == x-build ] ; then + BUILD_DIR=$2 + shift 1 +elif [ "x$1" == x-prefix ] ; then + PREFIX=$2 + shift 1 else echo "Unrecognized option: " $1 _help ; @@ -192,6 +199,15 @@ fi shift 1 done +SOURCE_DIR=`cd $SOURCE_DIR; pwd` +SYSROOT=${PREFIX}/${TARGET} + +echo "DIRECTORIES:" +echo " BUILD_DIR: " ${BUILD_DIR} +echo " SOURCE_DIR: " ${SOURCE_DIR} +echo " SYSROOT: " ${SYSROOT} +echo " PREFIX: " ${PREFIX} + PATH="${PREFIX}/bin:${PATH}" export PATH @@ -203,7 +219,6 @@ then fi - if test "x${INSTALL_GCC}" == "xyes" then _gcc diff --git a/configure b/configure index 0780b324d03..d0ad6972073 100755 --- a/configure +++ b/configure @@ -1344,7 +1344,7 @@ case "${target}" in ;; cil32-*-*) unsupported_languages="$unsupported_languages ada fortran java" - noconfigdirs="$noconfigdirs target-libssp target-libiberty target-libmudflap" + skipdirs="$skipdirs target-libssp target-libiberty target-libmudflap" ;; cris-*-* | crisv32-*-*) unsupported_languages="$unsupported_languages java" diff --git a/configure.in b/configure.in index 2ab1abd1512..7510699cfee 100644 --- a/configure.in +++ b/configure.in @@ -520,7 +520,7 @@ case "${target}" in ;; cil32-*-*) unsupported_languages="$unsupported_languages ada fortran java" - noconfigdirs="$noconfigdirs target-libssp target-libiberty target-libmudflap" + skipdirs="$skipdirs target-libssp target-libiberty target-libmudflap" ;; cris-*-* | crisv32-*-*) unsupported_languages="$unsupported_languages java" diff --git a/gcc/config/cil32/cil32.c b/gcc/config/cil32/cil32.c index 7cf4938b285..b598d25611f 100644 --- a/gcc/config/cil32/cil32.c +++ b/gcc/config/cil32/cil32.c @@ -59,9 +59,9 @@ Roberto Costa */ /* Per-function machine data. */ struct machine_function GTY(()) - { - char dummy; - }; +{ + char dummy; +}; static tree cil32_handle_function_attribute (tree *, tree, tree, int, bool *); static void cil32_file_start (void); @@ -125,7 +125,7 @@ cil32_handle_function_attribute (tree *node, tree name, } if (strcmp (IDENTIFIER_POINTER (name), "pinvoke") == 0) - cil_add_pinvoke(*node); + cil_add_pinvoke(*node); return NULL_TREE; } @@ -174,20 +174,30 @@ cil32_assemble_integer (rtx x ATTRIBUTE_UNUSED, } static tree cil32_builtin_va_arg_decl; +tree cil32_is_LE_decl; static void cil32_init_builtins (void) { - - tree arglist = build_tree_list (NULL_TREE, ptr_type_node); - arglist = tree_cons (NULL_TREE, va_list_type_node, arglist); - cil32_builtin_va_arg_decl = lang_hooks.builtin_function ("__builtin_va_arg", - build_function_type (ptr_type_node, - arglist), - CIL32_BUILTIN_VA_ARG, - BUILT_IN_MD, - NULL, - NULL_TREE); + tree arglist; + tree va_list_ptr_type_node = build_pointer_type (va_list_type_node); + + arglist = build_tree_list (NULL_TREE, ptr_type_node); + arglist = tree_cons (NULL_TREE, va_list_ptr_type_node, arglist); + cil32_builtin_va_arg_decl = lang_hooks.builtin_function ("__builtin_va_arg", + build_function_type (ptr_type_node, + arglist), + CIL32_BUILTIN_VA_ARG, + BUILT_IN_MD, + NULL, + NULL_TREE); + cil32_is_LE_decl = lang_hooks.builtin_function ("__builtin_isLittleEndian", + build_function_type (integer_type_node, + NULL_TREE), + CIL32_BUILTIN_IS_LITTLE_ENDIAN, + BUILT_IN_MD, + NULL, + NULL_TREE); } static tree @@ -213,13 +223,17 @@ cil32_build_builtin_va_list (void) static tree cil32_gimplify_va_arg (tree valist, tree type, tree *pre_p ATTRIBUTE_UNUSED, tree *post_p ATTRIBUTE_UNUSED) { - tree fcall; - tree ptr_type = build_pointer_type(type); - tree arglist = build_tree_list (NULL_TREE, build_int_cstu (ptr_type,0)); - arglist = tree_cons (NULL_TREE, valist, arglist); - fcall = build_function_call_expr (cil32_builtin_va_arg_decl, arglist); - TREE_TYPE (fcall) = ptr_type; - return build1(INDIRECT_REF,type,fcall); + tree fcall; + tree ptr_type = build_pointer_type (type); + tree arglist = build_tree_list (NULL_TREE, build_int_cstu (ptr_type, 0)); + arglist = tree_cons (NULL_TREE, + build1 (ADDR_EXPR, + build_pointer_type (va_list_type_node), + valist), + arglist); + fcall = build_function_call_expr (cil32_builtin_va_arg_decl, arglist); + TREE_TYPE (fcall) = ptr_type; + return build1 (INDIRECT_REF, type, fcall); } /* Target hook for vector_mode_supported_p. */ diff --git a/gcc/config/cil32/cil32.h b/gcc/config/cil32/cil32.h index 43af5cf5eda..3769f4495c9 100644 --- a/gcc/config/cil32/cil32.h +++ b/gcc/config/cil32/cil32.h @@ -116,7 +116,7 @@ extern int target_flags; #define FIRST_PSEUDO_REGISTER (1) #define FIXED_REGISTERS {0} -#define CALL_USED_REGISTERS {0} +#define CALL_USED_REGISTERS {1} /* Node: Allocation Order */ @@ -528,9 +528,12 @@ extern struct tree_opt_pass pass_simp_cil; /* cil32 builtin ID */ enum cil32_builtin { - CIL32_BUILTIN_VA_ARG + CIL32_BUILTIN_VA_ARG, + CIL32_BUILTIN_IS_LITTLE_ENDIAN }; +extern tree cil32_is_LE_decl; + /* * Local variables: * eval: (c-set-style "gnu") diff --git a/gcc/config/cil32/cil32.opt b/gcc/config/cil32/cil32.opt index 79fdcc0291d..3a73d34c2e7 100644 --- a/gcc/config/cil32/cil32.opt +++ b/gcc/config/cil32/cil32.opt @@ -51,3 +51,11 @@ Emits the GIMPLE node as a CIL comment before the CIL sequence memit-external-assembly Target Mask(EMIT_EXTERNAL_ASSEMBLY) Emits all external symbols as if defined in an assembly called ExternalAssembly + +memit-vcg +Target Mask(EMIT_VCG) +Emits the functions in VCG format + +Wcil-missing-prototypes +Target Var(warn_cil_missing_prototypes) Init(1) +Warn about missing prototypes dangerous for CLI generation diff --git a/gcc/config/cil32/gcc4net.cs b/gcc/config/cil32/gcc4net.cs index 3321a55b4ff..c1a4ba0302b 100644 --- a/gcc/config/cil32/gcc4net.cs +++ b/gcc/config/cil32/gcc4net.cs @@ -53,13 +53,20 @@ namespace gcc4net { public unsafe static void Startup() { Assembly assembly; - Type type; + MethodInfo initMethod = null; // Find the module that contains the "main" function. assembly = Assembly.GetEntryAssembly(); - type = assembly.GetType(""); + + Type type = assembly.GetType(""); + if (type != null) + initMethod = type.GetMethod(".init"); + else { + Module module = assembly.GetModules()[0]; + initMethod = module.GetMethod(".init"); + } + // Invoke the application's ".init" function, if present. - MethodInfo initMethod = type.GetMethod(".init"); if(initMethod != null) initMethod.Invoke(null, null); } @@ -88,5 +95,13 @@ namespace gcc4net { public static long __absti2(long a) { return (a>=0) ? a : -a; } public static float __abssf2(float a) { return (a>=0) ? a : -a; } public static double __absdf2(double a) { return (a>=0) ? a : -a; } + + public static unsafe bool __isLittleEndian() { + // big endian: 3f f0 00 00 00 00 00 00 + // little endian: 00 00 00 00 00 00 f0 3f + double d = 1.0; + byte* b = (byte*)&d; + return b[0]==0; + } } } diff --git a/gcc/config/cil32/gen-cil.c b/gcc/config/cil32/gen-cil.c index afe4d918756..124d38760f4 100644 --- a/gcc/config/cil32/gen-cil.c +++ b/gcc/config/cil32/gen-cil.c @@ -56,19 +56,33 @@ Roberto Costa */ (! TYPE_CONTEXT (EXP) \ || TREE_CODE (TYPE_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL) -struct fnct_attr { +/* Length of compacted identifiers (in characters) */ +#define COMPACT_ID_LENGTH 16 + +struct fnct_attr +{ const char *assembly_name; const char *cil_name; const char *pinvoke_assembly; const char *pinvoke_fname; }; +/* Element of the pointer id hash table */ +struct pointer_id_data +{ + const void *ptr; + unsigned int id; +}; + /* Local functions, macros and variables. */ +static hashval_t pointer_id_data_hash (const void *); +static int pointer_id_data_eq (const void *, const void *); static void decode_function_attrs (tree, struct fnct_attr *); static void mark_var_defs_uses (tree); static void remove_stloc_ldloc (block_stmt_iterator, tree *, bool *); static void mark_referenced_type (tree); static void mark_referenced_string (tree); +static unsigned int get_string_cst_id (tree); static void dump_decl_name (FILE *, tree); static void dump_string_name (FILE *, tree); static void dump_label_name (FILE *, tree); @@ -80,7 +94,7 @@ static void gen_cil_modify_expr (FILE *, tree); static char * append_string (char *, const char *, unsigned int *, unsigned int *); static char * append_coded_type (char *, tree, unsigned int *, unsigned int *); -static char * get_md5 (const char *, size_t, size_t *); +static char * get_compact_identifier (const char *, size_t, size_t *); static tree make_valuetype_identifier (tree); static void print_valuetype_decl (FILE *, tree); static void dump_type (FILE *, tree, bool); @@ -94,6 +108,7 @@ static void stack_reset (void); static void stack_push (unsigned int); static void stack_pop (unsigned int); static void gen_integral_conv (FILE *, tree, tree); +static void gen_binary_cond_branch (FILE *, tree, tree); static void gen_start_function (FILE *); static unsigned int gen_cil (void); static void gen_cil_1 (FILE *); @@ -111,8 +126,28 @@ static GTY(()) varray_type referenced_strings; static struct pointer_set_t *referenced_string_ptrs; static struct pointer_set_t *referenced_pinvoke; static GTY(()) varray_type pending_ctors; +static htab_t pointer_id_htable; +static unsigned int pointer_next_id = 0; static unsigned int stack; static unsigned int max_stack; +static basic_block bb; + + +/* Hashing and equality routines for pointer id hash table. */ +static hashval_t +pointer_id_data_hash (const void *p) +{ + return ((unsigned long)((struct pointer_id_data *)p)->ptr >> 4) & 255; +} + +static int +pointer_id_data_eq (const void *p1, const void *p2) +{ + const void* ptr1 = ((struct pointer_id_data *)p1)->ptr; + const void* ptr2 = ((struct pointer_id_data *)p2)->ptr; + + return ptr1 == ptr2; +} /* Recursively mark the definitions and the uses of the non-static @@ -156,22 +191,58 @@ mark_var_defs_uses (tree node) /* Calls to some built-in functions require ad-hoc simplifications */ if (dfun && DECL_BUILT_IN (dfun)) { - switch (DECL_FUNCTION_CODE (dfun)) + if (DECL_BUILT_IN_CLASS (dfun) == BUILT_IN_MD) { - case BUILT_IN_VA_COPY: - { - tree va_dest = TREE_VALUE (TREE_OPERAND (node, 1)); + switch (DECL_FUNCTION_CODE (dfun)) + { + case CIL32_BUILTIN_VA_ARG: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); - gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR); - gcc_assert (TREE_CODE (TREE_OPERAND (va_dest, 0)) == VAR_DECL - && !DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0))); + gcc_assert (TREE_CODE (va) == ADDR_EXPR + || TREE_CODE (va) == VAR_DECL); - TREE_SIDE_EFFECTS (TREE_OPERAND (va_dest, 0)) = true; - } - break; + if (TREE_CODE (va) == VAR_DECL) + TREE_LANG_FLAG_0 (va) = true; + } + break; - default: - ; + default: + ; + } + } + else + { + switch (DECL_FUNCTION_CODE (dfun)) + { + case BUILT_IN_VA_START: + case BUILT_IN_VA_END: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); + + gcc_assert (TREE_CODE (va) == ADDR_EXPR + || TREE_CODE (va) == VAR_DECL); + + if (TREE_CODE (va) == VAR_DECL) + TREE_LANG_FLAG_0 (va) = true; + } + break; + + case BUILT_IN_VA_COPY: + { + tree va_dest = TREE_VALUE (TREE_OPERAND (node, 1)); + + gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR); + gcc_assert (TREE_CODE (TREE_OPERAND (va_dest, 0)) == VAR_DECL + && !DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0))); + + TREE_LANG_FLAG_0 (TREE_OPERAND (va_dest, 0)) = true; + } + break; + + default: + ; + } } } } @@ -217,14 +288,18 @@ mark_var_defs_uses (tree node) { if (! TREE_ADDRESSABLE (lhs) && ! TREE_STATIC (lhs) - && ! TREE_THIS_VOLATILE (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); @@ -232,7 +307,7 @@ mark_var_defs_uses (tree node) mark_var_defs_uses (rhs); if (AGGREGATE_TYPE_P (TREE_TYPE (lhs)) && TREE_CODE (rhs) == VAR_DECL) - TREE_SIDE_EFFECTS (rhs) = true; + TREE_LANG_FLAG_0 (rhs) = true; gcc_assert (TREE_CODE (rhs) != CONSTRUCTOR && TREE_CODE (rhs) != STRING_CST); @@ -252,24 +327,17 @@ mark_var_defs_uses (tree node) mark_var_defs_uses (TREE_OPERAND (node, 0)); break; + case ARRAY_REF: + gcc_assert (integer_zerop (TREE_OPERAND (node, 1))); case ADDR_EXPR: case COMPONENT_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_SIDE_EFFECTS (op) = true; - } - break; - case INDIRECT_REF: { tree op = TREE_OPERAND (node, 0); mark_var_defs_uses (op); - if (AGGREGATE_TYPE_P (TREE_TYPE (node)) && TREE_CODE (op) == VAR_DECL) - TREE_SIDE_EFFECTS (op) = true; + if (AGGREGATE_TYPE_P (TREE_TYPE (op)) && TREE_CODE (op) == VAR_DECL) + TREE_LANG_FLAG_0 (op) = true; } break; @@ -291,11 +359,15 @@ mark_var_defs_uses (tree 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: @@ -393,6 +465,8 @@ remove_stloc_ldloc (block_stmt_iterator bsi, tree *node_ptr, bool *mod) case INIT_EXPR: case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (node, 0)) != VAR_DECL) + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 1), mod); gcc_assert (TREE_CODE (TREE_OPERAND (node, 1)) != CONSTRUCTOR && TREE_CODE (TREE_OPERAND (node, 1)) != STRING_CST); @@ -408,6 +482,7 @@ remove_stloc_ldloc (block_stmt_iterator bsi, tree *node_ptr, bool *mod) case ADDR_EXPR: case COMPONENT_REF: case INDIRECT_REF: + case ARRAY_REF: case ABS_EXPR: case RETURN_EXPR: case WITH_SIZE_EXPR: @@ -415,14 +490,9 @@ remove_stloc_ldloc (block_stmt_iterator bsi, tree *node_ptr, bool *mod) break; case VAR_DECL: - /* In GIMPLE, TREE_SIDE_EFFECTS is true for a VAR_DECL only if the - variable is volatile. - However, mark_var_defs_uses (...) function sets TREE_SIDE_EFFECTS - for some non-volatile variables that shouldn't be removed. */ - if (! TREE_ADDRESSABLE (node) - && ! TREE_STATIC (node) - && ! TREE_SIDE_EFFECTS (node) - && ! DECL_FILE_SCOPE_P (node)) + /* 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; @@ -591,7 +661,7 @@ mark_referenced_type (tree t) else orig_name = IDENTIFIER_POINTER (DECL_NAME (type_name)); - snprintf (suffix, 31, "?vt%lu", (unsigned long)t); + snprintf (suffix, 15, "?vt%u", TYPE_UID (t)); tmp_name = (char *)xmalloc (tmp_name_max_len); tmp_name = append_string (tmp_name, orig_name, @@ -675,6 +745,33 @@ mark_referenced_string (tree t) } } +/* Get an unique id for string constant NODE. */ + +static +unsigned int get_string_cst_id (tree node) +{ + struct pointer_id_data tmp_pid; + void **slot; + + gcc_assert (TREE_CODE (node) == STRING_CST); + + tmp_pid.ptr = TREE_STRING_POINTER (node); + slot = htab_find_slot (pointer_id_htable, &tmp_pid, INSERT); + + if (*slot != NULL) + return ((struct pointer_id_data *)(*slot))->id; + else + { + struct pointer_id_data *pid = XNEW (struct pointer_id_data); + + *slot = pid; + pid->ptr = TREE_STRING_POINTER (node); + pid->id = pointer_next_id++; + + return pid->id; + } +} + /* Mark the function represented by tree T as a pinvoke. T must be a FUNCTION_DECL node. */ @@ -691,20 +788,15 @@ cil_add_pinvoke (tree t) static void dump_decl_name (FILE* file, tree node) { - gcc_assert (DECL_P (node) || TREE_CODE (node) == IDENTIFIER_NODE); + gcc_assert (DECL_P (node)); fputs ("'", file); + mark_decl_referenced (node); + if (DECL_ASSEMBLER_NAME_SET_P (node)) - { - fprintf (file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node))); - } - else if (TREE_CODE (node) == IDENTIFIER_NODE) - fprintf (file, IDENTIFIER_POINTER (node)); + fprintf (file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node))); else if (DECL_NAME (node)) - { - mark_decl_referenced (node); - fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node))); - } + fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node))); else fprintf (file, "?UNNAMED%d", DECL_UID (node)); @@ -718,7 +810,7 @@ dump_string_name (FILE* file, tree node) { gcc_assert (TREE_CODE (node) == STRING_CST); - fprintf (file, "'?string%lu'", (unsigned long)TREE_STRING_POINTER (node)); + fprintf (file, "'?string%u'", get_string_cst_id (node)); } /* Dump the name of a label. */ @@ -739,6 +831,29 @@ dump_label_name (FILE* file, tree 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, ""); + } + } + else + { + fprintf (stream, ""); + } +} + /* 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. */ @@ -788,7 +903,7 @@ dump_fun_type (FILE *stream, tree fun_type, tree fun, const char *name, bool ref args_type = TYPE_ARG_TYPES (fun_type); if (args_type == NULL) - warning (0, + warning (OPT_Wcil_missing_prototypes, "Missing function %s prototype, guessing it, you should fix the code", fun?IDENTIFIER_POINTER (DECL_NAME (fun)):""); else @@ -1283,6 +1398,19 @@ compute_addr_expr (FILE *file, tree t) 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); + + compute_addr_expr (file, node); + } + break; + case COMPONENT_REF: { tree obj = TREE_OPERAND (t, 0); @@ -1404,7 +1532,7 @@ 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) || TREE_CODE (in_type) == POINTER_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)); @@ -1466,6 +1594,39 @@ gen_integral_conv (FILE *file, tree out_type, tree in_type) } } +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); + + 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; + default: + gcc_unreachable (); + } + + if (is_unsigned) + fputs (".un\t", file); + else + fputs ("\t", file); + dump_label_name (file, label); + + stack_pop (2); +} + /* Dump the node NODE in CIL on the file FILE. */ static void gen_cil_node (FILE *file, tree node) @@ -1497,7 +1658,7 @@ gen_cil_node (FILE *file, tree node) fputs ("\n\tldc.i8\t", file); dump_double_int (file, TREE_INT_CST (node), false); - if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) + if (POINTER_TYPE_P (TREE_TYPE (node))) fputs ("\n\tconv.i", file); stack_push (1); @@ -1595,9 +1756,18 @@ gen_cil_node (FILE *file, tree node) break; case GOTO_EXPR: - fputs ("\n\tbr ", file); - dump_label_name (file, GOTO_DESTINATION (node)); - gcc_assert (stack == 0); + { + tree label_decl = GOTO_DESTINATION (node); + 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: @@ -1606,37 +1776,44 @@ gen_cil_node (FILE *file, tree node) && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR); op0 = COND_EXPR_COND (node); - if (TREE_CODE (op0) == LE_EXPR - || TREE_CODE (op0) == LT_EXPR - || TREE_CODE (op0) == GE_EXPR - || TREE_CODE (op0) == GT_EXPR - || TREE_CODE (op0) == EQ_EXPR + if (TREE_CODE (op0) == EQ_EXPR || TREE_CODE (op0) == NE_EXPR) - { tree op00 = TREE_OPERAND (op0, 0); tree op01 = TREE_OPERAND (op0, 1); - bool is_unsigned = TYPE_UNSIGNED (TREE_TYPE (op00)); - gen_cil_node (file, op00); - gen_cil_node (file, op01); - switch (TREE_CODE (op0)) + 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))))) { - case LE_EXPR: fputs ("\n\tble", file); break; - case LT_EXPR: fputs ("\n\tblt", file); break; - case GE_EXPR: fputs ("\n\tbge", file); break; - case GT_EXPR: fputs ("\n\tbgt", file); break; - case EQ_EXPR: fputs ("\n\tbeq", file); is_unsigned = FALSE; break; - case NE_EXPR: fputs ("\n\tbne", file); is_unsigned = TRUE; break; - default: - gcc_unreachable (); - } + if ((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, GOTO_DESTINATION (COND_EXPR_THEN (node))); - if (is_unsigned) - fputs (".un\t", file); + stack_pop (1); + } else - fputs ("\t", file); - dump_label_name (file, GOTO_DESTINATION (COND_EXPR_THEN (node))); - stack_pop (2); + gen_binary_cond_branch (file, op0, + GOTO_DESTINATION (COND_EXPR_THEN (node))); + } + else if (TREE_CODE (op0) == LE_EXPR + || TREE_CODE (op0) == LT_EXPR + || TREE_CODE (op0) == GE_EXPR + || TREE_CODE (op0) == GT_EXPR) + { + gen_binary_cond_branch (file, op0, + GOTO_DESTINATION (COND_EXPR_THEN (node))); } else { @@ -1648,9 +1825,7 @@ gen_cil_node (FILE *file, tree node) stack_pop (2); } - fputs ("\n\tbr\t", file); - dump_label_name (file, GOTO_DESTINATION (COND_EXPR_ELSE (node))); - gcc_assert (stack == 0); + gen_cil_node (file, COND_EXPR_ELSE (node)); break; case SWITCH_EXPR: @@ -1828,8 +2003,13 @@ gen_cil_node (FILE *file, tree node) tree dummy = TREE_VALUE (TREE_CHAIN (args)); tree type = TREE_TYPE (TREE_TYPE (dummy)); - gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (va)) == va_list_type_node); - compute_addr_expr (file, va); + gcc_assert (TREE_CODE (va) == ADDR_EXPR + || TREE_CODE (va) == VAR_DECL); + gcc_assert (POINTER_TYPE_P (TREE_TYPE (va)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va))) + == va_list_type_node); + + gen_cil_node (file, va); fputs ("\n\tcall\tinstance typedref [mscorlib]System.ArgIterator::GetNextArg()" "\n\trefanyval ", file); @@ -1839,6 +2019,16 @@ gen_cil_node (FILE *file, tree node) } break; + case CIL32_BUILTIN_IS_LITTLE_ENDIAN: + { + fputs ("\n\tcall\tbool [gcc4net]gcc4net.Crt::__isLittleEndian()", + file); + + stack_push (1); + done = true; + } + break; + default: gcc_assert (0); } @@ -1852,17 +2042,23 @@ gen_cil_node (FILE *file, tree node) tree va = TREE_VALUE (TREE_OPERAND (node, 1)); /* A lowering phase should have checked that va - has no side effects. */ - gcc_assert (! TREE_SIDE_EFFECTS (va)); + has no side effects. + There is alaready an assertion to prevent that + in the stloc ldloc elimination. */ + + gcc_assert (TREE_CODE (va) == ADDR_EXPR + || TREE_CODE (va) == VAR_DECL); + gcc_assert (POINTER_TYPE_P (TREE_TYPE (va)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va))) + == va_list_type_node); - gcc_assert (TREE_CODE (va) == ADDR_EXPR); - compute_addr_expr (file, TREE_OPERAND (va, 0)); + gen_cil_node (file, va); fputs ("\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator", file); stack_pop (1); - compute_addr_expr (file, TREE_OPERAND (va, 0)); + gen_cil_node (file, va); fputs ("\n\targlist" "\n\tcall\tinstance void " "[mscorlib]System.ArgIterator::.ctor(valuetype " @@ -1879,8 +2075,13 @@ gen_cil_node (FILE *file, tree node) { tree va = TREE_VALUE (TREE_OPERAND (node, 1)); - gcc_assert (TREE_CODE (va) == ADDR_EXPR); - compute_addr_expr (file, TREE_OPERAND (va, 0)); + gcc_assert (TREE_CODE (va) == ADDR_EXPR + || TREE_CODE (va) == VAR_DECL); + gcc_assert (POINTER_TYPE_P (TREE_TYPE (va)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va))) + == va_list_type_node); + + gen_cil_node (file, va); fputs ("\n\tcall\tinstance void [mscorlib]System.ArgIterator::End()", file); @@ -2028,12 +2229,12 @@ gen_cil_node (FILE *file, tree node) if (args_type == NULL) { if (direct_call) - warning (0, + warning (OPT_Wcil_missing_prototypes, "Missing function %s prototype, guessing it, " "you should fix the code", IDENTIFIER_POINTER (DECL_NAME (dfun))); else - warning (0, + warning (OPT_Wcil_missing_prototypes, "Missing indirect function prototype, guessing it, " "you should fix the code"); } @@ -2144,7 +2345,6 @@ gen_cil_node (FILE *file, tree node) break; case BIT_IOR_EXPR: - case BIT_AND_EXPR: case BIT_XOR_EXPR: op0 = TREE_OPERAND (node, 0); op1 = TREE_OPERAND (node, 1); @@ -2155,7 +2355,6 @@ gen_cil_node (FILE *file, tree node) switch (TREE_CODE (node)) { case BIT_IOR_EXPR: fputs ("\n\tor", file); break; - case BIT_AND_EXPR: fputs ("\n\tand", file); break; case BIT_XOR_EXPR: fputs ("\n\txor", file); break; default: gcc_unreachable (); @@ -2169,6 +2368,70 @@ gen_cil_node (FILE *file, tree node) 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: @@ -2325,7 +2588,12 @@ gen_cil_node (FILE *file, tree node) break; case INDIRECT_REF: + case ARRAY_REF: compute_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); @@ -2351,11 +2619,10 @@ gen_cil_node (FILE *file, tree node) gen_cil_node (file, op); - if (TREE_CODE (node) == NOP_EXPR && INTEGRAL_TYPE_P (out_type)) + if (TREE_CODE (node) == NOP_EXPR + && INTEGRAL_TYPE_P (out_type) + && INTEGRAL_TYPE_P (in_type)) { - gcc_assert (INTEGRAL_TYPE_P (in_type) - || TREE_CODE (in_type) == POINTER_TYPE); - if (TYPE_PRECISION (out_type) > TYPE_PRECISION (in_type)) { tree tmp_type = TYPE_UNSIGNED (in_type) @@ -2368,7 +2635,11 @@ gen_cil_node (FILE *file, tree node) else gen_integral_conv (file, out_type, in_type); } - else + /* 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); @@ -2491,17 +2762,43 @@ gen_cil_node (FILE *file, tree node) mark_referenced_type (TREE_TYPE (node)); if (!DECL_FILE_SCOPE_P (node)) - fputs ("\n\tldloc\t", file); + { + 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))) + { + fputs ("\n\tldobj\t", file); + dump_type (file, TREE_TYPE (node), true); + } + 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); fputs (" ", file); if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (node)) fputs ("[ExternalAssembly]ExternalAssembly::", file); + dump_decl_name (file, node); } - dump_decl_name (file, node); stack_push (1); break; @@ -2543,6 +2840,8 @@ gen_cil_node (FILE *file, tree node) gcc_assert (! DECL_BIT_FIELD (fld)); compute_addr_expr (file, obj); + if (TREE_THIS_VOLATILE (fld)) + fputs ("\n\tvolatile.", file); fputs ("\n\tldfld\t", file); dump_type (file, fld_type, true); fputs (" ", file); @@ -2641,9 +2940,13 @@ gen_cil_modify_expr (FILE *file, tree node) break; case INDIRECT_REF: + case ARRAY_REF: compute_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))) { gcc_assert (AGGREGATE_TYPE_P (TREE_TYPE (rhs))); @@ -2661,21 +2964,52 @@ gen_cil_modify_expr (FILE *file, tree node) case VAR_DECL: mark_referenced_type (TREE_TYPE (lhs)); - gen_cil_node (file, rhs); if (!DECL_FILE_SCOPE_P (lhs)) - fputs ("\n\tstloc\t", file); + { + 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 ldind or ldobj */ + fputs ("\n\tvolatile.", file); + if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))) + { + fputs ("\n\tstobj\t", file); + dump_type (file, TREE_TYPE (lhs), true); + } + 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); fputs (" ", file); if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (lhs)) fputs ("[ExternalAssembly]ExternalAssembly::", file); + dump_decl_name (file, lhs); + stack_pop (1); } - dump_decl_name (file, lhs); - - stack_pop (1); break; case PARM_DECL: @@ -2698,6 +3032,8 @@ gen_cil_modify_expr (FILE *file, tree node) compute_addr_expr (file, obj); gen_cil_node (file, rhs); mark_referenced_type (obj_type); + if (TREE_THIS_VOLATILE (fld)) + fputs ("\n\tvolatile.", file); fputs ("\n\tstfld\t", file); dump_type (file, fld_type, true); fputs (" ", file); @@ -2869,17 +3205,72 @@ append_coded_type (char *str, tree type, return str; } +/* Compute and return a compact identifier from identifier STR of size LEN. + Memory is allocated for the compact identifier. + Store the length of the compact identifier in COMPACT_LEN. */ + static char * -get_md5 (const char *str, size_t len, size_t *md5_len) +get_compact_identifier (const char *str, size_t len, size_t *compact_len) { - char *md5_str; + char *compact_str; + size_t i; + unsigned char buffer[COMPACT_ID_LENGTH / 2]; + + gcc_assert (COMPACT_ID_LENGTH % 2 == 0); + + /* If the string is shorter than the length of compact strings, + then return it unchanged. */ + if (len <= COMPACT_ID_LENGTH) + { + compact_str = (char *)xmalloc (len); + memcpy (compact_str, str, len); + + *compact_len = len; + return compact_str; + } + + /* Fill the buffer */ + memset (buffer, 0, COMPACT_ID_LENGTH / 2); + for (i=0; i < len; ++i) + { + int j = 0; + unsigned char c = str[i]; + + while (true) + { + unsigned char tmp_c; + + /* Modify a position in buffer */ + buffer[(i + j) % (COMPACT_ID_LENGTH / 2)] ^= c; + + if (j == COMPACT_ID_LENGTH / 2) + break; + + /* Rotate c 1-bit right */ + tmp_c = c >> 1; + tmp_c |= (c & 1) << 7; + c = tmp_c; + + ++j; + } + } + + /* Build the compact string */ + compact_str = (char *)xmalloc (COMPACT_ID_LENGTH); + for (i=0; i < COMPACT_ID_LENGTH / 2; ++i) + { + unsigned char c1, c2; - /* TODO: unimplemented */ - *md5_len = len; - md5_str = (char *)xmalloc (len); - memcpy (md5_str, str, len); + c1 = buffer[i] & 0xf; + c2 = buffer[i] >> 4; + + compact_str[i * 2] = c1 + ((c1 < 10) ? '0' : 'a' - 10); + compact_str[i * 2 + 1] = c2 + ((c2 < 10) ? '0' : 'a' - 10); + } - return md5_str; + /* Return the compact string and its length */ + *compact_len = COMPACT_ID_LENGTH; + return compact_str; } static tree @@ -2954,7 +3345,7 @@ make_valuetype_identifier (tree t) } } - vt_name = get_md5 (tmp_name, tmp_name_len, &vt_name_len); + vt_name = get_compact_identifier (tmp_name, tmp_name_len, &vt_name_len); free (tmp_name); ident = get_identifier_with_length (vt_name, vt_name_len); @@ -3023,9 +3414,10 @@ print_valuetype_decl (FILE *file, tree t) { fputs ("\t.field public static literal ", file); dump_type (file, t, false); - fputs (" ", file); - dump_decl_name (file, TREE_PURPOSE (tmp)); - fprintf (file, " = %s(%ld)\n", + 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); } @@ -3120,18 +3512,16 @@ print_string_decl (FILE *file, tree t) } fputs ("\"\n", file); - fprintf (file, ".data 'DataStr%lu' = bytearray(", - (unsigned long)TREE_STRING_POINTER (t)); + fprintf (file, ".data 'DataStr%u' = bytearray(", get_string_cst_id (t)); for (i=0; i < len; ++i) - fprintf (file, "%02x ", str[i]); + fprintf (file, "%02x ", (unsigned char)str[i]); fputs (")\n", file); fputs (".field private static ", file); dump_type (file, TREE_TYPE (t), true); fputs (" ", file); dump_string_name (file, t); - fprintf (file, " at 'DataStr%lu'\n", - (unsigned long)TREE_STRING_POINTER (t)); + fprintf (file, " at 'DataStr%u'\n", get_string_cst_id (t)); } static void @@ -3189,10 +3579,106 @@ gen_start_function (FILE *stream) "\n\n", stream); } + +/* This function is mostly a copy of the last part of 'gen_cil'. */ +static void +gen_cil_vcg(FILE* vcg_stream) +{ + block_stmt_iterator bsi; + 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", + lang_hooks.decl_printable_name (current_function_decl, 1)); + 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 (BASIC_BLOCK (ENTRY_BLOCK))->index); + + FOR_EACH_BB (bb) + { + tree stmt = NULL_TREE; + + 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); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + if (TARGET_EMIT_GIMPLE_COMMENTS) + { + fprintf (vcg_stream, "\n\t [ "); + print_generic_expr (vcg_stream, stmt, 0); + fprintf (vcg_stream, " ]"); + } + gcc_assert (stack == 0); + + if (TREE_CODE (stmt) != NOP_EXPR + || TREE_CODE (TREE_OPERAND (stmt, 0)) != INTEGER_CST) + gen_cil_node (vcg_stream, stmt); + + if (TREE_CODE (stmt) == CALL_EXPR) + { + tree fun_expr = TREE_OPERAND (stmt, 0); + tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr)); + + if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE) + { + fputs ("\n\tpop", vcg_stream); + stack_pop (1); + } + } + } + + if ((!stmt || (TREE_CODE (stmt) != COND_EXPR)) && single_succ_p (bb)) + { + basic_block succ = single_succ (bb); + + /* The last part of the test (succ != bb->next_bb) is a HACK. It + avoids generating a branch to the successor in case of a + fallthrough. To be fixed when we have a proper layout of basic + blocks. Note that branches from COND_EXPR are still generated, + even to a fallthrough. */ + if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb)) + { + tree label = tree_block_label (succ); + fputs ("\n\tbr\t", vcg_stream); + dump_label_name (vcg_stream, label); + gcc_assert (stack == 0); + } + } + 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 + fprintf (vcg_stream, "edge: { "); + if (e->flags & EDGE_LOOP_EXIT) + fprintf (vcg_stream, "color: blue label:\"loop_exit\""); + + fprintf (vcg_stream, + " sourcename: \"%sBB%d\" targetname: \"%sBB%d\" }\n", + fun_name, bb->index, fun_name, e->dest->index); + } + } + fprintf (vcg_stream, "}\n"); +} + + static void gen_cil_1 (FILE *stream) { - basic_block bb; block_stmt_iterator bsi; bool varargs = FALSE; tree args; @@ -3323,8 +3809,9 @@ gen_cil_1 (FILE *stream) } fputs (") cil managed" - "\n{" - "\n\t.locals init (", stream); + "\n{", stream); + + fputs ("\n\t.locals (", stream); { tree var, cell; bool first = true; @@ -3358,6 +3845,9 @@ gen_cil_1 (FILE *stream) FOR_EACH_BB (bb) { tree stmt = NULL_TREE; + + fprintf (stream, "\n\t/* Basic block frequency: %d */\n", bb->frequency * 100 / BB_FREQ_MAX); + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { stmt = bsi_stmt (bsi); @@ -3398,11 +3888,23 @@ gen_cil_1 (FILE *stream) if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb)) { tree label = tree_block_label (succ); - fputs ("\n\tbr ", stream); + fputs ("\n\tbr\t", stream); dump_label_name (stream, label); gcc_assert (stack == 0); } } + + { + fprintf (stream, "\n\t/* Edge probabilities: "); + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->succs) + { + dump_entry_label_name (stream, e->dest); + fprintf (stream, ": %d ", e->probability * 100 / REG_BR_PROB_BASE); + } + fprintf (stream, "*/"); + } } fprintf (stream, "\n\t.maxstack %d\n", max_stack); @@ -3415,6 +3917,7 @@ static void create_init_method (tree decl) { static int init_counter = 0; + struct function *current_cfun = cfun; tree init; char name[30]; tree fun_type; @@ -3433,7 +3936,12 @@ create_init_method (tree decl) DECL_IGNORED_P (result) = 1; DECL_RESULT (fun_decl) = result; + /* Allocate memory for the function structure. The call to + allocate_struct_function clobbers CFUN, so we need to restore + it afterward. */ allocate_struct_function (fun_decl); + DECL_SOURCE_LOCATION (fun_decl) = DECL_SOURCE_LOCATION (decl); + cfun->function_end_locus = DECL_SOURCE_LOCATION (decl); TREE_STATIC (fun_decl) = 1; @@ -3451,15 +3959,16 @@ create_init_method (tree decl) init = DECL_INITIAL (decl); DECL_INITIAL (decl) = NULL_TREE; - DECL_SOURCE_LOCATION (fun_decl) = EXPR_LOCATION (init); - - expand_init_to_stmt_list (decl, init, &init_expr, false); + expand_init_to_stmt_list (decl, init, &init_expr); DECL_SAVED_TREE (fun_decl) = init_expr; gimplify_function_tree (fun_decl); tree_lowering_passes (fun_decl); tree_rest_of_compilation (fun_decl); + + /* Restore the current function */ + cfun = current_cfun; } void @@ -3514,6 +4023,15 @@ gen_cil_init (void) referenced_string_ptrs = pointer_set_create (); referenced_pinvoke = pointer_set_create (); VARRAY_TREE_INIT (pending_ctors, 32, "pending ctors"); + + /* Allocate hash table for pointer ids */ + pointer_id_htable = htab_create (256, + pointer_id_data_hash, + pointer_id_data_eq, + free); + + if (TARGET_EMIT_VCG) + fprintf (stdout, "graph: {\ndisplay_edge_labels: yes\n"); } void @@ -3635,6 +4153,12 @@ gen_cil_fini (void) it = pointer_set_next (referenced_pinvoke, it); } pointer_set_destroy (referenced_pinvoke); + + /* Delete hash table for pointer ids */ + htab_delete (pointer_id_htable); + + if (TARGET_EMIT_VCG) + fprintf (stdout, "}\n"); } static bool @@ -3647,6 +4171,10 @@ static unsigned int gen_cil (void) { gen_cil_1 (asm_out_file); + + if (TARGET_EMIT_VCG) + gen_cil_vcg(stdout); + return 0; } diff --git a/gcc/config/cil32/tree-simp-cil.c b/gcc/config/cil32/tree-simp-cil.c index d8f8aa26994..cb97315b525 100644 --- a/gcc/config/cil32/tree-simp-cil.c +++ b/gcc/config/cil32/tree-simp-cil.c @@ -73,6 +73,9 @@ Roberto Costa */ -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 SWITCH_EXPR, when it is not profitable to have a switch table (heuristic decision is based on case density). CIL emission pass (gen_cil) always emits a SWITCH_EXPR to a @@ -101,11 +104,15 @@ Roberto Costa */ however, a previous expansion may trigger further optimizations (since there is no similar construct in CIL bytecodes). - *) Expansion of ARRAY_REF nodes. + *) 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. @@ -136,11 +143,20 @@ Roberto Costa */ 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_BUILTIN_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. + *) 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, @@ -156,20 +172,26 @@ Roberto Costa */ 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 bool is_copy_required (tree); static bool mostly_zeros_p (tree); static bool all_zeros_p (tree); +static void simp_cond_stmt (block_stmt_iterator, tree); static void simp_switch (block_stmt_iterator *, tree *); static void simp_trivial_switch (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_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_bitfield (block_stmt_iterator *, tree *, tree, unsigned int, unsigned int, unsigned int, HOST_WIDEST_INT, bool); @@ -184,6 +206,13 @@ static void simp_vars (void); static unsigned int simp_cil (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 tree res_var; /* Return the integer type with size BITS bits. @@ -242,6 +271,7 @@ is_copy_required (tree node) case VAR_DECL: case PARM_DECL: return FALSE; + default: return TRUE; } @@ -267,6 +297,14 @@ simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr) { case COND_EXPR: simp_cil_node (bsi, &COND_EXPR_COND (node)); + if (bsi_stmt (*bsi) == node) + simp_cond_stmt (*bsi, node); + else + { + simp_cil_node (bsi, &COND_EXPR_THEN (node)); + simp_cil_node (bsi, &COND_EXPR_ELSE (node)); + simp_cond_expr (bsi, node_ptr); + } break; case SWITCH_EXPR: @@ -361,10 +399,39 @@ simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr) break; case ADDR_EXPR: - simp_cil_node (bsi, &TREE_OPERAND (node, 0)); - if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0))) - && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR) - split_use (*bsi, &TREE_OPERAND (node, 0), false); + 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: @@ -407,22 +474,33 @@ simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr) simp_cil_node (bsi, &TMR_BASE (node)); simp_cil_node (bsi, &TMR_INDEX (node)); simp_target_mem_ref (bsi, node_ptr); - node = *node_ptr; - gcc_assert (TREE_CODE (node) == INDIRECT_REF); - if (AGGREGATE_TYPE_P (TREE_TYPE (node)) - && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR) - split_use (*bsi, &TREE_OPERAND (node, 0), false); + /* The current node may require further simplification */ + simp_cil_node (bsi, node_ptr); break; case ARRAY_REF: - simp_cil_node (bsi, &TREE_OPERAND (node, 0)); - simp_cil_node (bsi, &TREE_OPERAND (node, 1)); - simp_array_ref (bsi, node_ptr); - node = *node_ptr; - gcc_assert (TREE_CODE (node) == INDIRECT_REF); - if (AGGREGATE_TYPE_P (TREE_TYPE (node)) - && TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR) - split_use (*bsi, &TREE_OPERAND (node, 0), false); + { + 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: @@ -456,12 +534,6 @@ simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr) break; case MAX_EXPR: - simp_cil_node (bsi, &TREE_OPERAND (node, 0)); - simp_cil_node (bsi, &TREE_OPERAND (node, 1)); - if (TARGET_EXPAND_MINMAX) - simp_min_max (bsi, node_ptr); - break; - case MIN_EXPR: simp_cil_node (bsi, &TREE_OPERAND (node, 0)); simp_cil_node (bsi, &TREE_OPERAND (node, 1)); @@ -474,6 +546,63 @@ simp_cil_node (block_stmt_iterator *bsi, tree *node_ptr) } } +/* 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; + tree cond_type; + + /* The condition targets are lowered in gimplify.c, we should never have + COND_EXPR with 'then' or 'else' operands that aren't GOTO_EXPRs. */ + gcc_assert (TREE_CODE (node) == COND_EXPR + && TREE_CODE (COND_EXPR_THEN (node)) == GOTO_EXPR + && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR); + gcc_assert (bsi_stmt (bsi) == node); + + cond_expr = COND_EXPR_COND (node); + then_expr = COND_EXPR_THEN (node); + cond_code = TREE_CODE (cond_expr); + + /* Do something only for a set of handled conditions */ + if (cond_code != LE_EXPR + && cond_code != LT_EXPR + && cond_code != GE_EXPR + && cond_code != GT_EXPR + && cond_code != EQ_EXPR + && cond_code != NE_EXPR) + return; + + cond_type = TREE_TYPE (TREE_OPERAND (cond_expr, 0)); + if ((INTEGRAL_TYPE_P (cond_type) || POINTER_TYPE_P (cond_type)) + && label_to_block (GOTO_DESTINATION (then_expr)) == bb->next_bb) + { + enum tree_code rev_code = invert_tree_comparison (cond_code, false); + edge e; + + gcc_assert (rev_code != ERROR_MARK); + + /* 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); + } +} + /* Expand the SWITCH_EXPR pointed by NODE_PTR by inserting compare trees. The expansion occurs only if heuristics say it is profitable; the current heuristic is based on case label @@ -514,7 +643,10 @@ simp_switch (block_stmt_iterator *bsi, tree *node_ptr) /* Switches made of one case are always separately (they are always transformed into if ... then ... else ... */ if (vec_len == 2) - simp_trivial_switch (bsi, node_ptr); + { + simp_trivial_switch (bsi, node_ptr); + return; + } /* Compute range of cases */ for (i = 0; i < vec_len - 1; ++i) @@ -709,6 +841,7 @@ simp_switch (block_stmt_iterator *bsi, tree *node_ptr) tree elt = TREE_VEC_ELT (vec, vec_len - 1); basic_block target_bb = label_to_block (CASE_LABEL (elt)); edge e = make_edge (bb2, target_bb, 0); + tree new_elt; if (!e) e = find_edge (bb2, target_bb); @@ -716,7 +849,12 @@ simp_switch (block_stmt_iterator *bsi, tree *node_ptr) e->count = bb2->count; e->probability = REG_BR_PROB_BASE; - TREE_VEC_ELT (vec2, vec_len - sw1_last - 2) = elt; + /* Duplicate this case label expression, since it is used + in the first switch. */ + new_elt = build3 (CASE_LABEL_EXPR, TREE_TYPE (elt), + CASE_LOW (elt), CASE_HIGH (elt), CASE_LABEL (elt)); + + TREE_VEC_ELT (vec2, vec_len - sw1_last - 2) = new_elt; } /* Update out-edges of original switch basic block */ @@ -742,7 +880,7 @@ simp_switch (block_stmt_iterator *bsi, tree *node_ptr) } /* Expand the SWITCH_EXPR pointed by NODE_PTR, composed of just - one case, into a COND_EXPR (or GOTO_EXPR). + one case, into a COND_EXPR (or fallthru). The expansion always occurs, since generally profitable. BSI points to the iterator of the statement that contains *NODE_PTR (in order to allow insertion of new statements). @@ -771,29 +909,24 @@ simp_trivial_switch (block_stmt_iterator *bsi, tree *node_ptr) /* Check for the easiest situation: the one case and default go to the same basic block. - If so, SWITCH_EXPR is replaced by a GOTO_EXPR. */ + If so, SWITCH_EXPR is replaced by a fallthru. */ if (single_succ_p (bb_sw)) { - tree goto_stmt; edge e; gcc_assert (bb_case == label_to_block (CASE_LABEL (TREE_VEC_ELT (SWITCH_LABELS (node), 1)))); - /* Build the GOTO_EXPR */ - goto_stmt = build1 (GOTO_EXPR, void_type_node, CASE_LABEL (one_case)); - SET_EXPR_LOCATION (goto_stmt, locus); - /* Update CFG */ e = find_edge (bb_sw, bb_case); e->flags |= EDGE_FALLTHRU; - /* Replace the original switch with the GOTO_EXPR */ - *node_ptr = goto_stmt; - set_bb_for_stmt (goto_stmt, bb_sw); + /* Remove the original switch */ + bsi_remove (bsi, true); /* Update the basic block statement iterator */ *bsi = bsi_last (bb_sw); + *node_ptr = bsi_stmt (*bsi); } /* Check whether the one case is not a range. @@ -922,27 +1055,67 @@ static void simp_builtin_call (block_stmt_iterator bsi, tree node) { tree fun_expr = TREE_OPERAND (node, 0); + tree dfun = TREE_OPERAND (fun_expr, 0); gcc_assert (TREE_CODE (node) == CALL_EXPR); gcc_assert (TREE_CODE (fun_expr) == ADDR_EXPR); - gcc_assert (TREE_CODE (TREE_OPERAND (fun_expr, 0)) == FUNCTION_DECL); - gcc_assert (DECL_BUILT_IN (TREE_OPERAND (fun_expr, 0))); + gcc_assert (TREE_CODE (dfun) == FUNCTION_DECL); + gcc_assert (DECL_BUILT_IN (dfun)); - switch (DECL_FUNCTION_CODE (TREE_OPERAND (fun_expr, 0))) + if (DECL_BUILT_IN_CLASS (dfun) == BUILT_IN_MD) { - case BUILT_IN_VA_COPY: - { - tree va_dest = TREE_VALUE (TREE_OPERAND (node, 1)); + switch (DECL_FUNCTION_CODE (dfun)) + { + case CIL32_BUILTIN_VA_ARG: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); - gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR); - if (TREE_CODE (TREE_OPERAND (va_dest, 0)) != VAR_DECL - || DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0))) - split_use (bsi, &TREE_OPERAND (va_dest, 0), true); - } - break; + gcc_assert (POINTER_TYPE_P (TREE_TYPE (va)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va))) + == va_list_type_node); - default: - ; + if (TREE_CODE (va) != ADDR_EXPR && TREE_CODE (va) != VAR_DECL) + split_use (bsi, &TREE_VALUE (TREE_OPERAND (node, 1)), true); + } + break; + + default: + ; + } + } + else + { + switch (DECL_FUNCTION_CODE (dfun)) + { + case BUILT_IN_VA_START: + case BUILT_IN_VA_END: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); + + gcc_assert (POINTER_TYPE_P (TREE_TYPE (va)) + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (va))) + == va_list_type_node); + + if (TREE_CODE (va) != ADDR_EXPR && TREE_CODE (va) != VAR_DECL) + split_use (bsi, &TREE_VALUE (TREE_OPERAND (node, 1)), true); + } + break; + + case BUILT_IN_VA_COPY: + { + tree va_dest = TREE_VALUE (TREE_OPERAND (node, 1)); + + gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR); + if (TREE_CODE (TREE_OPERAND (va_dest, 0)) != VAR_DECL + || DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0))) + split_use (bsi, &TREE_OPERAND (va_dest, 0), true); + recompute_tree_invariant_for_addr_expr (va_dest); + } + break; + + default: + ; + } } } @@ -1131,6 +1304,108 @@ simp_min_max (block_stmt_iterator *bsi, tree *node_ptr) *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; + 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 = build2 (MODIFY_EXPR, TREE_TYPE (then_op), 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 = build2 (MODIFY_EXPR, TREE_TYPE (else_op), 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; + 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; + unchecked_make_edge (bb_comp, bb_then, EDGE_TRUE_VALUE); + make_single_succ_edge (bb_then, bb_sel, EDGE_FALLTHRU); + unchecked_make_edge (bb_comp, bb_else, EDGE_FALSE_VALUE); + make_single_succ_edge (bb_else, bb_sel, EDGE_FALLTHRU); + + /* 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 = build2 (MODIFY_EXPR, TREE_TYPE (then_op), 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 = build2 (MODIFY_EXPR, TREE_TYPE (else_op), 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); +} + /* 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 @@ -1193,10 +1468,10 @@ simp_rotate (block_stmt_iterator *bsi, tree *node_ptr) /* Build second shift */ t2 = fold_build2 (left ? RSHIFT_EXPR : LSHIFT_EXPR, op0_uns_type, op0, - build2 (MINUS_EXPR, unsigned_intSI_type_node, - fold_convert (unsigned_intSI_type_node, - TYPE_SIZE (TREE_TYPE (op0))), - op1)); + 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); @@ -1214,7 +1489,7 @@ simp_rotate (block_stmt_iterator *bsi, tree *node_ptr) /* Given the LSHIFT_EXPR or RSHIFT_EXPR in NODE with the second operand of an integer type bigger than 32 bits, convert such operand to a 32-bit type. - BSI points to the iterator of the statement that contains *NODE_PTR + 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. */ @@ -1299,8 +1574,42 @@ simp_target_mem_ref (block_stmt_iterator *bsi, tree *node_ptr) *node_ptr = force_gimple_operand_bsi (bsi, t1, FALSE, NULL); } -/* Expand the ARRAY_REF pointed by NODE_PTR by inserting - the equivalent sums and multiplication. +/* 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 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); + *disp = fold_build2 (MULT_EXPR, long_integer_type_node, + fold_convert (long_integer_type_node, op1), + fold_convert (long_integer_type_node, + array_ref_element_size (node))); + 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. @@ -1312,88 +1621,39 @@ simp_array_ref (block_stmt_iterator *bsi, tree *node_ptr) { tree node = *node_ptr; location_t locus = EXPR_LOCATION (bsi_stmt (*bsi)); - tree base, index; - tree base_type; - tree t1, t2; - tree tmp_var, tmp_stmt; + tree array_start, array_disp; + tree ptr_type; + tree t1, t2, stmt; gcc_assert (TREE_CODE (node) == ARRAY_REF); - base = TREE_OPERAND (node, 0); - index = TREE_OPERAND (node, 1); + /* 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); - /* The type of base is a pointer, no longer an array! */ - base_type = build0 (POINTER_TYPE, TREE_TYPE (TREE_TYPE (base))); - layout_type (base_type); + /* Update addressable information */ + UPDATE_ADDRESSABLE (array_start); - /* Generate the equivalent gimplified expression */ + /* Build type pointer to the array element */ + ptr_type = build_pointer_type (TREE_TYPE (node)); - t1 = fold_convert (long_integer_type_node, index); - t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL); - gcc_assert (t1 && t1 != error_mark_node); - - t2 = fold_convert (long_integer_type_node, array_ref_element_size (node)); - t2 = force_gimple_operand_bsi (bsi, t2, TRUE, NULL); - gcc_assert (t2 && t2 != error_mark_node); - - if (TREE_CODE (t1) == INTEGER_CST - && (double_int_zero_p (TREE_INT_CST (t1)) - || double_int_one_p (TREE_INT_CST (t1)))) - { - if (double_int_one_p (TREE_INT_CST (t1))) - t1 = t2; - } - else if (TREE_CODE (t2) == INTEGER_CST - && (double_int_zero_p (TREE_INT_CST (t2)) - || double_int_one_p (TREE_INT_CST (t2)))) - { - if (double_int_zero_p (TREE_INT_CST (t2))) - t1 = t2; - } - else - { - tmp_var = create_tmp_var (long_integer_type_node, "cilsimp"); - tmp_stmt = build2 (MODIFY_EXPR, long_integer_type_node, - tmp_var, - fold_build2 (MULT_EXPR, long_integer_type_node, - t1, - t2)); - SET_EXPR_LOCATION (tmp_stmt, locus); - t1 = tmp_var; - bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); - } - gcc_assert (t1 && t1 != error_mark_node); - - tmp_var = create_tmp_var (base_type, "cilsimp"); - tmp_stmt = build2 (MODIFY_EXPR, base_type, - tmp_var, - build1 (ADDR_EXPR, base_type, base)); - gcc_assert (TREE_CODE (base) != CALL_EXPR); - SET_EXPR_LOCATION (tmp_stmt, locus); - t2 = tmp_var; - bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); + /* 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); + t2 = create_tmp_var (ptr_type, "cilsimp"); + stmt = build2 (MODIFY_EXPR, ptr_type, t2, t1); + SET_EXPR_LOCATION (stmt, locus); + bsi_insert_before (bsi, stmt, BSI_SAME_STMT); - if (TREE_CODE (t1) == INTEGER_CST - && double_int_zero_p (TREE_INT_CST (t1))) - { - t1 = t2; - } - else - { - tmp_var = create_tmp_var (base_type, "cilsimp"); - tmp_stmt = build2 (MODIFY_EXPR, base_type, - tmp_var, - build2 (PLUS_EXPR, base_type, - t2, - t1)); - SET_EXPR_LOCATION (tmp_stmt, locus); - t1 = tmp_var; - bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); - } - gcc_assert (t1 && t1 != error_mark_node); + /* Build the expression for the access to the array element */ + t1 = fold_build2 (PLUS_EXPR, ptr_type, + t2, + fold_convert (ptr_type, array_disp)); + t1 = force_gimple_operand_bsi (bsi, t1, TRUE, NULL); /* Update the current node */ - *node_ptr = build1 (INDIRECT_REF, TREE_TYPE (node), t1); + *node_ptr = t1; } /* Expand a bit-field reference by transforming it @@ -1418,18 +1678,21 @@ simp_bitfield (block_stmt_iterator *bsi, tree *node_ptr, { tree node = *node_ptr; location_t locus = EXPR_LOCATION (bsi_stmt (*bsi)); - tree new_type, obj_ptr_type; + tree new_type, new_type_ptr, obj_ptr_type; tree tmp_var, tmp_stmt; tree t; gcc_assert (cont_size >= bfld_size + bfld_off); + /* Set that the object being accessed is addressable */ + UPDATE_ADDRESSABLE (obj); + /* Build the type corresponding of a pointer to the object */ - obj_ptr_type = build0 (POINTER_TYPE, TREE_TYPE (obj)); - layout_type (obj_ptr_type); + obj_ptr_type = build_pointer_type (TREE_TYPE (obj)); - /* Build the new type for the equivalent access */ + /* Build the new type for the equivalent access (and a pointer type to it) */ new_type = get_integer_type (cont_size, uns); + new_type_ptr = build_pointer_type (new_type); /* Build the (gimplified) equivalent expression */ @@ -1441,6 +1704,13 @@ simp_bitfield (block_stmt_iterator *bsi, tree *node_ptr, SET_EXPR_LOCATION (tmp_stmt, locus); t = tmp_var; bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); + tmp_var = create_tmp_var (new_type_ptr, "cilsimp"); + tmp_stmt = build2 (MODIFY_EXPR, new_type_ptr, + tmp_var, + build1 (NOP_EXPR, new_type_ptr, t)); + SET_EXPR_LOCATION (tmp_stmt, locus); + t = tmp_var; + bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); if (off > 0) { @@ -1557,7 +1827,7 @@ simp_lhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr) tree fld_type, fld_off ; unsigned int cont_size, bfld_size, bfld_off; tree stmt = bsi_stmt (*bsi), rhs, addr; - tree new_type, obj_ptr_type; + tree new_type, new_type_ptr, obj_ptr_type; tree tmp_var, tmp_stmt; tree t; HOST_WIDEST_INT off; @@ -1568,6 +1838,9 @@ simp_lhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr) gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR && TREE_OPERAND (stmt, 0) == node); + /* Set that the object being accessed is addressable */ + UPDATE_ADDRESSABLE (obj); + /* Extract bit field layout */ fld_type = DECL_BIT_FIELD_TYPE (fld); fld_off = DECL_FIELD_OFFSET (fld); @@ -1576,12 +1849,12 @@ simp_lhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr) bfld_off = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld)) & (cont_size - 1); gcc_assert (cont_size >= TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node)))); - /* Build the new type for the equivalent access */ + /* Build the new type for the equivalent access (and a pointer type to it) */ new_type = get_integer_type (cont_size, true); + new_type_ptr = build_pointer_type (new_type); /* Build the type corresponding of a pointer to the object */ - obj_ptr_type = build0 (POINTER_TYPE, TREE_TYPE (obj)); - layout_type (obj_ptr_type); + obj_ptr_type = build_pointer_type (TREE_TYPE (obj)); /* Convert the original rhs into the new type */ gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 1)) == VAR_DECL); @@ -1634,6 +1907,13 @@ simp_lhs_bitfield_component_ref (block_stmt_iterator *bsi, tree *node_ptr) SET_EXPR_LOCATION (tmp_stmt, locus); t = tmp_var; bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); + tmp_var = create_tmp_var (new_type_ptr, "cilsimp"); + tmp_stmt = build2 (MODIFY_EXPR, new_type_ptr, + tmp_var, + build1 (NOP_EXPR, new_type_ptr, t)); + SET_EXPR_LOCATION (tmp_stmt, locus); + t = tmp_var; + bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); off = TREE_INT_CST_LOW (fld_off) + ((TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld)) @@ -1773,7 +2053,7 @@ pre_simp_init (block_stmt_iterator *bsi, tree node) gcc_assert (TREE_CODE (rhs) == CONSTRUCTOR || TREE_CODE (rhs) == STRING_CST); /* Expand the constructor into a separate statement list */ - expand_init_to_stmt_list (lhs, rhs, &stmt_list, FALSE); + expand_init_to_stmt_list (lhs, rhs, &stmt_list); gcc_assert (TREE_CODE (stmt_list) == STATEMENT_LIST); /* Gimplify the new statements and insert them */ @@ -1807,7 +2087,7 @@ pre_simp_init (block_stmt_iterator *bsi, tree node) } /* Remove the old statement */ - bsi_remove (bsi, false); + bsi_remove (bsi, true); /* Update the basic block statement iterator */ *bsi = tmp_bsi; @@ -1888,19 +2168,17 @@ all_zeros_p (tree exp) STMT_LIST may be NULL; in this case a statement list is allocated. */ -void -expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) +static void +expand_init_to_stmt_list1 (tree decl, tree init, + tree *stmt_list1, bool cleared, + tree *stmt_list2, void *le_image, void *be_image) { tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl)); unsigned int size = TREE_INT_CST_LOW (decl_size); bool need_to_clear = FALSE; - if (! *stmt_list) - { - *stmt_list = alloc_stmt_list (); - } - - gcc_assert (TREE_CODE (*stmt_list) == STATEMENT_LIST); + gcc_assert (TREE_CODE (*stmt_list1) == STATEMENT_LIST); + gcc_assert (TREE_CODE (*stmt_list2) == STATEMENT_LIST); if (TREE_CODE (init) == CONST_DECL) { @@ -1919,7 +2197,7 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) t = implicit_built_in_decls[BUILT_IN_MEMSET]; t = build_function_call_expr (t, args); - append_to_statement_list (t, stmt_list); + append_to_statement_list (t, stmt_list1); return; } @@ -1944,7 +2222,10 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) t = implicit_built_in_decls[BUILT_IN_MEMCPY]; t = build_function_call_expr (t, args); - append_to_statement_list (t, stmt_list); + append_to_statement_list (t, stmt_list1); + + memcpy(le_image, TREE_STRING_POINTER (init), TREE_INT_CST_LOW (decl_size)); + memcpy(be_image, TREE_STRING_POINTER (init), TREE_INT_CST_LOW (decl_size)); } break; @@ -1994,7 +2275,7 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) t = implicit_built_in_decls[BUILT_IN_MEMSET]; t = build_function_call_expr (t, args); - append_to_statement_list (t, stmt_list); + append_to_statement_list (t, stmt_list1); cleared = TRUE; } @@ -2014,10 +2295,27 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) if (cleared && initializer_zerop (value)) continue; - ltarget = build3 (COMPONENT_REF, TREE_TYPE (field), decl, - field, NULL); + ltarget = build3 (COMPONENT_REF, TREE_TYPE (field), decl, field, NULL); - expand_init_to_stmt_list (ltarget, value, stmt_list, cleared); + if (le_image != NULL && !DECL_BIT_FIELD(field)) + { + unsigned HOST_WIDE_INT offset = TREE_INT_CST_LOW (DECL_FIELD_OFFSET(field)); + unsigned HOST_WIDE_INT bit_offset = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET(field)); + gcc_assert(bit_offset%BITS_PER_UNIT==0); + offset += bit_offset/BITS_PER_UNIT; + + expand_init_to_stmt_list1 (ltarget, value, + stmt_list1, cleared, + stmt_list2, + (void*)((intptr_t)le_image+offset), + (void*)((intptr_t)be_image+offset)); + } + else + { + expand_init_to_stmt_list1 (ltarget, value, + stmt_list1, cleared, + stmt_list2, NULL, NULL); + } } } break; @@ -2113,7 +2411,7 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) t = implicit_built_in_decls[BUILT_IN_MEMSET]; t = build_function_call_expr (t, args); - append_to_statement_list (t, stmt_list); + append_to_statement_list (t, stmt_list1); cleared = TRUE; } @@ -2124,6 +2422,7 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, index, value) { tree t; + tree elsize; if (initializer_zerop (value)) continue; @@ -2139,7 +2438,28 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) TYPE_MIN_VALUE (domain))); t = build4 (ARRAY_REF, elttype, decl, index, NULL, NULL); - expand_init_to_stmt_list (t, value, stmt_list, cleared); + + elsize = array_ref_element_size (t); + + if (le_image != NULL + && TREE_CODE (index) == INTEGER_CST + && TREE_CODE (elsize) == INTEGER_CST) + { + unsigned HOST_WIDE_INT offset = TREE_INT_CST_LOW(index); + offset *= TREE_INT_CST_LOW(elsize); + + expand_init_to_stmt_list1 (t, value, + stmt_list1, cleared, + stmt_list2, + (void*)((intptr_t)le_image+offset), + (void*)((intptr_t)be_image+offset)); + } + else + { + expand_init_to_stmt_list1 (t, value, + stmt_list1, cleared, + stmt_list2, NULL, NULL); + } } } break; @@ -2156,14 +2476,154 @@ expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list, bool cleared) } break; + case INTEGER_CST: + { + int type_size = TREE_INT_CST_LOW (decl_size); + tree t = build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, init); + append_to_statement_list (t, stmt_list1); + + if (le_image != NULL) + { + unsigned int temp = TREE_INT_CST_LOW (init); + unsigned char b[4] = {((temp>> 0)&0xff), + ((temp>> 8)&0xff), + ((temp>>16)&0xff), + ((temp>>24)&0xff)}; + + gcc_assert (be_image != NULL); + switch (type_size) + { + case 1: + *(unsigned char*)le_image = b[0]; + *(unsigned char*)be_image = b[0]; + break; + + case 2: + *((unsigned char*)le_image+0) = b[0]; + *((unsigned char*)le_image+1) = b[1]; + *((unsigned char*)be_image+0) = b[1]; + *((unsigned char*)be_image+1) = b[0]; + break; + + case 4: + *((unsigned char*)le_image+0) = b[0]; + *((unsigned char*)le_image+1) = b[1]; + *((unsigned char*)le_image+2) = b[2]; + *((unsigned char*)le_image+3) = b[3]; + *((unsigned char*)be_image+0) = b[3]; + *((unsigned char*)be_image+1) = b[2]; + *((unsigned char*)be_image+2) = b[1]; + *((unsigned char*)be_image+3) = b[0]; + break; + +#if 0 + case 8: + /*...*/ + break; +#endif + + default: + append_to_statement_list (t, stmt_list2); + break; + } + } + else + { + append_to_statement_list (t, stmt_list2); + } + } + break; + + case REAL_CST: + /* Missing optimization, fall through for now */ default: - append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (decl), - decl, init), - stmt_list); + { + tree t = build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, init); + append_to_statement_list (t, stmt_list1); + append_to_statement_list (t, stmt_list2); + } break; } } +static int +statement_list_num_instr (tree stmt_list) +{ + int i = 0; + tree_stmt_iterator it = tsi_start (stmt_list); + while (!tsi_end_p (it)) + { + ++i; + tsi_next (&it); + } + return i; +} + +void +expand_init_to_stmt_list (tree decl, tree init, tree *stmt_list) +{ + unsigned int size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (decl))); + void* le_image = alloca (size); + void* be_image = alloca (size); + tree stmt_list1 = alloc_stmt_list (); + int num_list1; + tree stmt_list2 = alloc_stmt_list (); + int num_list2; + bool le_eq_be; + + memset (le_image, 0, size); + memset (be_image, 0, size); + + expand_init_to_stmt_list1 (decl, init, + &stmt_list1, FALSE, + &stmt_list2, le_image, be_image); + + le_eq_be = (memcmp (le_image, be_image, size) == 0); + num_list1 = statement_list_num_instr (stmt_list1); + num_list2 = statement_list_num_instr (stmt_list2); + + + /* Decide what to do */ + if ((num_list2 + 2) < num_list1) + { + tree mem_cpy; + tree args; + tree from_ptr; + tree to_ptr = build_fold_addr_expr (decl); + + tree sconst = build_string_literal (size, le_image); + + if (le_eq_be) + { + from_ptr = sconst; + } + else + { + tree sconst2 = build_string_literal (size, be_image); + + gcc_assert (TREE_TYPE (sconst) == TREE_TYPE (sconst2)); + + from_ptr = fold_build3 (COND_EXPR, + TREE_TYPE (sconst), + build_function_call_expr (cil32_is_LE_decl, NULL_TREE), + sconst, + sconst2); + } + + args = tree_cons (NULL, size_int (size), NULL); + args = tree_cons (NULL, from_ptr, args); + args = tree_cons (NULL, to_ptr, args); + + mem_cpy = build_function_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], + args); + + append_to_statement_list (mem_cpy, stmt_list); + append_to_statement_list (stmt_list2, stmt_list); + } + else + append_to_statement_list (stmt_list1, stmt_list); +} + /* Rename a single variable using the specified suffix */ static void @@ -2186,7 +2646,8 @@ rename_var (tree var, const char* suffix, unsigned long index) static void simp_vars (void) { - block_stmt_iterator bsi = bsi_start (ENTRY_BLOCK_PTR); + basic_block new_bb = 0; + block_stmt_iterator bsi; tree *p = &cfun->unexpanded_var_list; unsigned long num_loc = 0; @@ -2197,7 +2658,7 @@ simp_vars (void) if (TREE_STATIC (var) && DECL_CONTEXT (var) != 0) { - rename_var (var, "?fs", (unsigned long)var); + rename_var (var, "?fs", DECL_UID (var)); DECL_CONTEXT (var) = 0; } @@ -2213,10 +2674,27 @@ simp_vars (void) if (!TREE_STATIC (var) && init && init != error_mark_node) { - /* DECL_INITIAL (var) = NULL_TREE; */ - bsi_insert_after (&bsi, - build2 (INIT_EXPR, TREE_TYPE (var), var, init), - BSI_NEW_STMT); + /* 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, + build2 (MODIFY_EXPR, TREE_TYPE (var), var, init), + BSI_SAME_STMT); } } } @@ -2271,6 +2749,24 @@ simp_cil (void) 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 (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); + } + } } #if 0 diff --git a/gcc/config/cil32/tree-simp-cil.h b/gcc/config/cil32/tree-simp-cil.h index 6f4ea4fc502..18a3d36ec67 100644 --- a/gcc/config/cil32/tree-simp-cil.h +++ b/gcc/config/cil32/tree-simp-cil.h @@ -33,7 +33,7 @@ Roberto Costa */ #include "tree.h" -extern void expand_init_to_stmt_list (tree, tree, tree *, bool); +extern void expand_init_to_stmt_list (tree, tree, tree *); extern tree get_integer_type (int, bool); #endif /* TREE_SIMP_CIL_H */ -- cgit v1.2.3