Hello,
this is the second approach of the patch I've sent some months ago. I think we
saw that there was no other approach shown, so I will continue on that ...
The idea of this pass is to introduce a statement "normalization" and
"denormalization". The "normalization" happens in forward-propagation, and
"denormalization" is done by this type-demotion-pass. Therefore it is
recommented that the type-demotion pass runs just before the forwprop-pass, as
otherwise we might end in "denormalized" representation, which is in some cases
less performance.
The current pass supports for addition/substraction type-transscript to
unsigned-integer logic for preventing overflow-issues. By this we transform
operations like:
int a,b; ... (unsigned int) (a + b) ... into ((unsigned int) a) + ((unsigned
int) b).
This transformation needs to be done after first analyze code, as we otherwise
would destroy overflow-detection by this transscription. We could do the same
for MULT_EXPR, if there wouldn't be that late analyzis of "possible" overflow
of it. Therefore I disabled such transformation for it.
Then it supports shift-operation type-sinking/type-raising. This seems to be
the most interesting part of this patch - beside of the constnat propagtion
optimization as seen in ts-add-3.c testcase - as this kind of optimization is
new to gcc. The part in forward-propagation is required to define the "normal"
notation of such shift-expressions. As nice side-effect by these
transformation we can find that type-over-widening on some operations don't
occure anymore in vectorize code.
Additional this pass should catch useless type-conversion and simplifies them.
Therefore I kept the code about type-cast reduction still within that pass. Of
course we can move it out to some other place, like tree-ssa-gimple, or even
gimple might be a place. But right now I would like to keep at beginning all
those pieces together.
ChangeLog gcc
* Makefile.in: Add tree-ssa-te.c to build.
* passes.def: Add typedemote passes.
* tree-pass.h (make_pass_demote1): Add prototype.
(make_pass_demote2): Likewise.
* tree-ssa-forwprop.c (simplify_shift): New function.
(ssa_forward_propagate_and_combine): Use it.
* tree-ssa-te.c: New pass.
Changelog gcc/testsuite:
* gcc.dg/tree-ssa/scev-cast.c: Adjust test.
* gcc.dg/tree-ssa/ssa-fre-2.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-4.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-5.c: Likewise.
* gcc.dg/vect/vect-over-widen-1-big-array.c: Likewise.
* gcc.dg/vect/vect-over-widen-1.c: Likewise.
* gcc.dg/vect/vect-over-widen-3-big-array.c: Likewise.
* gcc.dg/vect/vect-over-widen-3.c: Likewise.
* gcc.dg/vect/vect-over-widen-4-big-array.c: Likewise.
* gcc.dg/vect/vect-over-widen-4.c: Likewise.
* gcc.dg/tree-ssa/ts-add-1.c: New test.
* gcc.dg/tree-ssa/ts-add-2.c: New test.
* gcc.dg/tree-ssa/ts-add-3.c: New test.
* gcc.dg/tree-ssa/ts-shift-1.c: New test.
Test for x86_64-unknown-linux-gnu, and i686-pc-cygwin, and x86_64-pc-cygwin.
Ok for apply?
Regards,
Kai
Index: gcc-trunk/gcc/Makefile.in
===================================================================
--- gcc-trunk.orig/gcc/Makefile.in
+++ gcc-trunk/gcc/Makefile.in
@@ -1430,6 +1430,7 @@ OBJS = \
tree-ssa-pre.o \
tree-ssa-propagate.o \
tree-ssa-reassoc.o \
+ tree-ssa-te.o \
tree-ssa-sccvn.o \
tree-ssa-sink.o \
tree-ssa-strlen.o \
Index: gcc-trunk/gcc/passes.def
===================================================================
--- gcc-trunk.orig/gcc/passes.def
+++ gcc-trunk/gcc/passes.def
@@ -64,6 +64,7 @@ along with GCC; see the file COPYING3.
NEXT_PASS (pass_remove_cgraph_callee_edges);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_ccp);
+ NEXT_PASS (pass_demote1);
/* After CCP we rewrite no longer addressed locals into SSA
form if possible. */
NEXT_PASS (pass_forwprop);
@@ -141,6 +142,7 @@ along with GCC; see the file COPYING3.
/* After CCP we rewrite no longer addressed locals into SSA
form if possible. */
NEXT_PASS (pass_phiprop);
+ NEXT_PASS (pass_demote2);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_object_sizes);
/* pass_build_alias is a dummy pass that ensures that we
Index: gcc-trunk/gcc/tree-pass.h
===================================================================
--- gcc-trunk.orig/gcc/tree-pass.h
+++ gcc-trunk/gcc/tree-pass.h
@@ -430,6 +430,8 @@ extern gimple_opt_pass *make_pass_vrp (g
extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_reassoc (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_demote1 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_demote2 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_rebuild_cgraph_edges (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_remove_cgraph_callee_edges (gcc::context
*ctxt);
@@ -447,6 +449,8 @@ extern gimple_opt_pass *make_pass_split_
extern gimple_opt_pass *make_pass_feedback_split_functions (gcc::context
*ctxt);
extern gimple_opt_pass *make_pass_strength_reduction (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_vtable_verify (gcc::context *ctxt);
+extern struct gimple_opt_pass pass_type_demote1;
+extern struct gimple_opt_pass pass_type_demote2;
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
Index: gcc-trunk/gcc/tree-ssa-forwprop.c
===================================================================
--- gcc-trunk.orig/gcc/tree-ssa-forwprop.c
+++ gcc-trunk/gcc/tree-ssa-forwprop.c
@@ -548,6 +548,107 @@ forward_propagate_into_gimple_cond (gimp
return 0;
}
+/* Try to simplify shift-statement ((TYPE1) X) CODE Y for
+ integral-kind types.
+ Returns none-zero if the stmt was changed. */
+
+static int
+simplify_shift (enum tree_code code, gimple_stmt_iterator *gsi_p)
+{
+ gimple stmt = gsi_stmt (*gsi_p);
+ gimple def, newop;
+ tree op1, opx, op2, t_opx, tem;
+ int ret;
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
+ return 0;
+
+ op1 = gimple_assign_rhs1 (stmt);
+ if (TREE_CODE (op1) != SSA_NAME
+ || !(def = SSA_NAME_DEF_STMT (op1))
+ || !is_gimple_assign (def)
+ || !gimple_assign_cast_p (def)
+ || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1)
+ || !has_single_use (op1))
+ return 0;
+
+ opx = gimple_assign_rhs1 (def);
+ if (TREE_CODE (opx) != SSA_NAME)
+ return 0;
+
+ t_opx = TREE_TYPE (opx);
+
+ if (!INTEGRAL_TYPE_P (t_opx))
+ return 0;
+
+ op2 = gimple_assign_rhs2 (stmt);
+
+ if (code == LSHIFT_EXPR)
+ {
+ if (TYPE_PRECISION (TREE_TYPE (op1))
+ > TYPE_PRECISION (t_opx))
+ return 0;
+ }
+ else if (code == RSHIFT_EXPR)
+ {
+ /* If type of OPX and OP1 are compatible, we don't need to check OP2
+ for validity as we don't change range of operation.
+ Otherwise we need to check that right-hand operand of shift-right
+ doesn't exceed type-precision of inner operand. */
+ if (!useless_type_conversion_p (TREE_TYPE (op1), t_opx))
+ {
+ if (TREE_CODE (op2) != INTEGER_CST)
+ return 0;
+ if (integer_zerop (fold_binary (LT_EXPR, boolean_type_node, op2,
+ build_int_cst (TREE_TYPE (op2),
+ TYPE_PRECISION
(t_opx)))))
+ return 0;
+
+ /* See if cast can be moved out of the shift-right operation. */
+ if (TYPE_PRECISION (TREE_TYPE (op1)) <= TYPE_PRECISION (t_opx)
+ || (!TYPE_UNSIGNED (t_opx) && TYPE_UNSIGNED (TREE_TYPE (op1))))
+ return 0;
+ }
+ }
+ else
+ return 0;
+
+ /* Do transformation ((T1) X) shift-code N -> (T1) (X shift-code N). */
+ if (dump_file)
+ {
+ fprintf (dump_file, " Replaced ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, " ");
+ print_gimple_stmt (dump_file, def, 0, 0);
+ fprintf (dump_file, " by ");
+ }
+
+ tem = make_ssa_name (t_opx, NULL);
+ newop = gimple_build_assign_with_ops (code, tem, opx, op2);
+ gimple_set_location (newop, gimple_location (stmt));
+ gsi_insert_before (gsi_p, newop, GSI_SAME_STMT);
+ gimple_assign_set_rhs_with_ops_1 (gsi_p, NOP_EXPR, tem, NULL_TREE,
NULL_TREE);
+
+ if (gimple_location (def) != UNKNOWN_LOCATION)
+ gimple_set_location (stmt, gimple_location (def));
+
+ stmt = gsi_stmt (*gsi_p);
+ update_stmt (stmt);
+
+ if (TREE_CODE (op1) == SSA_NAME)
+ ret = remove_prop_source_from_use (op1) ? 2 : 1;
+ else
+ ret = 1;
+ if (dump_file)
+ {
+ fprintf (dump_file, " by ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, " ");
+ print_gimple_stmt (dump_file, newop, 0, 0);
+ }
+
+ return ret;
+}
/* Propagate from the ssa name definition statements of COND_EXPR
in the rhs of statement STMT into the conditional if that simplifies it.
@@ -3429,6 +3530,15 @@ ssa_forward_propagate_and_combine (void)
|| code == NEGATE_EXPR)
&& TREE_CODE (rhs1) == SSA_NAME)
changed = simplify_not_neg_expr (&gsi);
+ else if (code == LSHIFT_EXPR
+ || code == RSHIFT_EXPR)
+ {
+ int did_something;
+ did_something = simplify_shift (code, &gsi);
+ if (did_something == 2)
+ cfg_changed = true;
+ changed = did_something != 0;
+ }
else if (code == COND_EXPR
|| code == VEC_COND_EXPR)
{
Index: gcc-trunk/gcc/tree-ssa-te.c
===================================================================
--- /dev/null
+++ gcc-trunk/gcc/tree-ssa-te.c
@@ -0,0 +1,885 @@
+/* Type-demotion for trees
+ Copyright (C) 2013
+ Free Software Foundation, Inc.
+ Contributed by Kai Tietz <[email protected]>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ This pass tries sink casts into statements. So statements like
+ (TYPE) (OP1 code OP2) are getting transformed into ((TYPE) OP1) code
((TYPE) OP2).
+
+ These transformation are the oppose transformation-direction of that one
done in
+ tree-ssa-forward-propagation. We can do those transformation within one
pass due
+ cycles. The "normal" representation is generated by the
forward-propagation. It
+ tries instead to raise casts out of the statement.
+ Therefore it is essential that forward-propagation pass is done after this
+ type-demotion pass, so that "normal" representation is kept.
+
+ By this we are able to resolve two optimization opportunities. First is
some
+ constant propagation within binary-expressions. The second is the
reduction of
+ useless type-conversions within statements.
+
+ That we actual do here full transformation instead of doing "virtual"
+ expression-optimization and just write out optimized expression is caused
+ by a complexity issues. Such analyzis might cause too high complexity. So
+ it is more efficient and simpler to perform optimization instead. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "hash-table.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "tree.h"
+#include "flags.h"
+#include "basic-block.h"
+#include "gimple-pretty-print.h"
+#include "tree-inline.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
+#include "tree-iterator.h"
+#include "tree-pass.h"
+#include "alloc-pool.h"
+#include "vec.h"
+#include "langhooks.h"
+#include "pointer-set.h"
+#include "cfgloop.h"
+#include "target.h"
+#include "params.h"
+#include "diagnostic-core.h"
+
+/* Operation kinds. */
+#define TDK_NO_EXPAND_VIA_UNSIGNED 1
+#define TDK_NO_EXPAND_WIDENING 2
+
+/* Returns true if statement S1 dominates statement S2. Like
+ stmt_dominates_stmt_p, but uses stmt UIDs to optimize. */
+
+static bool
+uid_stmt_dominates_stmt_p (gimple s1, gimple s2)
+{
+ basic_block bb1 = gimple_bb (s1), bb2 = gimple_bb (s2);
+
+ /* If bb1 is NULL, it should be a GIMPLE_NOP def stmt of an (D)
+ SSA_NAME. Assume it lives at the beginning of function and
+ thus dominates everything. */
+ if (!bb1 || s1 == s2)
+ return true;
+
+ /* If bb2 is NULL, it doesn't dominate any stmt with a bb. */
+ if (!bb2)
+ return false;
+
+ if (bb1 == bb2)
+ {
+ /* PHIs in the same basic block are assumed to be
+ executed all in parallel, if only one stmt is a PHI,
+ it dominates the other stmt in the same basic block. */
+ if (gimple_code (s1) == GIMPLE_PHI)
+ return true;
+
+ if (gimple_code (s2) == GIMPLE_PHI)
+ return false;
+
+ /* gcc_assert (gimple_uid (s1) && gimple_uid (s2)); */
+
+ if (gimple_uid (s1) < gimple_uid (s2))
+ return true;
+
+ if (gimple_uid (s1) > gimple_uid (s2))
+ return false;
+
+ gimple_stmt_iterator gsi = gsi_for_stmt (s1);
+ unsigned int uid = gimple_uid (s1);
+ for (gsi_next (&gsi); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple s = gsi_stmt (gsi);
+ if (gimple_uid (s) != uid)
+ break;
+ if (s == s2)
+ return true;
+ }
+
+ return false;
+ }
+
+ return dominated_by_p (CDI_DOMINATORS, bb2, bb1);
+}
+
+/* Insert STMT after INSERT_POINT. */
+
+static void
+insert_stmt_after (gimple stmt, gimple insert_point)
+{
+ gimple_stmt_iterator gsi;
+ basic_block bb;
+
+ if (gimple_code (insert_point) == GIMPLE_PHI)
+ bb = gimple_bb (insert_point);
+ else if (!stmt_ends_bb_p (insert_point))
+ {
+ gsi = gsi_for_stmt (insert_point);
+ gimple_set_uid (stmt, gimple_uid (insert_point));
+ gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
+ return;
+ }
+ else
+ /* We assume INSERT_POINT is a SSA_NAME_DEF_STMT of some SSA_NAME,
+ thus if it must end a basic block, it should be a call that can
+ throw, or some assignment that can throw. If it throws, the LHS
+ of it will not be initialized though, so only valid places using
+ the SSA_NAME should be dominated by the fallthru edge. */
+ bb = find_fallthru_edge (gimple_bb (insert_point)->succs)->dest;
+ gsi = gsi_after_labels (bb);
+ if (gsi_end_p (gsi))
+ {
+ gimple_stmt_iterator gsi2 = gsi_last_bb (bb);
+ gimple_set_uid (stmt,
+ gsi_end_p (gsi2) ? 1 : gimple_uid (gsi_stmt (gsi2)));
+ }
+ else
+ gimple_set_uid (stmt, gimple_uid (gsi_stmt (gsi)));
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+}
+
+/* Returns the basic-block, which would be used, if a statement
+ would be insert at INSERT_POINT. */
+
+static basic_block
+get_insert_stmt_after_bb (gimple insert_point)
+{
+ basic_block bb = gimple_bb (insert_point);
+
+ if (gimple_code (insert_point) == GIMPLE_PHI
+ || !stmt_ends_bb_p (insert_point))
+ return bb;
+ /* We assume INSERT_POINT is a SSA_NAME_DEF_STMT of some SSA_NAME,
+ thus if it must end a basic block, it should be a call that can
+ throw, or some assignment that can throw. If it throws, the LHS
+ of it will not be initialized though, so only valid places using
+ the SSA_NAME should be dominated by the fallthru edge. */
+ bb = find_fallthru_edge (bb->succs)->dest;
+ return gimple_bb (gsi_stmt (gsi_after_labels (bb)));
+}
+
+/* Returns the basic-block, which would be used on insertation
+ of a statement having OP1 (and OP2). */
+
+static basic_block
+get_insertation_bb (tree op1, tree op2)
+{
+ gimple op1def = NULL, op2def = NULL, insert_point;
+ gimple_stmt_iterator gsi;
+
+ /* Find an insertion place and insert. */
+ if (op1 && TREE_CODE (op1) == SSA_NAME)
+ op1def = SSA_NAME_DEF_STMT (op1);
+ if (op2 && TREE_CODE (op2) == SSA_NAME)
+ op2def = SSA_NAME_DEF_STMT (op2);
+
+ if ((!op1def || gimple_nop_p (op1def))
+ && (!op2def || gimple_nop_p (op2def)))
+ {
+ gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+ return gimple_bb (gsi_stmt (gsi));
+ }
+
+ if ((!op1def || gimple_nop_p (op1def))
+ || (op2def && !gimple_nop_p (op2def)
+ && uid_stmt_dominates_stmt_p (op1def, op2def)))
+ insert_point = op2def;
+ else
+ insert_point = op1def;
+
+ return get_insert_stmt_after_bb (insert_point);
+}
+
+/* Determine if a new statement dependent on OP1 (and OP2)
+ would be inserted at place with loop-depth bigger as the
+ loop-depth of statement STMT.
+ On matching condition TRUE is returned, otherwise FALSE. */
+
+static bool
+sink_into_loop_p (gimple stmt, tree op1, tree op2)
+{
+ basic_block bb;
+ unsigned stmt_depth, ins_deepth;
+
+ if (op1 && TREE_CODE (op1) != SSA_NAME)
+ op1 = NULL_TREE;
+ if (op2 && TREE_CODE (op2) != SSA_NAME)
+ op2 = NULL_TREE;
+ if (!op1 && !op2)
+ return false;
+
+ bb = get_insertation_bb (op1, op2);
+ ins_deepth = loop_depth (bb->loop_father);
+
+ if (!ins_deepth)
+ return false;
+
+ stmt_depth = loop_depth (gimple_bb (stmt)->loop_father);
+
+ return (stmt_depth < ins_deepth);
+}
+
+/* Builds one assign-statement performing OP1 OPCODE OP2 or OPCODE OP1,
+ using TMPVAR for the result. Places the statement after the definition
+ of either OP1 or OP2. Returns the new statement's lhs-tree. */
+
+static tree
+build_gimple_assign_loc (tree type, tree op1, tree op2, enum tree_code opcode,
+ location_t loc)
+{
+ gimple op1def = NULL, op2def = NULL;
+ gimple_stmt_iterator gsi;
+ tree op;
+ gimple sum;
+
+ /* Create the addition statement. */
+ op = make_ssa_name (type, NULL);
+ sum = gimple_build_assign_with_ops (opcode, op, op1, op2);
+
+ /* Find an insertion place and insert. */
+ if (op1 && TREE_CODE (op1) == SSA_NAME)
+ op1def = SSA_NAME_DEF_STMT (op1);
+ if (op2 && TREE_CODE (op2) == SSA_NAME)
+ op2def = SSA_NAME_DEF_STMT (op2);
+ if ((!op1def || gimple_nop_p (op1def))
+ && (!op2def || gimple_nop_p (op2def)))
+ {
+ gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+ if (gsi_end_p (gsi))
+ {
+ gimple_stmt_iterator gsi2
+ = gsi_last_bb (single_succ (ENTRY_BLOCK_PTR));
+ gimple_set_uid (sum,
+ gsi_end_p (gsi2) ? 1 : gimple_uid (gsi_stmt (gsi2)));
+ }
+ else
+ gimple_set_uid (sum, gimple_uid (gsi_stmt (gsi)));
+ gsi_insert_before (&gsi, sum, GSI_NEW_STMT);
+ }
+ else
+ {
+ gimple insert_point;
+ if ((!op1def || gimple_nop_p (op1def))
+ || (op2def && !gimple_nop_p (op2def)
+ && uid_stmt_dominates_stmt_p (op1def, op2def)))
+ insert_point = op2def;
+ else
+ insert_point = op1def;
+ insert_stmt_after (sum, insert_point);
+ }
+
+ gimple_set_location (sum, loc);
+ update_stmt (sum);
+
+ return gimple_assign_lhs (sum);
+}
+
+/* Release assign-statement chain of VAR, if it has zero-uses.
+ This functions tries to recurse on up to two operands. */
+
+static void
+remove_stmt_chain (tree var)
+{
+ tree var2;
+ gimple stmt;
+ gimple_stmt_iterator gsi;
+
+ while (1)
+ {
+ if (TREE_CODE (var) != SSA_NAME || !has_zero_uses (var))
+ return;
+ stmt = SSA_NAME_DEF_STMT (var);
+ if (!is_gimple_assign (stmt))
+ return;
+ var = gimple_assign_rhs1 (stmt);
+ if (gimple_assign_rhs_class (stmt) == GIMPLE_BINARY_RHS)
+ var2 = gimple_assign_rhs2 (stmt);
+ else
+ var2 = NULL_TREE;
+ gsi = gsi_for_stmt (stmt);
+ gsi_remove (&gsi, true);
+ release_defs (stmt);
+ if (var2)
+ remove_stmt_chain (var2);
+ }
+}
+
+/* Generated gimple cast expression (NEWTYPE) name, and
+ return new created assignment. */
+
+static tree
+gen_cast (tree newtype, tree name)
+{
+ tree ret;
+
+ if (INTEGRAL_TYPE_P (newtype) && TREE_CODE (name) == INTEGER_CST)
+ {
+ bool saved_flag_wrapv = flag_wrapv;
+ flag_wrapv = 1;
+ ret = fold_convert (newtype, name);
+ flag_wrapv = saved_flag_wrapv;
+
+ return ret;
+ }
+
+ /* We can't propagate through our defining statement, so emit
+ a conversion explicitely. */
+ if (useless_type_conversion_p (newtype, TREE_TYPE (name)))
+ return name;
+
+ ret = build_gimple_assign_loc (newtype, name, NULL_TREE, NOP_EXPR,
+ EXPR_LOCATION (name));
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Create cast ");
+ print_gimple_stmt (dump_file, SSA_NAME_DEF_STMT (ret), 0, 0);
+ }
+
+ return ret;
+}
+
+/* Check if simplification of pattern '(TYPE1) (TYPE2) X' to '(TYPE1) X' is
+ possible. If so this function returns true, otherwise false.
+ */
+
+static bool
+demote_cast_p (tree t1, tree t2, tree tx)
+{
+ if (!INTEGRAL_TYPE_P (t1)
+ || !INTEGRAL_TYPE_P (t2))
+ return false;
+
+ /* A boolean-cast of a boolean-type can be optimized away for any width.
+ A useless type-conversion can be optimized away, too. */
+ if (useless_type_conversion_p (t1, t2)
+ || useless_type_conversion_p (t2, tx)
+ /* Boolean types might have different width. */
+ || (TREE_CODE (t2) == BOOLEAN_TYPE
+ && (TREE_CODE (t1) == BOOLEAN_TYPE
+ || TREE_CODE (tx) == BOOLEAN_TYPE)))
+ return true;
+
+ /* Boolean types are special ...
+ They aren't real integer-scalar values, and a cast to a boolean-type
+ implies a comparison. Therefore it isn't allowed to perform
simplification
+ for any of the remaining operations if T2 is of Boolean kind. */
+ if (TREE_CODE (t2) == BOOLEAN_TYPE
+ || !INTEGRAL_TYPE_P (tx))
+ return false;
+
+ /* For (T1) (T2) X, if T1 <= X && T2 >= X we can transform to
+ (T1) X. */
+ if (TYPE_PRECISION (t1) <= TYPE_PRECISION (tx))
+ return (TYPE_PRECISION (t1) <= TYPE_PRECISION (t2));
+
+ /* If T2 < X, then there is a truncation and we
+ can't do anything. */
+ if (TYPE_PRECISION (t2) < TYPE_PRECISION (tx))
+ return false;
+
+ /* For (T1) (T2) X, if T1 > X && T1 <= T2, we can
+ transform to (T1) X. */
+ if (TYPE_PRECISION (t1) <= TYPE_PRECISION (t2))
+ return true;
+
+ /* For (T1) (T2) X, if T1 > X && T2 >= X && SIGN(X) == SIGN(T2),
+ we can transform to (T1) X. */
+ return (TYPE_UNSIGNED (t2) == TYPE_UNSIGNED (tx));
+}
+
+
+/* Try to sink cast expression (TYPE1) (TYPE2) X to (TYPE1) X, if
+ TYPE1, TYPE2, and type of X are of integral kind and met condition
+ checked in demote_cast_p.
+ If cast was sunken, then TRUE is returned, otherwise FALSE. */
+
+static bool
+demote_cast (gimple def, tree name, tree c, gimple def2)
+{
+ tree x;
+
+ if (!gimple_assign_cast_p (def2))
+ return false;
+
+ x = gimple_assign_rhs1 (def2);
+
+ if (TREE_CODE (x) != SSA_NAME
+ || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (x)
+ || !demote_cast_p (TREE_TYPE (name), TREE_TYPE (c), TREE_TYPE (x)))
+ return false;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Remove cast ");
+ print_gimple_stmt (dump_file, def, 0, 0);
+ fprintf (dump_file, " ");
+ print_gimple_stmt (dump_file, def2, 0, 0);
+ }
+
+ gimple_assign_set_rhs1 (def, x);
+
+ if (useless_type_conversion_p (TREE_TYPE (name), TREE_TYPE (x)))
+ gimple_assign_set_rhs_code (def, SSA_NAME);
+
+ if (gimple_location (def2) != UNKNOWN_LOCATION
+ && gimple_location (def) == UNKNOWN_LOCATION)
+ gimple_set_location (def, gimple_location (def2));
+
+ update_stmt (def);
+ remove_stmt_chain (c);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, " by cast ");
+ print_gimple_stmt (dump_file, def, 0, 0);
+ }
+
+ return true;
+}
+
+/* Helper routine to check if OP is an gimple-cast-statement of
+ an integral value.
+ On success the gimple-statment variable referenced by PDEF is set,
+ if PDEF isn't zero.
+ On sucess the right-hand operand of the cast statment is stored in PINNER,
+ if PINNER isn't zero.
+ On success TRUE is returnd, otherwise FALSE. */
+
+static bool
+is_integral_cast (tree op, gimple *pdef, tree *pinner)
+{
+ gimple def = NULL;
+ tree inner;
+
+ if (TREE_CODE (op) != SSA_NAME
+ || !(def = SSA_NAME_DEF_STMT (op))
+ || !is_gimple_assign (def)
+ || !gimple_assign_cast_p (def)
+ || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
+ return false;
+
+ inner = gimple_assign_rhs1 (def);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (inner)))
+ return false;
+
+ if (pdef)
+ *pdef = def;
+ if (pinner)
+ *pinner = inner;
+ return true;
+}
+
+/* Try to demote a cast into assignment. We try to do this for
+ MULT_EXPR, PLUS_EXPR, MINUS_EXPR, LROTATE_EXPR, RROTATE_EXPR,
+ LSHIFT_EXPR, RSHIFT_EXPR, BIT_IOR_EXPR, BIT_XOR_EXPR, BIT_AND_EXPR,
+ MIN_EXPR, and MAX_EXPR.
+ On success function modifies incoming STMT and new statement is stored
+ in PSTMT. The result on success is TRUE, otherwise FALSE. */
+
+static bool
+demote_into (int flags, gimple stmt, tree lhs, tree r, gimple r_stmt, gimple
*pstmt)
+{
+ gimple_stmt_iterator gsi;
+ enum tree_code code;
+ tree l_type = TREE_TYPE (lhs);
+ tree r_type = TREE_TYPE (r);
+ tree a1, a2, i1 = NULL_TREE;
+ gimple def = NULL;
+
+ /* We can't do type-sinking if only one side is Boolean-typed. */
+ if ((TREE_CODE (r_type) == BOOLEAN_TYPE
+ || TREE_CODE (l_type) == BOOLEAN_TYPE)
+ && TREE_CODE (r_type) != TREE_CODE (l_type))
+ return false;
+
+ if ((flags & TDK_NO_EXPAND_WIDENING) != 0
+ && TYPE_PRECISION (l_type) > TYPE_PRECISION (r_type))
+ return false;
+
+ code = gimple_assign_rhs_code (r_stmt);
+
+ switch (code)
+ {
+ case MULT_EXPR:
+ /* We don't want to sink casts into multiply-expressions
+ if outter type and inner-type don't have same sign. */
+ if (TYPE_UNSIGNED (l_type) != TYPE_UNSIGNED (r_type))
+ return false;
+
+ /* If inner-type isn't unsigned, we don't want to convert. */
+ if (!TYPE_UNSIGNED (l_type)
+ && !useless_type_conversion_p (l_type, r_type))
+ return false;
+ /* Fall through. */
+
+ case PLUS_EXPR: case MINUS_EXPR:
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+
+ if (TYPE_PRECISION (l_type) < TYPE_PRECISION (r_type)
+ && (!TYPE_UNSIGNED (l_type) && !flag_wrapv))
+ {
+ tree uns;
+
+ if ((flags & TDK_NO_EXPAND_VIA_UNSIGNED) != 0
+ || sink_into_loop_p (stmt, a1, a2))
+ return false;
+
+ uns = unsigned_type_for (l_type);
+ a1 = gen_cast (uns, a1);
+ a2 = gen_cast (uns, a2);
+ a1 = build_gimple_assign_loc (uns, a1, a2, code,
+ gimple_location (r_stmt));
+ code = NOP_EXPR;
+ a2 = NULL_TREE;
+ break;
+ }
+ else if ((flags & TDK_NO_EXPAND_VIA_UNSIGNED) == 0
+ && TYPE_PRECISION (l_type) < TYPE_PRECISION (r_type)
+ && (TYPE_UNSIGNED (l_type) || flag_wrapv))
+ {
+ if (sink_into_loop_p (stmt, a1, a2))
+ return false;
+ a1 = gen_cast (l_type, a1);
+ a2 = gen_cast (l_type, a2);
+ break;
+ }
+ else if (TYPE_PRECISION (l_type) == TYPE_PRECISION (r_type))
+ {
+ if (TYPE_UNSIGNED (r_type) == TYPE_UNSIGNED (l_type)
+ || !TYPE_UNSIGNED (r_type))
+ {
+ a1 = gen_cast (l_type, a1);
+ a2 = gen_cast (l_type, a2);
+ break;
+ }
+ }
+ return false;
+
+ case LROTATE_EXPR: case RROTATE_EXPR:
+ /* Any cast with same precision as inner left-hand value can be
+ sunken. */
+ if (TYPE_PRECISION (l_type) == TYPE_PRECISION (r_type))
+ {
+ a1 = gimple_assign_rhs1 (r_stmt);
+ if (!useless_type_conversion_p (l_type, r_type))
+ a1 = gen_cast (l_type, a1);
+ a2 = gimple_assign_rhs2 (r_stmt);
+ break;
+ }
+
+ return false;
+
+ case RSHIFT_EXPR:
+ /* For shift-right operation (T1) (X >> N) we can do sink type into
shift-statement,
+ if types of X and T1 are compatible, or if type-precision of T1
+ is greater then type-precision of X plus the T1 isn't unsigned
+ and type of X isn't signed.
+ As this doesn't lower precision of resulting type, we don't need to
check for
+ out of bounds N for type T1. */
+
+ if (useless_type_conversion_p (l_type, r_type))
+ {
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+ break;
+ }
+
+ if (TYPE_PRECISION (l_type) > TYPE_PRECISION (r_type)
+ && (!TYPE_UNSIGNED (l_type) || TYPE_UNSIGNED (r_type)))
+ {
+ a1 = gimple_assign_rhs1 (r_stmt);
+ /* We do this transformation only, if left-hand operand
+ is a cast operation. It is valid for any such construct,
+ nevertheless it might introduce none-reversable pattern.
+ TODO: Add reverse-pattern to forward-propagation. Then
+ this check can additional check for validity of N on reversal. */
+ if (is_integral_cast (a1, &def, &i1)
+ && demote_cast_p (l_type, r_type, TREE_TYPE (i1)))
+ {
+ a1 = gen_cast (l_type, a1);
+ a2 = gimple_assign_rhs2 (r_stmt);
+ break;
+ }
+ }
+
+ return false;
+
+ case LSHIFT_EXPR:
+ /* For shift-left operation '(T1) (X << N)', we can sink T1 into
+ shift-left statement, if X and T1 are of compatible type, or if N
+ doesn't exceed value-range of type T1 and type-precision of T1 is
+ smaller or equal to type-precision of X. */
+ /* If outer type's precision is wider then inner, it is a truncation
+ and can't be handled. */
+ if (TYPE_PRECISION (l_type) > TYPE_PRECISION (r_type))
+ return false;
+
+ /* Trivial case. */
+ if (useless_type_conversion_p (l_type, r_type))
+ {
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+ break;
+ }
+
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+
+ /* If A2 isn't an integral constant, or A1 isn't a cast-assignment,
+ or precision of LTYPE is greater then precision of R_TYPE, then
+ we can't do anything. */
+ if (TREE_CODE (a2) != INTEGER_CST
+ || !is_integral_cast (a1, &def, &i1))
+ return false;
+
+ /* Check if right-hand constant operand A2 is overflowing
+ precision of L_TYPE on shift. */
+ if (integer_zerop (fold_binary (LT_EXPR, boolean_type_node, a2,
+ build_int_cst (TREE_TYPE (a2),
+ TYPE_PRECISION (l_type)))))
+ return false;
+
+ /* We only sink into, if pattern can be simplified further.
+ TODO: Add reverse pattern to forward-propagation pass. Then
+ this check can be removed. */
+ if (!demote_cast_p (l_type, r_type, TREE_TYPE (i1)))
+ return false;
+
+ /* Sink cast into shift-statement. */
+ a1 = gen_cast (l_type, a1);
+
+ break;
+
+ case MIN_EXPR: case MAX_EXPR:
+
+ /* Truncation can't be handled. */
+ if (TYPE_PRECISION (l_type) < TYPE_PRECISION (r_type))
+ return false;
+
+ if (TYPE_UNSIGNED (l_type) != TYPE_UNSIGNED (r_type))
+ {
+ /* See that we don't introduce here an implicit sign-change. */
+ if (!TYPE_UNSIGNED (r_type)
+ || TYPE_PRECISION (l_type) == TYPE_PRECISION (r_type))
+ return false;
+ }
+
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+
+ if (useless_type_conversion_p (l_type, r_type))
+ break;
+
+ a1 = gen_cast (l_type, a1);
+ a2 = gen_cast (l_type, a2);
+
+ break;
+
+ case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR:
+ a1 = gimple_assign_rhs1 (r_stmt);
+ a2 = gimple_assign_rhs2 (r_stmt);
+
+ if (useless_type_conversion_p (l_type, r_type))
+ break;
+ a1 = gen_cast (l_type, a1);
+ a2 = gen_cast (l_type, a2);
+ break;
+ default:
+ return false;
+ }
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Sink cast ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, " of stmt ");
+ print_gimple_stmt (dump_file, r_stmt, 0, 0);
+ }
+
+ if (gimple_location (r_stmt) != UNKNOWN_LOCATION
+ && gimple_location (stmt) == UNKNOWN_LOCATION)
+ gimple_set_location (stmt, gimple_location (r_stmt));
+
+ gsi = gsi_for_stmt (stmt);
+ gimple_assign_set_rhs_with_ops (&gsi, code, a1, a2);
+ stmt = gsi_stmt (gsi);
+ update_stmt (stmt);
+
+ remove_stmt_chain (r);
+ *pstmt = stmt;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, " into ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ return true;
+}
+
+/* Loop over each statement for each basic-block. */
+
+static void
+execute_type_demote_int (int flags, basic_block bb)
+{
+ gimple_stmt_iterator gsi;
+ basic_block son;
+
+ for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
+ {
+ gimple stmt, def2;
+ tree lhs, inner;
+
+ stmt = gsi_stmt (gsi);
+ gsi_prev (&gsi);
+
+ if (!is_gimple_assign (stmt)
+ || (lhs = gimple_assign_lhs (stmt)) == NULL_TREE
+ || TREE_CODE (lhs) != SSA_NAME
+ || !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ || !gimple_assign_cast_p (stmt))
+ continue;
+
+ inner = gimple_assign_rhs1 (stmt);
+
+ if (TREE_CODE (inner) != SSA_NAME
+ || !INTEGRAL_TYPE_P (TREE_TYPE (inner))
+ || !(def2 = SSA_NAME_DEF_STMT (inner))
+ || !is_gimple_assign (def2)
+ || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (inner)
+ || !has_single_use (inner))
+ continue;
+
+ if (demote_cast (stmt, lhs, inner, def2))
+ gsi = gsi_for_stmt (stmt);
+ else if (demote_into (flags, stmt, lhs, inner, def2, &stmt))
+ {
+ gsi = gsi_for_stmt (stmt);
+ gsi_prev (&gsi);
+ }
+ }
+
+ for (son = first_dom_son (CDI_POST_DOMINATORS, bb);
+ son;
+ son = next_dom_son (CDI_POST_DOMINATORS, son))
+ execute_type_demote_int (flags, son);
+
+}
+
+/* Entry for type demotion. By FLAG you can control mode of operation of this
pass. */
+
+static unsigned int
+execute_type_demote (int flag)
+{
+ /* We calculate dominance info as CDI_DOMINATORS to make
+ sure we can insert new generated statenents at proper
+ basic-block. */
+ calculate_dominance_info (CDI_DOMINATORS);
+ calculate_dominance_info (CDI_POST_DOMINATORS);
+
+ execute_type_demote_int (flag, EXIT_BLOCK_PTR);
+
+ free_dominance_info (CDI_POST_DOMINATORS);
+
+ return 0;
+}
+
+namespace {
+
+const pass_data pass_data_demote1 =
+{
+ GIMPLE_PASS,
+ "typedemote1", /* name */
+ OPTGROUP_NONE,
+ false, /* has gate */
+ true, /* has execute */
+ TV_NONE, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ (TODO_verify_ssa | TODO_update_ssa), /* todo_flags_finish */
+};
+
+const pass_data pass_data_demote2 =
+{
+ GIMPLE_PASS,
+ "typedemote2", /* name */
+ OPTGROUP_NONE,
+ false, /* has gate */
+ true, /* has execute */
+ TV_NONE, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ (TODO_verify_ssa | TODO_update_ssa), /* todo_flags_finish */
+};
+
+class pass_demote1 : public gimple_opt_pass
+{
+public:
+ pass_demote1 (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_demote1, ctxt)
+ {}
+ /* opt_pass methods: */
+ opt_pass * clone() { return new pass_demote1 (m_ctxt); }
+ unsigned int execute () { return execute_type_demote
(TDK_NO_EXPAND_VIA_UNSIGNED); }
+}; // class pass_demote1
+
+class pass_demote2 : public gimple_opt_pass
+{
+public:
+ pass_demote2 (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_demote2, ctxt)
+ {}
+ /* opt_pass methods: */
+ opt_pass * clone() { return new pass_demote2 (m_ctxt); }
+ unsigned int execute () { return execute_type_demote (0); }
+}; // class pass_demote1
+
+}
+
+gimple_opt_pass *
+make_pass_demote1 (gcc::context *ctxt)
+{
+ return new pass_demote1 (ctxt);
+}
+
+gimple_opt_pass *
+make_pass_demote2 (gcc::context *ctxt)
+{
+ return new pass_demote2 (ctxt);
+}
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
@@ -22,7 +22,7 @@ void tst(void)
blau ((unsigned char) i);
}
-/* { dg-final { scan-tree-dump-times "& 255" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "& 255" 2 "optimized" } } */
/* { dg-final { scan-tree-dump-times "= \\(signed char\\)" 1 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
@@ -14,5 +14,5 @@ foo (long a)
h = c;
}
-/* { dg-final { scan-tree-dump "Replaced \\\(short int\\\) c_.*with b_" "fre1"
} } */
+/* { dg-final { scan-tree-dump "Replaced \\\(short int\\\) c_.*with g\\\."
"fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
@@ -18,5 +18,5 @@ foo (int a, int b)
return aa + bb;
}
-/* { dg-final { scan-tree-dump "Replaced \\\(int\\\) aa_.*with a_" "fre1" } }
*/
+/* { dg-final { scan-tree-dump-times "Replaced \\\(int\\\) aa_.*with a_" 0
"fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
@@ -11,5 +11,5 @@ char bar(char f)
return wrap(f);
}
-/* { dg-final { scan-tree-dump "Replaced \\\(char\\\) .*with " "fre1" } } */
+/* { dg-final { scan-tree-dump-times "Replaced \\\(char\\\) .*with " 0 "fre1"
} } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
@@ -10,5 +10,5 @@ bar (unsigned int t)
return a == t;
}
-/* { dg-final { scan-tree-dump "Replaced \\\(unsigned int\\\) a_.*with t_"
"fre1" } } */
+/* { dg-final { scan-tree-dump-times "Replaced \\\(unsigned int\\\) a_.*with
t_" 0 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-1-big-array.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-1-big-array.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-1-big-array.c
@@ -58,9 +58,8 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 4 "vect" { target { ! vect_widen_shift } } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 4 "vect" { target vect_widen_shift } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-1.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-1.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-1.c
@@ -58,10 +58,8 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 4 "vect" { target { { ! vect_sizes_32B_16B } && { ! vect_widen_shift
} } } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 8 "vect" { target vect_sizes_32B_16B } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 3 "vect" { target vect_widen_shift } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-3-big-array.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-3-big-array.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-3-big-array.c
@@ -58,7 +58,7 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-3.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-3.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-3.c
@@ -58,7 +58,7 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump "vect_recog_over_widening_pattern: detected"
"vect" } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-4-big-array.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-4-big-array.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-4-big-array.c
@@ -62,9 +62,8 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 4 "vect" { target { ! vect_widen_shift } } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 4 "vect" { target vect_widen_shift } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-4.c
===================================================================
--- gcc-trunk.orig/gcc/testsuite/gcc.dg/vect/vect-over-widen-4.c
+++ gcc-trunk/gcc/testsuite/gcc.dg/vect/vect-over-widen-4.c
@@ -62,10 +62,8 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 2 "vect" { target vect_widen_shift } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 4 "vect" { target { { ! vect_sizes_32B_16B } && { ! vect_widen_shift
} } } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 8 "vect" { target vect_sizes_32B_16B } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern:
detected" 4 "vect" { target vect_widen_shift } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_over_widening_pattern:
detected" 0 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-1.c
===================================================================
--- /dev/null
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+short foo (unsigned char a, unsigned char b)
+{
+ int c = (int) a + (int) b;
+ return (short) c;
+}
+
+/* { dg-final { scan-tree-dump-times "= \\\(int\\\)" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-2.c
===================================================================
--- /dev/null
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+short foo (unsigned char a, unsigned short b)
+{
+ int c = (int) a + (int) b;
+ return (short) c;
+}
+
+/* { dg-final { scan-tree-dump-times "= \\\(int\\\)" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-3.c
===================================================================
--- /dev/null
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-add-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+signed char a[1024], b[1024];
+
+void
+foo (void)
+{
+ int i, s, t;
+
+ for (i = 0; i < 1024; i++)
+ {
+ s = a[i];
+ t = b[i];
+ s += t + 0x12345600;
+ a[i] = s;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "305419776" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-shift-1.c
===================================================================
--- /dev/null
+++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/ts-shift-1.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned char f1 (char x)
+{
+ unsigned char x1 = (unsigned char) x;
+ return (x1 << 5);
+}
+
+unsigned short f2 (unsigned int x)
+{
+ unsigned short x1 = (unsigned short) x;
+ return (x1 << 15);
+}
+
+unsigned int f3 (unsigned short x)
+{
+ unsigned long long x1 = (unsigned long long) x;
+ return (unsigned int) (x1 >> 15);
+}
+
+unsigned long long f4 (unsigned short x)
+{
+ unsigned int x1 = (unsigned int) x;
+ return (unsigned long long) (x1 >> 7);
+}
+
+/* { dg-final { scan-tree-dump-times "= \\\(long long unsigned int\\\)" 1
"optimized" } } */
+/* { dg-final { scan-tree-dump-times "= \\\(short unsigned int\\\)" 1
"optimized" } } */
+/* { dg-final { scan-tree-dump-times "= \\\(unsigned int\\\)" 1 "optimized" }
} */
+/* { dg-final { scan-tree-dump-times "= \\\(unsigned char\\\)" 1 "optimized" }
} */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+