From 26277d41791a5f1817fbd3412ddb06f6efc961b9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Jul 2004 08:20:40 +0000 Subject: [PATCH] tree-cfg.c (gimplify_val): Move from tree-complex.c. 2004-07-22 Paolo Bonzini * 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. From-SVN: r85039 --- gcc/ChangeLog | 42 +++ gcc/Makefile.in | 5 +- gcc/c-common.c | 23 +- gcc/optabs.c | 86 ++++++- gcc/optabs.h | 4 + gcc/print-tree.c | 2 + gcc/regclass.c | 11 +- gcc/regs.h | 4 + gcc/stor-layout.c | 51 +++- gcc/tree-cfg.c | 73 ++++++ gcc/tree-complex.c | 603 ++++++++++++++++++++++++++++++++++++-------- gcc/tree-flow.h | 7 + gcc/tree-nested.c | 10 +- gcc/tree-optimize.c | 2 +- gcc/tree-pass.h | 3 +- gcc/tree.c | 68 ++--- gcc/tree.def | 3 +- gcc/tree.h | 3 +- 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 + + * 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 * 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 @@ -627,6 +627,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 @@ -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); -- 2.30.2