aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Costa <roberto.costa@st.com>2006-11-10 09:56:10 +0000
committerRoberto Costa <roberto.costa@st.com>2006-11-10 09:56:10 +0000
commit3fda9d86d679e905aff77fbb5f18fd8c117d4ba8 (patch)
treec3f7a9140c3ce1513405a59bfac443470bf07cdd
parent5efb6d8cfa3b70289d30571f36103bde0f31d799 (diff)
Merge from ST 20061110
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/st/cli@118651 138bc75d-0d04-0410-961f-82ee72b054a4
-rwxr-xr-xcil32-crosstool.sh45
-rwxr-xr-xconfigure2
-rw-r--r--configure.in2
-rw-r--r--gcc/config/cil32/cil32.c56
-rw-r--r--gcc/config/cil32/cil32.h7
-rw-r--r--gcc/config/cil32/cil32.opt8
-rw-r--r--gcc/config/cil32/gcc4net.cs21
-rw-r--r--gcc/config/cil32/gen-cil.c784
-rw-r--r--gcc/config/cil32/tree-simp-cil.c826
-rw-r--r--gcc/config/cil32/tree-simp-cil.h2
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 <roberto.costa@st.com> */
/* 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("<Module>");
+
+ Type type = assembly.GetType("<Module>");
+ 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 <roberto.costa@st.com> */
(! 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, "<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. */
@@ -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 <roberto.costa@st.com> */
-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 <roberto.costa@st.com> */
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 <roberto.costa@st.com> */
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 <roberto.costa@st.com> */
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 <roberto.costa@st.com> */
#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 */