tree-cfg.c (gimplify_val): Move from tree-complex.c.

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.

From-SVN: r85039
This commit is contained in:
Paolo Bonzini 2004-07-22 08:20:40 +00:00 committed by Paolo Bonzini
parent 727a31fab8
commit 26277d4179
18 changed files with 827 additions and 173 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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)

View File

@ -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])

View File

@ -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

View File

@ -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. */

View File

@ -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. */

View File

@ -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;
/* 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. */
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;
}
/* 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_complex_operations (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
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 */
};

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -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;
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
nunits = GET_MODE_NUNITS (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 ();
nunits = GET_MODE_BITSIZE (mode)
/ TREE_INT_CST_LOW (TYPE_SIZE (innertype));
}
else
abort ();
return make_vector_type (innertype, nunits, mode);
}
/* Similarly, but takes inner type and units. */
/* 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)
{
enum machine_mode innermode = TYPE_MODE (innertype);
enum machine_mode mode;
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)
return build_vector_type_for_mode (innertype, mode);
return NULL_TREE;
return make_vector_type (innertype, nunits, VOIDmode);
}
/* Given an initializer INIT, return TRUE if INIT is zero or some

View File

@ -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.

View File

@ -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);