aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog42
-rw-r--r--gcc/Makefile.in5
-rw-r--r--gcc/c-common.c23
-rw-r--r--gcc/optabs.c86
-rw-r--r--gcc/optabs.h4
-rw-r--r--gcc/print-tree.c2
-rw-r--r--gcc/regclass.c11
-rw-r--r--gcc/regs.h4
-rw-r--r--gcc/stor-layout.c51
-rw-r--r--gcc/tree-cfg.c73
-rw-r--r--gcc/tree-complex.c603
-rw-r--r--gcc/tree-flow.h7
-rw-r--r--gcc/tree-nested.c10
-rw-r--r--gcc/tree-optimize.c2
-rw-r--r--gcc/tree-pass.h3
-rw-r--r--gcc/tree.c68
-rw-r--r--gcc/tree.def3
-rw-r--r--gcc/tree.h3
18 files changed, 827 insertions, 173 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 02ba1037f21..cdd99137bc8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,45 @@
+2004-07-22 Paolo Bonzini <bonzini@gnu.org>
+
+ * tree-cfg.c (gimplify_val): Move from tree-complex.c.
+ (gimplify_build1): Move from tree-complex.c do_unop.
+ (gimplify_build2): Move from tree-complex.c do_binop.
+ (gimplify_build3): New.
+ * tree-complex.c (gimplify_val, do_unop, do_binop): Remove.
+ Adjust throughout to call the functions above.
+ * tree-flow.h: Declare the functions above.
+ * tree-nested.c (gimplify_val): Rename to...
+ (tsi_gimplify_val): ... this.
+
+ * Makefile.in (tree_complex.o): Update dependencies.
+ (stor-layout.o): Depend on regs.h.
+ * c-common.c (handle_vector_size_attribute): Update for
+ vector types without corresponding vector modes.
+ * expr.c (expand_expr): Treat VECTOR_CST's like CONSTRUCTORS if
+ a corresponding vector mode is not available.
+ * print-tree.c (print_node): Print nunits for vector types
+ * regclass.c (have_regs_of_mode): New.
+ (init_reg_sets_1): Initialize it and use it instead
+ of allocatable_regs_of_mode.
+ * regs.h (have_regs_of_mode): Declare it.
+ * stor-layout.c (layout_type): Pick a mode for vector types.
+ * tree-complex.c (build_word_mode_vector_type, tree_vec_extract,
+ build_replicated_const, do_unop, do_binop, do_plus_minus,
+ do_negate, expand_vector_piecewise, expand_vector_parallel,
+ expand_vector_addition, expand_vector_operations_1,
+ expand_vector_operations, tree_lower_operations,
+ pass_lower_vector_ssa, pass_pre_expand): New.
+ (expand_complex_operations, pass_lower_complex): Remove.
+ * tree-optimize.c (init_tree_optimization_passes): Adjust
+ pass ordering for changes in tree-complex.c.
+ * tree-pass.h: Declare new passes.
+ * tree.c (finish_vector_type): Remove.
+ (make_vector_type): New.
+ (build_vector_type_for_mode, build_vector_type): Rewritten.
+ * tree.def (VECTOR_TYPE): Document where the number of
+ subparts is stored.
+ * tree.h (TYPE_VECTOR_SUBPARTS): Use TYPE_PRECISION field.
+ (make_vector): Remove declaration.
+
2004-07-21 Richard Henderson <rth@redhat.com>
* gimple-low.c (expand_var_p): Don't look at TREE_ADDRESSABLE,
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8706bae3c72..32bb1fe513e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1585,7 +1585,7 @@ print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H
$(GGC_H) langhooks.h real.h
stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(FLAGS_H) function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H) $(TARGET_H) \
- langhooks.h
+ langhooks.h $(REGS_H)
tree-alias-type.o: tree-alias-type.c tree-alias-type.h $(SYSTEM_H) $(CONFIG_H) \
$(GGC_H) $(TM_H) coretypes.h $(VARRAY_H)
tree-alias-ander.o: tree-alias-ander.c tree-alias-ander.h $(SYSTEM_H) \
@@ -1922,7 +1922,8 @@ tree-sra.o : tree-sra.c $(CONFIG_H) system.h errors.h $(TREE_H) $(RTL_H) \
langhooks.h tree-pass.h $(FLAGS_H) $(EXPR_H)
tree-complex.o : tree-complex.c $(CONFIG_H) system.h $(TREE_H) \
$(TM_H) $(TREE_FLOW_H) $(TREE_GIMPLE_H) tree-iterator.h tree-pass.h \
- $(FLAGS_H)
+ $(FLAGS_H) $(OPTABS_H) $(RTL_H) $(MACHMODE_H) $(EXPR_H) \
+ langhooks.h $(FLAGS_H) $(DIAGNOSTIC_H)
df.o : df.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
insn-config.h $(RECOG_H) function.h $(REGS_H) alloc-pool.h hard-reg-set.h \
$(BASIC_BLOCK_H) $(DF_H)
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 4d409222615..2f9e2e24e78 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -4783,7 +4783,7 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
bool *no_add_attrs)
{
unsigned HOST_WIDE_INT vecsize, nunits;
- enum machine_mode mode, orig_mode, new_mode;
+ enum machine_mode orig_mode;
tree type = *node, new_type, size;
*no_add_attrs = true;
@@ -4832,28 +4832,13 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
/* Calculate how many units fit in the vector. */
nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-
- /* Find a suitably sized vector. */
- new_mode = VOIDmode;
- for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
- ? MODE_VECTOR_INT
- : MODE_VECTOR_FLOAT);
- mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- if (vecsize == GET_MODE_SIZE (mode)
- && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
- {
- new_mode = mode;
- break;
- }
-
- if (new_mode == VOIDmode)
+ if (nunits & (nunits - 1))
{
- error ("no vector mode with the size and type specified could be found");
+ error ("number of components of the vector not a power of two");
return NULL_TREE;
}
- new_type = build_vector_type_for_mode (type, new_mode);
+ new_type = build_vector_type (type, nunits);
/* Build back pointers if needed. */
*node = reconstruct_complex_type (*node, new_type);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 2440a86dc94..1f013f37a60 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -628,6 +628,89 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1, rtx realr,
return 1;
}
+/* Return the optab used for computing the operation given by
+ the tree code, CODE. This function is not always usable (for
+ example, it cannot give complete results for multiplication
+ or division) but probably ought to be relied on more widely
+ throughout the expander. */
+optab
+optab_for_tree_code (enum tree_code code, tree type)
+{
+ bool trapv;
+ switch (code)
+ {
+ case BIT_AND_EXPR:
+ return and_optab;
+
+ case BIT_IOR_EXPR:
+ return ior_optab;
+
+ case BIT_NOT_EXPR:
+ return one_cmpl_optab;
+
+ case BIT_XOR_EXPR:
+ return xor_optab;
+
+ case TRUNC_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
+
+ case RDIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
+
+ case LSHIFT_EXPR:
+ return ashl_optab;
+
+ case RSHIFT_EXPR:
+ return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
+
+ case LROTATE_EXPR:
+ return rotl_optab;
+
+ case RROTATE_EXPR:
+ return rotr_optab;
+
+ case MAX_EXPR:
+ return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
+
+ case MIN_EXPR:
+ return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
+
+ default:
+ break;
+ }
+
+ trapv = flag_trapv && INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type);
+ switch (code)
+ {
+ case PLUS_EXPR:
+ return trapv ? addv_optab : add_optab;
+
+ case MINUS_EXPR:
+ return trapv ? subv_optab : sub_optab;
+
+ case MULT_EXPR:
+ return trapv ? smulv_optab : smul_optab;
+
+ case NEGATE_EXPR:
+ return trapv ? negv_optab : neg_optab;
+
+ case ABS_EXPR:
+ return trapv ? absv_optab : abs_optab;
+
+ default:
+ return NULL;
+ }
+}
+
+
/* Wrapper around expand_binop which takes an rtx code to specify
the operation to perform, not an optab pointer. All other
arguments are the same. */
@@ -2804,7 +2887,8 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
}
/* If there is no negate operation, try doing a subtract from zero.
- The US Software GOFAST library needs this. */
+ The US Software GOFAST library needs this. FIXME: This is *wrong*
+ for floating-point operations due to negative zeros! */
if (unoptab->code == NEG)
{
rtx temp;
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 064d753269d..dec53d37e29 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -454,6 +454,10 @@ enum can_compare_purpose
ccp_store_flag
};
+/* Return the optab used for computing the given operation on the type
+ given by the second argument. */
+extern optab optab_for_tree_code (enum tree_code, tree);
+
/* Nonzero if a compare of mode MODE can be done straightforwardly
(without splitting it into pieces). */
extern int can_compare_p (enum rtx_code, enum machine_mode,
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 5d23a6e0d18..3944842635d 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -537,6 +537,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
print_node (file, "values", TYPE_VALUES (node), indent + 4);
else if (TREE_CODE (node) == ARRAY_TYPE || TREE_CODE (node) == SET_TYPE)
print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
+ else if (TREE_CODE (node) == VECTOR_TYPE)
+ fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node));
else if (TREE_CODE (node) == RECORD_TYPE
|| TREE_CODE (node) == UNION_TYPE
|| TREE_CODE (node) == QUAL_UNION_TYPE)
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 5bc6cc8051f..f341c39c214 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -191,6 +191,10 @@ const char * reg_names[] = REGISTER_NAMES;
enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
+/* 1 if there is a register of given mode. */
+
+bool have_regs_of_mode [MAX_MACHINE_MODE];
+
/* 1 if class does contain register of given mode. */
static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
@@ -305,7 +309,6 @@ init_reg_sets_1 (void)
{
unsigned int i, j;
unsigned int /* enum machine_mode */ m;
- char allocatable_regs_of_mode [MAX_MACHINE_MODE];
/* This macro allows the fixed or call-used registers
and the register classes to depend on target flags. */
@@ -469,8 +472,8 @@ init_reg_sets_1 (void)
SET_HARD_REG_BIT (regs_invalidated_by_call, i);
}
+ memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode));
memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
- memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
for (i = 0; i < N_REG_CLASSES; i++)
if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
@@ -479,7 +482,7 @@ init_reg_sets_1 (void)
&& HARD_REGNO_MODE_OK (j, m))
{
contains_reg_of_mode [i][m] = 1;
- allocatable_regs_of_mode [m] = 1;
+ have_regs_of_mode [m] = 1;
break;
}
@@ -487,7 +490,7 @@ init_reg_sets_1 (void)
and take the maximum cost of moving any subset to any other. */
for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
- if (allocatable_regs_of_mode [m])
+ if (have_regs_of_mode [m])
{
for (i = 0; i < N_REG_CLASSES; i++)
if (contains_reg_of_mode [i][m])
diff --git a/gcc/regs.h b/gcc/regs.h
index c100bdeabac..027b0e33c67 100644
--- a/gcc/regs.h
+++ b/gcc/regs.h
@@ -163,6 +163,10 @@ extern char regs_ever_live[FIRST_PSEUDO_REGISTER];
extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
+/* Vector indexed by machine mode saying whether there are regs of that mode. */
+
+extern bool have_regs_of_mode [MAX_MACHINE_MODE];
+
/* For each hard register, the widest mode object that it can contain.
This will be a MODE_INT mode if the register can hold integers. Otherwise
it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 0ca26c238f7..139ba510435 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "ggc.h"
#include "target.h"
#include "langhooks.h"
+#include "regs.h"
/* Set to one when set_sizetype has been called. */
static int sizetype_set;
@@ -1582,10 +1583,52 @@ layout_type (tree type)
break;
case VECTOR_TYPE:
- TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
- TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
- TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
- break;
+ {
+ int nunits = TYPE_VECTOR_SUBPARTS (type);
+ tree nunits_tree = build_int_2 (nunits, 0);
+ tree innertype = TREE_TYPE (type);
+
+ if (nunits & (nunits - 1))
+ abort ();
+
+ /* Find an appropriate mode for the vector type. */
+ if (TYPE_MODE (type) == VOIDmode)
+ {
+ enum machine_mode innermode = TYPE_MODE (innertype);
+ enum machine_mode mode;
+
+ /* First, look for a supported vector type. */
+ if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
+ mode = MIN_MODE_VECTOR_FLOAT;
+ else
+ mode = MIN_MODE_VECTOR_INT;
+
+ for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode))
+ if (GET_MODE_NUNITS (mode) == nunits
+ && GET_MODE_INNER (mode) == innermode
+ && VECTOR_MODE_SUPPORTED_P (mode))
+ break;
+
+ /* For integers, try mapping it to a same-sized scalar mode. */
+ if (mode == VOIDmode
+ && GET_MODE_CLASS (innermode) == MODE_INT)
+ mode = mode_for_size (nunits * GET_MODE_BITSIZE (innermode),
+ MODE_INT, 0);
+
+ if (mode == VOIDmode || !have_regs_of_mode[mode])
+ TYPE_MODE (type) = BLKmode;
+ else
+ TYPE_MODE (type) = mode;
+ }
+
+ TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
+ TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR,
+ TYPE_SIZE_UNIT (innertype),
+ nunits_tree, 0);
+ TYPE_SIZE (type) = int_const_binop (MULT_EXPR, TYPE_SIZE (innertype),
+ nunits_tree, 0);
+ break;
+ }
case VOID_TYPE:
/* This is an incomplete type and so doesn't have a size. */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c80dcf1d086..1c04e528cee 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4793,6 +4793,79 @@ struct tree_opt_pass pass_split_crit_edges =
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
};
+
+
+/* Return EXP if it is a valid GIMPLE rvalue, else gimplify it into
+ a temporary, make sure and register it to be renamed if necessary,
+ and finally return the temporary. Put the statements to compute
+ EXP before the current statement in BSI. */
+
+tree
+gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
+{
+ tree t, new_stmt, orig_stmt;
+
+ if (is_gimple_val (exp))
+ return exp;
+
+ t = make_rename_temp (type, NULL);
+ new_stmt = build (MODIFY_EXPR, type, t, exp);
+
+ orig_stmt = bsi_stmt (*bsi);
+ SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
+ TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
+
+ bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+
+ return t;
+}
+
+/* Build a ternary operation and gimplify it. Emit code before BSI.
+ Return the gimple_val holding the result. */
+
+tree
+gimplify_build3 (block_stmt_iterator *bsi, enum tree_code code,
+ tree type, tree a, tree b, tree c)
+{
+ tree ret;
+
+ ret = fold (build3 (code, type, a, b, c));
+ STRIP_NOPS (ret);
+
+ return gimplify_val (bsi, type, ret);
+}
+
+/* Build a binary operation and gimplify it. Emit code before BSI.
+ Return the gimple_val holding the result. */
+
+tree
+gimplify_build2 (block_stmt_iterator *bsi, enum tree_code code,
+ tree type, tree a, tree b)
+{
+ tree ret;
+
+ ret = fold (build2 (code, type, a, b));
+ STRIP_NOPS (ret);
+
+ return gimplify_val (bsi, type, ret);
+}
+
+/* Build a unary operation and gimplify it. Emit code before BSI.
+ Return the gimple_val holding the result. */
+
+tree
+gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
+ tree a)
+{
+ tree ret;
+
+ ret = fold (build1 (code, type, a));
+ STRIP_NOPS (ret);
+
+ return gimplify_val (bsi, type, ret);
+}
+
+
/* Emit return warnings. */
diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c
index 0e6dab7e471..a960f92c424 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -1,4 +1,4 @@
-/* Lower complex operations to scalar operations.
+/* Lower complex number and vector operations to scalar operations.
Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of GCC.
@@ -23,6 +23,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "coretypes.h"
#include "tree.h"
#include "tm.h"
+#include "rtl.h"
+#include "expr.h"
+#include "insn-codes.h"
+#include "diagnostic.h"
+#include "optabs.h"
+#include "machmode.h"
+#include "langhooks.h"
#include "tree-flow.h"
#include "tree-gimple.h"
#include "tree-iterator.h"
@@ -30,28 +37,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "flags.h"
-/* Force EXP to be a gimple_val. */
-
-static tree
-gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
-{
- tree t, new_stmt, orig_stmt;
-
- if (is_gimple_val (exp))
- return exp;
-
- t = make_rename_temp (type, NULL);
- new_stmt = build (MODIFY_EXPR, type, t, exp);
-
- orig_stmt = bsi_stmt (*bsi);
- SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
- TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
-
- bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
-
- return t;
-}
-
/* Extract the real or imaginary part of a complex variable or constant.
Make sure that it's a proper gimple_val and gimplify it if not.
Emit any new code before BSI. */
@@ -85,35 +70,6 @@ extract_component (block_stmt_iterator *bsi, tree t, bool imagpart_p)
return gimplify_val (bsi, inner_type, ret);
}
-/* Build a binary operation and gimplify it. Emit code before BSI.
- Return the gimple_val holding the result. */
-
-static tree
-do_binop (block_stmt_iterator *bsi, enum tree_code code,
- tree type, tree a, tree b)
-{
- tree ret;
-
- ret = fold (build (code, type, a, b));
- STRIP_NOPS (ret);
-
- return gimplify_val (bsi, type, ret);
-}
-
-/* Build a unary operation and gimplify it. Emit code before BSI.
- Return the gimple_val holding the result. */
-
-static tree
-do_unop (block_stmt_iterator *bsi, enum tree_code code, tree type, tree a)
-{
- tree ret;
-
- ret = fold (build1 (code, type, a));
- STRIP_NOPS (ret);
-
- return gimplify_val (bsi, type, ret);
-}
-
/* Update an assignment to a complex variable in place. */
static void
@@ -142,8 +98,8 @@ expand_complex_addition (block_stmt_iterator *bsi, tree inner_type,
{
tree rr, ri;
- rr = do_binop (bsi, code, inner_type, ar, br);
- ri = do_binop (bsi, code, inner_type, ai, bi);
+ rr = gimplify_build2 (bsi, code, inner_type, ar, br);
+ ri = gimplify_build2 (bsi, code, inner_type, ai, bi);
update_complex_assignment (bsi, rr, ri);
}
@@ -158,19 +114,19 @@ expand_complex_multiplication (block_stmt_iterator *bsi, tree inner_type,
{
tree t1, t2, t3, t4, rr, ri;
- t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br);
- t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi);
- t3 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
+ t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
+ t3 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
/* Avoid expanding redundant multiplication for the common
case of squaring a complex number. */
if (ar == br && ai == bi)
t4 = t3;
else
- t4 = do_binop (bsi, MULT_EXPR, inner_type, ai, br);
+ t4 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, br);
- rr = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2);
- ri = do_binop (bsi, PLUS_EXPR, inner_type, t3, t4);
+ rr = gimplify_build2 (bsi, MINUS_EXPR, inner_type, t1, t2);
+ ri = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t3, t4);
update_complex_assignment (bsi, rr, ri);
}
@@ -187,19 +143,19 @@ expand_complex_div_straight (block_stmt_iterator *bsi, tree inner_type,
{
tree rr, ri, div, t1, t2, t3;
- t1 = do_binop (bsi, MULT_EXPR, inner_type, br, br);
- t2 = do_binop (bsi, MULT_EXPR, inner_type, bi, bi);
- div = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, br, br);
+ t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, bi, bi);
+ div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, t2);
- t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br);
- t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi);
- t3 = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2);
- rr = do_binop (bsi, code, inner_type, t3, div);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
+ t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
+ t3 = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, t2);
+ rr = gimplify_build2 (bsi, code, inner_type, t3, div);
- t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, br);
- t2 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi);
- t3 = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2);
- ri = do_binop (bsi, code, inner_type, t3, div);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, br);
+ t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
+ t3 = gimplify_build2 (bsi, MINUS_EXPR, inner_type, t1, t2);
+ ri = gimplify_build2 (bsi, code, inner_type, t3, div);
update_complex_assignment (bsi, rr, ri);
}
@@ -215,8 +171,8 @@ expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type,
tree rr, ri, ratio, div, t1, t2, min, max, cond;
/* Examine |br| < |bi|, and branch. */
- t1 = do_unop (bsi, ABS_EXPR, inner_type, br);
- t2 = do_unop (bsi, ABS_EXPR, inner_type, bi);
+ t1 = gimplify_build1 (bsi, ABS_EXPR, inner_type, br);
+ t2 = gimplify_build1 (bsi, ABS_EXPR, inner_type, bi);
cond = fold (build (LT_EXPR, boolean_type_node, t1, t2));
STRIP_NOPS (cond);
@@ -292,20 +248,20 @@ expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type,
/* Now we have MIN(|br|, |bi|) and MAX(|br|, |bi|). We now use the
ratio min/max to scale both the dividend and divisor. */
- ratio = do_binop (bsi, code, inner_type, min, max);
+ ratio = gimplify_build2 (bsi, code, inner_type, min, max);
/* Calculate the divisor: min*ratio + max. */
- t1 = do_binop (bsi, MULT_EXPR, inner_type, min, ratio);
- div = do_binop (bsi, PLUS_EXPR, inner_type, t1, max);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, min, ratio);
+ div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, max);
- /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div). */
- t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, ratio);
- t2 = do_binop (bsi, PLUS_EXPR, inner_type, ar, t1);
- rr = do_binop (bsi, code, inner_type, t2, div);
+ /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div). */
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, ratio);
+ t2 = gimplify_build2 (bsi, PLUS_EXPR, inner_type, ar, t1);
+ rr = gimplify_build2 (bsi, code, inner_type, t2, div);
- t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, ratio);
- t2 = do_binop (bsi, MINUS_EXPR, inner_type, ai, t1);
- ri = do_binop (bsi, code, inner_type, t2, div);
+ t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, ratio);
+ t2 = gimplify_build2 (bsi, MINUS_EXPR, inner_type, ai, t1);
+ ri = gimplify_build2 (bsi, code, inner_type, t2, div);
update_complex_assignment (bsi, rr, ri);
}
@@ -343,8 +299,8 @@ expand_complex_negation (block_stmt_iterator *bsi, tree inner_type,
{
tree rr, ri;
- rr = do_unop (bsi, NEGATE_EXPR, inner_type, ar);
- ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai);
+ rr = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ar);
+ ri = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ai);
update_complex_assignment (bsi, rr, ri);
}
@@ -359,7 +315,7 @@ expand_complex_conjugate (block_stmt_iterator *bsi, tree inner_type,
{
tree ri;
- ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai);
+ ri = gimplify_build1 (bsi, NEGATE_EXPR, inner_type, ai);
update_complex_assignment (bsi, ar, ri);
}
@@ -372,10 +328,11 @@ expand_complex_comparison (block_stmt_iterator *bsi, tree ar, tree ai,
{
tree cr, ci, cc, stmt, type;
- cr = do_binop (bsi, code, boolean_type_node, ar, br);
- ci = do_binop (bsi, code, boolean_type_node, ai, bi);
- cc = do_binop (bsi, (code == EQ_EXPR ? TRUTH_AND_EXPR : TRUTH_OR_EXPR),
- boolean_type_node, cr, ci);
+ cr = gimplify_build2 (bsi, code, boolean_type_node, ar, br);
+ ci = gimplify_build2 (bsi, code, boolean_type_node, ai, bi);
+ cc = gimplify_build2 (bsi,
+ (code == EQ_EXPR ? TRUTH_AND_EXPR : TRUTH_OR_EXPR),
+ boolean_type_node, cr, ci);
stmt = bsi_stmt (*bsi);
modify_stmt (stmt);
@@ -517,17 +474,434 @@ expand_complex_operations_1 (block_stmt_iterator *bsi)
abort ();
}
}
+
+/* Build a constant of type TYPE, made of VALUE's bits replicated
+ every TYPE_SIZE (INNER_TYPE) bits to fit TYPE's precision. */
+static tree
+build_replicated_const (tree type, tree inner_type, HOST_WIDE_INT value)
+{
+ int width = tree_low_cst (TYPE_SIZE (inner_type), 1);
+ int n = HOST_BITS_PER_WIDE_INT / width;
+ unsigned HOST_WIDE_INT low, high, mask;
+ tree ret;
+
+ if (n == 0)
+ abort ();
+
+ if (width == HOST_BITS_PER_WIDE_INT)
+ low = value;
+ else
+ {
+ mask = ((HOST_WIDE_INT)1 << width) - 1;
+ low = (unsigned HOST_WIDE_INT) ~0 / mask * (value & mask);
+ }
+
+ if (TYPE_PRECISION (type) < HOST_BITS_PER_WIDE_INT)
+ low &= ((HOST_WIDE_INT)1 << TYPE_PRECISION (type)) - 1, high = 0;
+ else if (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT)
+ high = 0;
+ else if (TYPE_PRECISION (type) == 2 * HOST_BITS_PER_WIDE_INT)
+ high = low;
+ else
+ abort ();
+
+ ret = build_int_2 (low, high);
+ TREE_TYPE (ret) = type;
+ return ret;
+}
-/* Main loop to process each statement. */
-/* ??? Could use dominator bits to propagate from complex_expr at the
- same time. This might reveal more constants, particularly in cases
- such as (complex = complex op scalar). This may not be relevant
- after SRA and subsequent cleanups. Proof of this would be if we
- verify that the code generated by expand_complex_div_wide is
- simplified properly to straight-line code. */
+/* Return a suitable vector types made of SUBPARTS units each of mode
+ "word_mode" (the global variable). */
+static tree
+build_word_mode_vector_type (int nunits)
+{
+ static tree innertype;
+ static tree last;
+ static int last_nunits;
+
+ if (!innertype)
+ innertype = lang_hooks.types.type_for_mode (word_mode, 1);
+ else if (last_nunits == nunits)
+ return last;
+
+ /* We build a new type, but we canonicalize it nevertheless,
+ because it still saves some memory. */
+ last_nunits = nunits;
+ last = type_hash_canon (nunits, build_vector_type (innertype, nunits));
+ return last;
+}
+
+typedef tree (*elem_op_func) (block_stmt_iterator *,
+ tree, tree, tree, tree, tree, enum tree_code);
+
+static inline tree
+tree_vec_extract (block_stmt_iterator *bsi, tree type,
+ tree t, tree bitsize, tree bitpos)
+{
+ if (bitpos)
+ return gimplify_build3 (bsi, BIT_FIELD_REF, type, t, bitsize, bitpos);
+ else
+ return gimplify_build1 (bsi, VIEW_CONVERT_EXPR, type, t);
+}
+
+static tree
+do_unop (block_stmt_iterator *bsi, tree inner_type, tree a,
+ tree b ATTRIBUTE_UNUSED, tree bitpos, tree bitsize,
+ enum tree_code code)
+{
+ a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos);
+ return gimplify_build1 (bsi, code, inner_type, a);
+}
+
+static tree
+do_binop (block_stmt_iterator *bsi, tree inner_type, tree a, tree b,
+ tree bitpos, tree bitsize, enum tree_code code)
+{
+ a = tree_vec_extract (bsi, inner_type, a, bitsize, bitpos);
+ b = tree_vec_extract (bsi, inner_type, b, bitsize, bitpos);
+ return gimplify_build2 (bsi, code, inner_type, a, b);
+}
+
+/* Expand vector addition to scalars. This does bit twiddling
+ in order to increase parallelism:
+
+ a + b = (((int) a & 0x7f7f7f7f) + ((int) b & 0x7f7f7f7f)) ^
+ (a ^ b) & 0x80808080
+
+ a - b = (((int) a | 0x80808080) - ((int) b & 0x7f7f7f7f)) ^
+ (a ^ ~b) & 0x80808080
+
+ -b = (0x80808080 - ((int) b & 0x7f7f7f7f)) ^ (~b & 0x80808080)
+
+ This optimization should be done only if 4 vector items or more
+ fit into a word. */
+static tree
+do_plus_minus (block_stmt_iterator *bsi, tree word_type, tree a, tree b,
+ tree bitpos ATTRIBUTE_UNUSED, tree bitsize ATTRIBUTE_UNUSED,
+ enum tree_code code)
+{
+ tree inner_type = TREE_TYPE (TREE_TYPE (a));
+ unsigned HOST_WIDE_INT max;
+ tree low_bits, high_bits, a_low, b_low, result_low, signs;
+
+ max = GET_MODE_MASK (TYPE_MODE (inner_type));
+ low_bits = build_replicated_const (word_type, inner_type, max >> 1);
+ high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1));
+
+ a = tree_vec_extract (bsi, word_type, a, bitsize, bitpos);
+ b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos);
+
+ signs = gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, a, b);
+ b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits);
+ if (code == PLUS_EXPR)
+ a_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, a, low_bits);
+ else
+ {
+ a_low = gimplify_build2 (bsi, BIT_IOR_EXPR, word_type, a, high_bits);
+ signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, signs);
+ }
+
+ signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits);
+ result_low = gimplify_build2 (bsi, code, word_type, a_low, b_low);
+ return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs);
+}
+
+static tree
+do_negate (block_stmt_iterator *bsi, tree word_type, tree b,
+ tree unused ATTRIBUTE_UNUSED, tree bitpos ATTRIBUTE_UNUSED,
+ tree bitsize ATTRIBUTE_UNUSED,
+ enum tree_code code ATTRIBUTE_UNUSED)
+{
+ tree inner_type = TREE_TYPE (TREE_TYPE (b));
+ HOST_WIDE_INT max;
+ tree low_bits, high_bits, b_low, result_low, signs;
+
+ max = GET_MODE_MASK (TYPE_MODE (inner_type));
+ low_bits = build_replicated_const (word_type, inner_type, max >> 1);
+ high_bits = build_replicated_const (word_type, inner_type, max & ~(max >> 1));
+
+ b = tree_vec_extract (bsi, word_type, b, bitsize, bitpos);
+
+ b_low = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, b, low_bits);
+ signs = gimplify_build1 (bsi, BIT_NOT_EXPR, word_type, b);
+ signs = gimplify_build2 (bsi, BIT_AND_EXPR, word_type, signs, high_bits);
+ result_low = gimplify_build2 (bsi, MINUS_EXPR, word_type, high_bits, b_low);
+ return gimplify_build2 (bsi, BIT_XOR_EXPR, word_type, result_low, signs);
+}
+
+/* Expand a vector operation to scalars, by using many operations
+ whose type is the vector type's inner type. */
+static tree
+expand_vector_piecewise (block_stmt_iterator *bsi, elem_op_func f,
+ tree type, tree inner_type,
+ tree a, tree b, enum tree_code code)
+{
+ tree head, *chain = &head;
+ tree part_width = TYPE_SIZE (inner_type);
+ tree index = bitsize_int (0);
+ int nunits = TYPE_VECTOR_SUBPARTS (type);
+ int delta = tree_low_cst (part_width, 1)
+ / tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1);
+ int i;
+
+ for (i = 0; i < nunits;
+ i += delta, index = int_const_binop (PLUS_EXPR, index, part_width, 0))
+ {
+ tree result = f (bsi, inner_type, a, b, index, part_width, code);
+ *chain = tree_cons (NULL_TREE, result, NULL_TREE);
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ return build1 (CONSTRUCTOR, type, head);
+}
+
+/* Expand a vector operation to scalars with the freedom to use
+ a scalar integer type, or to use a different size for the items
+ in the vector type. */
+static tree
+expand_vector_parallel (block_stmt_iterator *bsi, elem_op_func f, tree type,
+ tree a, tree b,
+ enum tree_code code)
+{
+ tree result, compute_type;
+ enum machine_mode mode;
+ int n_words = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD;
+
+ /* We have three strategies. If the type is already correct, just do
+ the operation an element at a time. Else, if the vector is wider than
+ one word, do it a word at a time; finally, if the vector is smaller
+ than one word, do it as a scalar. */
+ if (TYPE_MODE (TREE_TYPE (type)) == word_mode)
+ return expand_vector_piecewise (bsi, f,
+ type, TREE_TYPE (type),
+ a, b, code);
+ else if (n_words > 1)
+ {
+ tree word_type = build_word_mode_vector_type (n_words);
+ result = expand_vector_piecewise (bsi, f,
+ word_type, TREE_TYPE (word_type),
+ a, b, code);
+ result = gimplify_val (bsi, word_type, result);
+ }
+ else
+ {
+ /* Use a single scalar operation with a mode no wider than word_mode. */
+ mode = mode_for_size (tree_low_cst (TYPE_SIZE (type), 1), MODE_INT, 0);
+ compute_type = lang_hooks.types.type_for_mode (mode, 1);
+ result = f (bsi, compute_type, a, b, NULL_TREE, NULL_TREE, code);
+ }
+
+ return build1 (VIEW_CONVERT_EXPR, type, result);
+}
+
+/* Expand a vector operation to scalars; for integer types we can use
+ special bit twiddling tricks to do the sums a word at a time, using
+ function F_PARALLEL instead of F. These tricks are done only if
+ they can process at least four items, that is, only if the vector
+ holds at least four items and if a word can hold four items. */
+static tree
+expand_vector_addition (block_stmt_iterator *bsi,
+ elem_op_func f, elem_op_func f_parallel,
+ tree type, tree a, tree b, enum tree_code code)
+{
+ int parts_per_word = UNITS_PER_WORD
+ / tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (type)), 1);
+
+ if (INTEGRAL_TYPE_P (TREE_TYPE (type))
+ && parts_per_word >= 4
+ && TYPE_VECTOR_SUBPARTS (type) >= 4)
+ return expand_vector_parallel (bsi, f_parallel,
+ type, a, b, code);
+ else
+ return expand_vector_piecewise (bsi, f,
+ type, TREE_TYPE (type),
+ a, b, code);
+}
+
+/* Return a type for the widest vector mode whose components are of mode
+ INNER_MODE, or NULL_TREE if none is found. */
+static tree
+type_for_widest_vector_mode (enum machine_mode inner_mode, optab op)
+{
+ enum machine_mode best_mode = VOIDmode, mode;
+ int best_nunits = 0;
+
+ if (GET_MODE_CLASS (inner_mode) == MODE_FLOAT)
+ mode = MIN_MODE_VECTOR_FLOAT;
+ else
+ mode = MIN_MODE_VECTOR_INT;
+
+ for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+ if (GET_MODE_INNER (mode) == inner_mode
+ && GET_MODE_NUNITS (mode) > best_nunits
+ && op->handlers[mode].insn_code != CODE_FOR_nothing)
+ best_mode = mode, best_nunits = GET_MODE_NUNITS (mode);
+
+ if (best_mode == VOIDmode)
+ return NULL_TREE;
+ else
+ return lang_hooks.types.type_for_mode (best_mode, 1);
+}
+
+/* Process one statement. If we identify a vector operation, expand it. */
+
+static void
+expand_vector_operations_1 (block_stmt_iterator *bsi)
+{
+ tree stmt = bsi_stmt (*bsi);
+ tree *p_rhs, rhs, type, compute_type;
+ enum tree_code code;
+ enum machine_mode compute_mode;
+ optab op;
+
+ switch (TREE_CODE (stmt))
+ {
+ case RETURN_EXPR:
+ stmt = TREE_OPERAND (stmt, 0);
+ if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR)
+ return;
+
+ /* FALLTHRU */
+
+ case MODIFY_EXPR:
+ p_rhs = &TREE_OPERAND (stmt, 1);
+ rhs = *p_rhs;
+ break;
+
+ default:
+ return;
+ }
+
+ type = TREE_TYPE (rhs);
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ return;
+
+ code = TREE_CODE (rhs);
+ if (TREE_CODE_CLASS (code) != '1'
+ && TREE_CODE_CLASS (code) != '2')
+ return;
+
+ if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
+ return;
+
+ if (code == CONVERT_EXPR)
+ abort ();
+
+ op = optab_for_tree_code (code, type);
+
+ /* Optabs will try converting a negation into a subtraction, so
+ look for it as well. TODO: negation of floating-point vectors
+ might be turned into an exclusive OR toggling the sign bit. */
+ if (op == NULL
+ && code == NEGATE_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+ op = optab_for_tree_code (MINUS_EXPR, type);
+
+ /* For very wide vectors, try using a smaller vector mode. */
+ compute_type = type;
+ if (TYPE_MODE (type) == BLKmode && op)
+ {
+ tree vector_compute_type
+ = type_for_widest_vector_mode (TYPE_MODE (TREE_TYPE (type)), op);
+ if (vector_compute_type != NULL_TREE)
+ compute_type = vector_compute_type;
+ }
+
+ compute_mode = TYPE_MODE (compute_type);
+
+ /* If we are breaking a BLKmode vector into smaller pieces,
+ type_for_widest_vector_mode has already looked into the optab,
+ so skip these checks. */
+ if (compute_type == type)
+ {
+ if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT
+ || GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT)
+ && op != NULL
+ && op->handlers[compute_mode].insn_code != CODE_FOR_nothing)
+ return;
+ else
+ {
+ /* There is no operation in hardware, so fall back to scalars. */
+ compute_type = TREE_TYPE (type);
+ compute_mode = TYPE_MODE (compute_type);
+ }
+ }
+
+ /* If the compute mode is not a vector mode (hence we are decomposing
+ a BLKmode vector to smaller, hardware-supported vectors), we may
+ want to expand the operations in parallel. */
+ if (GET_MODE_CLASS (compute_mode) != MODE_VECTOR_INT
+ && GET_MODE_CLASS (compute_mode) != MODE_VECTOR_FLOAT)
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ if (TYPE_TRAP_SIGNED (type))
+ break;
+
+ *p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
+ TREE_OPERAND (rhs, 0),
+ TREE_OPERAND (rhs, 1), code);
+ modify_stmt (bsi_stmt (*bsi));
+ return;
+
+ case NEGATE_EXPR:
+ if (TYPE_TRAP_SIGNED (type))
+ break;
+
+ *p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
+ TREE_OPERAND (rhs, 0),
+ NULL_TREE, code);
+ modify_stmt (bsi_stmt (*bsi));
+ return;
+
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ *p_rhs = expand_vector_parallel (bsi, do_binop, type,
+ TREE_OPERAND (rhs, 0),
+ TREE_OPERAND (rhs, 1), code);
+ modify_stmt (bsi_stmt (*bsi));
+ return;
+
+ case BIT_NOT_EXPR:
+ *p_rhs = expand_vector_parallel (bsi, do_unop, type,
+ TREE_OPERAND (rhs, 0),
+ NULL_TREE, code);
+ modify_stmt (bsi_stmt (*bsi));
+ return;
+
+ default:
+ break;
+ }
+
+ if (TREE_CODE_CLASS (code) == '1')
+ *p_rhs = expand_vector_piecewise (bsi, do_unop, type, compute_type,
+ TREE_OPERAND (rhs, 0),
+ NULL_TREE, code);
+ else
+ *p_rhs = expand_vector_piecewise (bsi, do_binop, type, compute_type,
+ TREE_OPERAND (rhs, 0),
+ TREE_OPERAND (rhs, 1), code);
+
+ modify_stmt (bsi_stmt (*bsi));
+}
+
+static void
+expand_vector_operations (void)
+{
+ block_stmt_iterator bsi;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ expand_vector_operations_1 (&bsi);
+ }
+}
static void
-expand_complex_operations (void)
+tree_lower_operations (void)
{
int old_last_basic_block = last_basic_block;
block_stmt_iterator bsi;
@@ -538,15 +912,19 @@ expand_complex_operations (void)
if (bb->index >= old_last_basic_block)
continue;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- expand_complex_operations_1 (&bsi);
+ {
+ expand_complex_operations_1 (&bsi);
+ expand_vector_operations_1 (&bsi);
+ }
}
}
-struct tree_opt_pass pass_lower_complex =
+
+struct tree_opt_pass pass_lower_vector_ssa =
{
- "complex", /* name */
+ "vector", /* name */
NULL, /* gate */
- expand_complex_operations, /* execute */
+ expand_vector_operations, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
@@ -555,7 +933,24 @@ struct tree_opt_pass pass_lower_complex =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_rename_vars
+ TODO_dump_func | TODO_rename_vars /* todo_flags_finish */
| TODO_ggc_collect | TODO_verify_ssa
- | TODO_verify_stmts | TODO_verify_flow /* todo_flags_finish */
+ | TODO_verify_stmts | TODO_verify_flow
+};
+
+struct tree_opt_pass pass_pre_expand =
+{
+ "oplower", /* name */
+ 0, /* gate */
+ tree_lower_operations, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_cfg, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func | TODO_ggc_collect
+ | TODO_verify_stmts /* todo_flags_finish */
};
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index bd8bd4a8ba4..4d9a18f10ca 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -496,6 +496,13 @@ extern tree tree_block_label (basic_block bb);
extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
extern bool tree_purge_dead_eh_edges (basic_block);
extern bool tree_purge_all_dead_eh_edges (bitmap);
+extern tree gimplify_val (block_stmt_iterator *, tree, tree);
+extern tree gimplify_build1 (block_stmt_iterator *, enum tree_code,
+ tree, tree);
+extern tree gimplify_build2 (block_stmt_iterator *, enum tree_code,
+ tree, tree, tree);
+extern tree gimplify_build3 (block_stmt_iterator *, enum tree_code,
+ tree, tree, tree, tree);
/* In tree-pretty-print.c. */
extern void dump_generic_bb (FILE *, basic_block, int, int);
diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c
index 16db5cf8157..e884260d2b3 100644
--- a/gcc/tree-nested.c
+++ b/gcc/tree-nested.c
@@ -373,7 +373,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
/* Similarly, but only do so to force EXP to satisfy is_gimple_val. */
static tree
-gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
+tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi)
{
if (is_gimple_val (exp))
return exp;
@@ -790,7 +790,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
where we only accept variables (and min_invariant, presumably),
then compute the address into a temporary. */
if (save_val_only)
- *tp = gimplify_val (wi->info, t, &wi->tsi);
+ *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
}
}
break;
@@ -904,7 +904,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
/* If we are in a context where we only accept values, then
compute the address into a temporary. */
if (save_val_only)
- *tp = gimplify_val (wi->info, t, &wi->tsi);
+ *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
}
}
break;
@@ -1041,7 +1041,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data)
field = get_nl_goto_field (i);
x = get_frame_field (info, target_context, field, &wi->tsi);
x = build_addr (x);
- x = gimplify_val (info, x, &wi->tsi);
+ x = tsi_gimplify_val (info, x, &wi->tsi);
arg = tree_cons (NULL, x, NULL);
x = build_addr (new_label);
arg = tree_cons (NULL, x, arg);
@@ -1139,7 +1139,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data)
/* Compute the address of the field holding the trampoline. */
x = get_frame_field (info, target_context, x, &wi->tsi);
x = build_addr (x);
- x = gimplify_val (info, x, &wi->tsi);
+ x = tsi_gimplify_val (info, x, &wi->tsi);
arg = tree_cons (NULL, x, NULL);
/* Do machine-specific ugliness. Normally this will involve
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
index bd4bb0d1885..f2d98af7309 100644
--- a/gcc/tree-optimize.c
+++ b/gcc/tree-optimize.c
@@ -299,6 +299,7 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
+ NEXT_PASS (pass_pre_expand);
NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_all_optimizations);
@@ -325,7 +326,6 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_ch);
NEXT_PASS (pass_profile);
- NEXT_PASS (pass_lower_complex);
NEXT_PASS (pass_sra);
NEXT_PASS (DUP_PASS (pass_rename_ssa_copies));
NEXT_PASS (DUP_PASS (pass_dominator));
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 93129100cef..1edff2df24e 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -120,7 +120,8 @@ extern struct tree_opt_pass pass_may_alias;
extern struct tree_opt_pass pass_split_crit_edges;
extern struct tree_opt_pass pass_pre;
extern struct tree_opt_pass pass_profile;
-extern struct tree_opt_pass pass_lower_complex;
+extern struct tree_opt_pass pass_pre_expand;
+extern struct tree_opt_pass pass_lower_vector_ssa;
extern struct tree_opt_pass pass_fold_builtins;
extern struct tree_opt_pass pass_early_warn_uninitialized;
extern struct tree_opt_pass pass_late_warn_uninitialized;
diff --git a/gcc/tree.c b/gcc/tree.c
index 9122df5437f..4ed3b6714a1 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -111,7 +111,7 @@ static void set_type_quals (tree, int);
static int type_hash_eq (const void *, const void *);
static hashval_t type_hash_hash (const void *);
static void print_type_hash_statistics (void);
-static void finish_vector_type (tree);
+static tree make_vector_type (tree, int, enum machine_mode);
static int type_hash_marked_p (const void *);
static unsigned int type_hash_list (tree, hashval_t);
static unsigned int attribute_hash_list (tree, hashval_t);
@@ -5279,18 +5279,23 @@ tree_operand_check_failed (int idx, enum tree_code code, const char *file,
}
#endif /* ENABLE_TREE_CHECKING */
-/* For a new vector type node T, build the information necessary for
- debugging output. */
+/* Create a new vector type node holding SUBPARTS units of type INNERTYPE,
+ and mapped to the machine mode MODE. Initialize its fields and build
+ the information necessary for debugging output. */
-static void
-finish_vector_type (tree t)
+static tree
+make_vector_type (tree innertype, int nunits, enum machine_mode mode)
{
+ tree t = make_node (VECTOR_TYPE);
+
+ TREE_TYPE (t) = innertype;
+ TYPE_VECTOR_SUBPARTS (t) = nunits;
+ TYPE_MODE (t) = mode;
layout_type (t);
{
- tree index = build_int_2 (TYPE_VECTOR_SUBPARTS (t) - 1, 0);
- tree array = build_array_type (TREE_TYPE (t),
- build_index_type (index));
+ tree index = build_int_2 (nunits - 1, 0);
+ tree array = build_array_type (innertype, build_index_type (index));
tree rt = make_node (RECORD_TYPE);
TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
@@ -5303,6 +5308,8 @@ finish_vector_type (tree t)
numbers equal. */
TYPE_UID (rt) = TYPE_UID (t);
}
+
+ return t;
}
static tree
@@ -5521,36 +5528,39 @@ reconstruct_complex_type (tree type, tree bottom)
return outer;
}
-/* Returns a vector tree node given a vector mode and inner type. */
+/* Returns a vector tree node given a mode (integer, vector, or BLKmode) and
+ the inner type. */
tree
build_vector_type_for_mode (tree innertype, enum machine_mode mode)
{
- tree t;
- t = make_node (VECTOR_TYPE);
- TREE_TYPE (t) = innertype;
- TYPE_MODE (t) = mode;
- finish_vector_type (t);
- return t;
-}
+ int nunits;
-/* Similarly, but takes inner type and units. */
+ if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+ || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+ nunits = GET_MODE_NUNITS (mode);
-tree
-build_vector_type (tree innertype, int nunits)
-{
- enum machine_mode innermode = TYPE_MODE (innertype);
- enum machine_mode mode;
+ else if (GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ /* Check that there are no leftover bits. */
+ if (GET_MODE_BITSIZE (mode) % TREE_INT_CST_LOW (TYPE_SIZE (innertype)))
+ abort ();
- if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
- mode = MIN_MODE_VECTOR_FLOAT;
+ nunits = GET_MODE_BITSIZE (mode)
+ / TREE_INT_CST_LOW (TYPE_SIZE (innertype));
+ }
else
- mode = MIN_MODE_VECTOR_INT;
+ abort ();
- for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode))
- if (GET_MODE_NUNITS (mode) == nunits && GET_MODE_INNER (mode) == innermode)
- return build_vector_type_for_mode (innertype, mode);
+ return make_vector_type (innertype, nunits, mode);
+}
- return NULL_TREE;
+/* Similarly, but takes the inner type and number of units, which must be
+ a power of two. */
+
+tree
+build_vector_type (tree innertype, int nunits)
+{
+ return make_vector_type (innertype, nunits, VOIDmode);
}
/* Given an initializer INIT, return TRUE if INIT is zero or some
diff --git a/gcc/tree.def b/gcc/tree.def
index 65fd479cdb4..80e42e0f862 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -151,7 +151,8 @@ DEFTREECODE (REAL_TYPE, "real_type", 't', 0)
DEFTREECODE (COMPLEX_TYPE, "complex_type", 't', 0)
/* Vector types. The TREE_TYPE field is the data type of the vector
- elements. */
+ elements. The TYPE_PRECISION field is the number of subparts of
+ the vector. */
DEFTREECODE (VECTOR_TYPE, "vector_type", 't', 0)
/* C enums. The type node looks just like an INTEGER_TYPE node.
diff --git a/gcc/tree.h b/gcc/tree.h
index ff5d5eaa72a..41d967c3465 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1516,7 +1516,7 @@ struct tree_block GTY(())
/* For a VECTOR_TYPE, this is the number of sub-parts of the vector. */
#define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \
- GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode)
+ (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.precision)
/* Indicates that objects of this type must be initialized by calling a
function when they are created. */
@@ -3480,7 +3480,6 @@ extern void expand_function_start (tree);
extern void expand_pending_sizes (tree);
extern void recompute_tree_invarant_for_addr_expr (tree);
extern bool needs_to_live_in_memory (tree);
-extern tree make_vector (enum machine_mode, tree, int);
extern tree reconstruct_complex_type (tree, tree);
extern int real_onep (tree);